home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / cklnet.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  59KB  |  2,209 lines

  1. #include "ckcsym.h"
  2. char *cknetv = "Stratus VOS Network Support, 7.0.010,  18 Oct 1999";
  3.  
  4. /*  C K L N E T  --  Network support  */
  5. /*
  6.   Authors:
  7.  
  8.   Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  9.     Columbia University Center for Computing Activities.
  10.   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  11.     (ken@cs.rochester.edu) (no longer at that address).
  12.   Missing pieces for Excelan sockets library from William Bader, Moravian
  13.     College <bader@moravian.edu>.
  14.   TELNET protocol by Frank da Cruz.
  15.   TGV MultiNet code by Frank da Cruz.
  16.   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  17.   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  18.   SunLink X.25 support by Marcello Frutig, Catholic University,
  19.     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
  20.     Stefaan Eeckels, Eurokom, Luxembourg.
  21.  
  22.   Most non-BSD sockets code removed, converted for Stratus VOS, renamed to
  23.   cklnet.c by David R. Lane, SoftCom Systems, Inc.
  24.  
  25.   Other contributions as indicated below.
  26.  
  27.   Copyright (C) 1985, 2000,
  28.     Trustees of Columbia University in the City of New York.
  29.     All rights reserved.  See the C-Kermit COPYING.TXT file or the 
  30.     copyright text in the ckcmai.c module for disclaimer and permissions.
  31. */
  32.  
  33. #include "ckcdeb.h"
  34. #include "ckcker.h"
  35. #include "ckcnet.h"
  36.  
  37. #ifdef NETCONN
  38. /* Don't need these if there is no network support. */
  39.  
  40. #include <errno.h>
  41. #include <setjmp.h>
  42. #include <signal.h>
  43. #include <error_codes.h>
  44.  
  45. /* only need these includes if using OS TCP/IP */
  46. #ifdef TCPSOCKET
  47. #include <tcp_socket.h>
  48. #include <ioctl.h>
  49.  
  50. #ifdef CK_SOCKS                /* SOCKS Internet relay package */
  51. #define accept  Raccept
  52. #define bind    Rbind
  53. #define connect Rconnect
  54. #define getsockname Rgetsockname
  55. #define listen Rlisten
  56. #endif /* CK_SOCKS */
  57.  
  58. #endif /* TCPSOCKET */
  59.  
  60. /* only need these for X.25 support */
  61. #ifdef STRATUSX25
  62. _PROTOTYP( extern VOID s$read_event, (long *event_id, long *event_count,
  63.     short *event_status, short *status) );
  64.  
  65. _PROTOTYP( extern VOID s$vc_call_full, (CV(32) *gateway, CV(15) *address, 
  66.     CV(63) *facilities, CV(128) *call_data, void *opts, long *timeout,
  67.     short *vcid, long *event_id, short *status) );
  68.  
  69. _PROTOTYP( extern VOID s$vc_call_full_sts, (CV(66) *destination, 
  70.     short *extension, CV(63) *facilities, CV(128) *call_data, void *opts,
  71.     long *timeout, short *vcid, long *event_id, short *status) );
  72.  
  73. _PROTOTYP( extern VOID s$vc_clear, (short *vcid, short *diag, short *status) );
  74.  
  75. _PROTOTYP( extern VOID s$vc_recv_packet, (short *vcid, short *buff_len,
  76.     void *buff, short *packet_size, short *level, short *more,
  77.     short *status) );
  78.  
  79. _PROTOTYP( extern VOID s$vc_recv_interrupt, (short *vcid, char *data,
  80.     short *status) );
  81.  
  82. _PROTOTYP( extern VOID s$vc_reset, (short *vcid, short *diag, short *status) );
  83.  
  84. _PROTOTYP( extern VOID s$vc_send_interrupt, (short *vcid, char *data,
  85.     short *status) );
  86.  
  87. _PROTOTYP( extern VOID s$vc_send_packet, (short *vcid, short *buff_len,
  88.     void *buff, short *level, short *more, short *status) );
  89.  
  90. _PROTOTYP( extern VOID s$vc_set_no_wait_mode, (void) );
  91.  
  92. _PROTOTYP( extern VOID s$vc_set_wait_mode, (void) );
  93.  
  94. _PROTOTYP( extern VOID s$vc_status, (short *vcid, short *diag_code,
  95.     short *status) );
  96.  
  97. extern int linkid, lcn, x25ver;
  98. extern int revcall, closgr, cudata;
  99. extern CHAR udata[MAXCUDATA];
  100. extern CHAR padparms[MAXPADPARMS+1];
  101.  
  102. static long vcid_event;    /* have to save this from open */
  103. static short x25qbit;    /* qbit out flag */
  104. #endif /* STRATUSX25 */
  105.  
  106. static int netnowait;
  107.  
  108. extern SIGTYP (*saval)();        /* For saving alarm handler */
  109.  
  110. _PROTOTYP( VOID bgchk, (void) );
  111. int tcp_rdns = SET_OFF;            /* Not working yet for VOS  */
  112.  
  113. /* These only go with TCP/IP */
  114. #ifdef TCPSOCKET
  115. #ifdef RLOGCODE
  116. #ifdef TCPIPLIB
  117. _PROTOTYP( static VOID rlog_oob, (CHAR *, int) );
  118. #else /* TCPIPLIB */
  119. _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
  120. #endif /* TCPIPLIB */
  121. _PROTOTYP( static int rlog_ini, (VOID) );
  122. int rlog_mode = RL_COOKED;
  123. int rlog_stopped = 0;
  124. #endif /* RLOGCODE */
  125. #endif /* TCPSOCKET */
  126.  
  127. _PROTOTYP( long congspd, (void) ); /* returns speed of console device */
  128.  
  129. extern int                /* External variables */
  130.   duplex, debses, seslog, sessft, wasclosed,
  131.   ttyfd, quiet, msgflg, what, nettype, ttmdm;
  132.  
  133. #define NAMECPYL 100            /* Local copy of hostname */
  134. char namecopy[NAMECPYL];                /* Referenced by ckctel.c */
  135.  
  136. char ipaddr[20] = { '\0' };        /* Global copy of IP address */
  137. char myipaddr[20] = { '\0' };        /* Global copy of my IP address */
  138.  
  139. #endif /* NETCONN */
  140.  
  141. int ttnet = NET_NONE;            /* Network type */
  142. int ttnproto = NP_NONE;            /* Network virtual terminal protocol */
  143.  
  144. /* 0 = don't lowercase username for Rlogin/Telnet protocol */
  145. /* nonzero = do lowercase it.  Add a SET command if necessary... */
  146. int ck_lcname = 0;
  147.  
  148. int tcp_incoming = 0;                   /* Incoming connection? */
  149. extern int sstelnet;                    /* Server side telnet? */
  150.  
  151. #ifndef NOTCPOPTS
  152.  
  153. /* Skip all this if NOTCPOPTS specified. */
  154.  
  155. #ifdef SOL_SOCKET
  156. #ifdef TCP_NODELAY
  157. int tcp_nodelay = 0;            /* Nagle algorithm TCP_NODELAY */
  158. #endif /* TCP_NODELAY */
  159.  
  160. #ifdef SO_DONTROUTE
  161. int tcp_dontroute = 0;
  162. #endif /* SO_DONTROUTE */
  163.  
  164. #ifdef SO_LINGER
  165. int tcp_linger  = 0;            /* SO_LINGER */
  166. int tcp_linger_tmo = 0;            /* SO_LINGER timeout */
  167. #endif /* SO_LINGER */
  168.  
  169. #ifdef SO_SNDBUF 
  170. int tcp_sendbuf = -1;
  171. #endif /* SO_SNDBUF */
  172. #ifdef SO_RCVBUF
  173. int tcp_recvbuf = -1;
  174. #endif /* SO_RCVBUF */
  175. #ifdef SO_KEEPALIVE 
  176. int tcp_keepalive = 1;
  177. #endif /* SO_KEEPALIVE */
  178. #endif /* SOL_SOCKET */
  179.  
  180. #endif /* NOTCPOPTS */
  181.  
  182.  
  183. #ifndef NETCONN
  184. /*
  185.   Network support not defined.
  186.   Dummy functions here in case #ifdef's forgotten elsewhere.
  187. */
  188. int                    /* Open network connection */
  189. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  190.     return(-1);
  191. }
  192. int                    /* Close network connection */
  193. netclos() {
  194.     return(-1);
  195. }
  196. int                    /* Check network input buffer */
  197. nettchk() {
  198.     return(-1);
  199. }
  200. int                    /* Flush network input buffer */
  201. netflui() {
  202.     return(-1);
  203. }
  204. int                    /* Send network BREAK */
  205. netbreak() {
  206.     return(-1);
  207. }
  208. int                    /* Input character from network */
  209. netinc(timo) int timo; {
  210.     return(-1);
  211. }
  212. int                    /* Output character to network */
  213. #ifdef CK_ANSIC
  214. nettoc(char c)
  215. #else
  216. nettoc(c) char c;
  217. #endif /* CK_ANSIC */
  218. /* nettoc */ {
  219.     return(-1);
  220. }
  221. int
  222. nettol(s,n) char *s; int n; {
  223.     return(-1);
  224. }
  225.  
  226. #else /* NETCONN is defined (rest of this module...) */
  227.  
  228. #ifdef TCPSOCKET
  229. int tcpsrfd = -1;
  230. #ifndef NOLISTEN            /* For incoming connections */
  231.  
  232. #ifndef INADDR_ANY
  233. #define INADDR_ANY 0           
  234. #endif /* INADDR_ANY */
  235.  
  236. _PROTOTYP( int ttbufr, ( VOID ) );
  237. _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
  238.  
  239. static unsigned short tcpsrv_port = 0;
  240.  
  241. #endif /* NOLISTEN */
  242.  
  243. static char svcbuf[80];            /* TCP service string */
  244. static int svcnum = 0;            /* TCP port number */
  245.  
  246. #endif /* TCPSOCKET */
  247.  
  248. /* For buffered network reads... */
  249. #define TTXBUFL 1024            /* Maybe 8K?... */
  250.  
  251. extern CHAR     ttxbuf[TTXBUFL+1];
  252. extern int     ttxbp, ttxbn = 0;
  253. /*
  254.   Read bytes from network into internal buffer ttxbuf[], the same buffer
  255.   that is used by ttbufr routine in ASYNC terminal io.
  256.   To be called when input buffer is empty, i.e. when ttxbn == 0.
  257.  
  258.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  259.   internal buffer first, and call this routine for a refill if necessary.
  260.  
  261.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  262.   returns number of bytes read, and sets global ttxbn to that number and
  263.   ttxbp (the buffer pointer) to zero.
  264. */
  265. int
  266. netbufr(int timo) {                /* TT Buffer Read */
  267.     int count;
  268.     short status;
  269.  
  270.     if (ttnet != NET_TCPB &&        /* First make sure current net is */
  271.     ttnet != NET_VX25) {        /* supported (VOS X.25 & OS TCP/IP) */
  272.     return(-1);            /* if not, do nothing. */
  273.     }
  274.  
  275.     if (ttxbn > 0)            /* Out internal buffer is not empty, */
  276.     return(ttxbn);            /* so keep using it. */
  277.  
  278.     count = nettchk();            /* Check network input buffer, */
  279.     if (ttxbn > 0) return(ttxbn);    /* which can put a char there! */
  280.     if (count < 0)            /* Read error */
  281.       return(-1);
  282.     else if (count > TTXBUFL)        /* Too many to read */
  283.       count = TTXBUFL;
  284.     else if (count == 0)        /* None, so read */
  285.       count = 1;
  286.  
  287.     debug(F101,"netbufr count 1","",count);
  288.  
  289. #ifdef TCPSOCKET
  290.     if (ttnet == NET_TCPB) {
  291.     /* This is for nonblocking reads */
  292.     if ((count = net_read(ttyfd,ttxbuf,count,0)) < 1) {
  293.         if (count == -1 && errno == e$caller_must_wait) {
  294.         debug(F100,"netbufr finds nothing","",0);
  295.         return(0);
  296.         } else if (count == 0) {
  297.         debug(F100,"netbufr socket eof","",0);        
  298.         return(-2);  /* this is really a disconnect */
  299.         } else {
  300.         debug(F101,"netbufr net_read error","",errno);
  301.         return(-2); /* say it's disconnected */
  302.         }
  303.     }
  304.     }
  305. #endif /* TCPSOCKET */
  306.  
  307. #ifdef STRATUSX25
  308.     if (ttnet == NET_VX25) {
  309.     count = x25xin(sizeof(ttxbuf), ttxbuf);
  310.     if (count <= 0)
  311.         return count;
  312.     }    
  313. #endif /* STRATUSX25 */
  314.  
  315.     ttxbp = 0;            /* Reset buffer pointer. */
  316.     ttxbn = count;
  317.  
  318. #ifdef DEBUG
  319.     debug(F101,"netbufr count 2","",count); /* Got some bytes. */
  320.     if (count > 0) ttxbuf[count] = '\0';
  321.     debug(F111,"netbufr ttxbuf",ttxbuf,ttxbp);
  322. #endif /* DEBUG */
  323.  
  324.     return(ttxbn);            /* Return buffer count. */
  325. }
  326.  
  327. /*
  328.   C-Kermit network open/close functions for OS TCP/IP & X.25/X.29 Networking.
  329. */
  330.  
  331. /*  N E T O P E N  --  Open a network connection.  */
  332.  
  333. /*  Returns 0 on success, -1 on failure.  */
  334.  
  335. #ifdef TCPSOCKET
  336. #define    TELNET_PORT    23       /* Should do lookup, but it won't change */
  337. #define RLOGIN_PORT 513
  338. #define KERMIT_PORT 1649
  339. #endif /* TCPSOCKET */
  340.  
  341. #ifndef NOTCPOPTS
  342. int
  343. ck_linger(onoff, timo) int onoff; int timo; {
  344. /*
  345.   The following, from William Bader, turns off the socket linger parameter,
  346.   which makes a close() block until all data is sent.  "I don't think that
  347.   disabling linger can ever cause kermit to lose data, but you telnet to a
  348.   flaky server (or to our modem server when the modem is in use), disabling
  349.   linger prevents kermit from hanging on the close if you try to exit."
  350.  
  351.   Modified by Jeff Altman to be generally useful.
  352. */
  353. #ifdef SOL_SOCKET
  354. #ifdef SO_LINGER
  355.     debug(F100,"TCP ck_linger dummy version", "", 0);
  356. #else
  357.     debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
  358. #endif /* SO_LINGER */
  359. #else
  360.     debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
  361. #endif /* SOL_SOCKET */
  362.     return(0);
  363. }
  364.  
  365. int 
  366. sendbuf(size) int size; {
  367. /*
  368.   The following, from William Bader, allows changing of socket buffer sizes,
  369.   in case that might affect performance.
  370.  
  371.   Modified by Jeff Altman to be generally useful.
  372. */
  373. #ifdef SOL_SOCKET
  374. #ifdef SO_SNDBUF
  375. #else
  376.     debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
  377. #endif /* SO_SNDBUF */
  378. #else
  379.     debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
  380. #endif /* SOL_SOCKET */
  381.     return(0);
  382. }
  383.  
  384. int 
  385. recvbuf(size) int size; {
  386. /*
  387.   The following, from William Bader, allows changing of socket buffer sizes,
  388.   in case that might affect performance.
  389.  
  390.   Modified by Jeff Altman to be generally useful.
  391. */
  392. #ifdef SOL_SOCKET
  393. #ifdef SO_RCVBUF
  394.     debug(F100,"TCP recvbuf dummy version","",0);
  395. #else
  396.     debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
  397. #endif /* SO_RCVBUF */
  398. #else
  399.     debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
  400. #endif /* SOL_SOCKET */
  401.     return 0;
  402. }
  403.  
  404. int
  405. keepalive(onoff) int onoff; {
  406. #ifdef SOL_SOCKET
  407. #ifdef SO_KEEPALIVE
  408.     debug(F100,"TCP keepalive dummy version","",0);
  409. #else
  410.     debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
  411. #endif /* SO_KEEPALIVE */
  412. #else
  413.     debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
  414. #endif /* SOL_SOCKET */
  415.     return(0);
  416. }
  417.  
  418.  
  419. int
  420. dontroute(onoff) int onoff; {
  421. #ifdef SOL_SOCKET
  422. #ifdef SO_DONTROUTE
  423.     debug(F100,"TCP dontroute dummy version","",0);
  424. #else
  425.     debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
  426. #endif /* SO_DONTROUTE */
  427. #else
  428.     debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
  429. #endif /* SOL_SOCKET */
  430.     return(0);
  431. }
  432.  
  433. int
  434. no_delay(onoff)     int onoff; {
  435. #ifdef SOL_SOCKET
  436. #ifdef TCP_NODELAY
  437.     debug(F100,"TCP no_delay dummy version","",0);
  438. #else
  439.     debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
  440. #endif /* TCP_NODELAY */
  441. #else
  442.     debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
  443. #endif /* SOL_SOCKET */
  444.     return 0;
  445. }
  446. #endif /* NOTCPOPTS */
  447.  
  448. char *
  449. ckgetpeer() {
  450. #ifdef TCPSOCKET
  451.     static struct hostent *host;
  452.     static struct sockaddr_in saddr;
  453. #ifdef PTX
  454.     static size_t saddrlen;
  455. #else
  456. #ifdef AIX42
  457.     /* It's size_t in 4.2 but int in 4.1 and earlier. */
  458.     /* Note: the 4.2 man page lies; believe socket.h. */
  459.     static size_t saddrlen;
  460. #else
  461. #ifdef UNIXWARE
  462.     static size_t saddrlen;
  463. #else  /* UNIXWARE */
  464. #ifdef VMS
  465.     static unsigned int saddrlen;
  466. #else
  467.     static int saddrlen;
  468. #endif /* VMS */
  469. #endif /* UNIXWARE */
  470. #endif /* AIX42 */
  471. #endif /* PTX */
  472.     saddrlen = sizeof(saddr);
  473.     if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0)
  474.       return(NULL);
  475.     host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
  476.     return((char *)host->h_name);
  477. #else
  478.     return(NULL);
  479. #endif /* TCPSOCKET */
  480. }
  481.  
  482. /*  N E T O P E N  --  Open a network connection  */
  483. /*
  484.   Calling conventions same as ttopen(), except third argument is network
  485.   type rather than modem type.  Designed to be called from within ttopen.
  486. */
  487. int
  488. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  489.     char *p = NULL;
  490. #ifdef SO_OOBINLINE
  491.     int on = 1;
  492. #endif /* SO_OOBINLINE */
  493.     int i=0, x=0, dns=0;;
  494. #ifdef TCPSOCKET
  495.     struct servent *service=NULL, servrec;
  496.     struct hostent *host=NULL;
  497.     struct sockaddr_in saddr;
  498.     extern CHAR uidbuf[];
  499. #endif /* TCPSOCKET */
  500.  
  501. #ifdef STRATUSX25
  502.     CV(66) destination;
  503.     CV(15) address;
  504.     CV(63) facilities;
  505.     CV(128) call_data;
  506.     long x25_timeout;
  507.     short vcid;
  508.     short status;
  509.     struct {
  510.     short version;
  511.     short max_delay;
  512.     short send_size;
  513.     short recv_size;
  514.     } x25_options;
  515.     short sts_extension;
  516. #endif /* STRATUSX25 */
  517.  
  518.     debug(F101,"netopen nett","",nett);
  519.     *ipaddr = '\0';            /* Initialize IP address string */
  520.  
  521. #ifdef STRATUSX25
  522.     if (nett == NET_VX25) {        /* If network type is X.25 */
  523.         netclos();            /* Close any previous net connection */
  524.         ttnproto = NP_NONE;        /* No protocol selected yet */
  525.     sts_extension = -1;
  526.  
  527.     strncpy (namecopy, name, NAMECPYL);
  528.     p = strchr (namecopy, ':');
  529.     if (NULL == p) { /* no address given */
  530.         strcpy (&destination, namecopy);
  531.         strcpy (&address, "");
  532.     }
  533.     else { /* address in part of name */
  534.         *p++ = '\0';
  535.         strcpy (&destination, namecopy);
  536.         strcpy (&address, p);
  537.     }
  538.  
  539.     if (namecopy[0] == '%') {    /* STS with %system#module */
  540.          /* remove % from destination if no module name given */
  541.         if (NULL == strchr (namecopy, '#')) /* no module name */
  542.         strcpy (&destination, &namecopy[1]);
  543.  
  544.         sts_extension = (*p) ? atoi (p) : 255;
  545.         strcpy (&call_data, ""); /* STS includes protocol ID */
  546.     }
  547.     else
  548.         memcpy (&call_data, "\x00\x04\x01\x00\x00\x00", 6); /* KLUDGE! */
  549.  
  550.     /* Set call user data if specified */
  551.         if (cudata)
  552.             strcat(&call_data,udata);
  553.  
  554.     strcpy (&facilities, "");
  555.     
  556.         /* Set reverse charge call and closed user group if requested */
  557.     if (revcall) {        /* reverse charge requested */
  558.         strcat (&facilities, "\x01\x01");
  559.     }
  560.  
  561.     /* closed user group not supported */
  562.         if (closgr > -1) {
  563.         debug(F101,"x25 closed user group not supported","",closgr);
  564.         }
  565.  
  566.     x25_options.version = 1;
  567.     x25_options.max_delay = 0;
  568.     x25_options.send_size = 1024;
  569.     x25_options.recv_size = 1024;
  570.  
  571.     x25_timeout = 30 * 1024; /* lost timeout coming to netopen() */
  572.  
  573.         /* Open X.25 virtual circuit */
  574.     if (sts_extension > -1) {
  575.         s$vc_call_full_sts (&destination, &sts_extension, &facilities,
  576.         &call_data, &x25_options, &x25_timeout, &vcid,
  577.         &vcid_event, &status);
  578.         debug(F101,"netopen s$vc_call_full_sts status","",status);
  579.     }
  580.     else {
  581.         s$vc_call_full ((CV(32) *)&destination, &address, &facilities,
  582.         &call_data, &x25_options, &x25_timeout, &vcid,
  583.         &vcid_event, &status);
  584.         debug(F101,"netopen s$vc_call_full status","",status);
  585.     }
  586.  
  587.     if (status) {
  588.             return (-1);
  589.         }
  590.  
  591.     lcn = vcid;
  592.     ttyfd = vcid;
  593.     linkid = sts_extension;
  594.  
  595.         ttnet = nett;                   /* Stratus X.25 network */
  596.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  597.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  598.         return(0);
  599.     }
  600. #endif /* STRATUSX25 */
  601.  
  602. #ifdef TCPSOCKET
  603.     if (nett == NET_TCPB) {
  604.     netclos();            /* Close any previous connection. */
  605.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  606.     ttnproto = NP_NONE;        /* No protocol selected yet. */
  607.     debug(F110,"netopen namecopy",namecopy,0);
  608.  
  609. #ifndef NOLISTEN
  610.         if (name[0] == '*')
  611.             return(tcpsrv_open(name, lcl, nett, 0));
  612. #endif /* NOLISTEN */
  613.  
  614.     p = namecopy;            /* Was a service requested? */
  615.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  616.     if (*p == ':') {            /* Have a colon */
  617.     debug(F110,"netopen name has colon",namecopy,0);
  618.     *p++ = '\0';            /* Get service name or number */
  619. #ifdef CK_URL
  620.     /*
  621.        Here we have to check for various popular syntaxes:
  622.        host:port (our original syntax)
  623.        URL such as telnet:host or telnet://host/
  624.        Or even telnet://user:password@host:port/
  625.        Or a malformed URL such as generated by Netscape 4.0 like:
  626.        telnet:telnet or telnet::host.
  627.     */
  628.     if (*p == ':')            /* a second colon */
  629.       *p++ = '\0';            /* get rid of that one too */
  630.         while (*p == '/') *p++ = '\0';    /* and slashes */
  631.     x = strlen(p);            /* Length of remainder */
  632.     if (p[x-1] == '/')        /* If there is a trailing slash */
  633.       p[x-1] = '\0';        /* remove it. */
  634.     debug(F110,"netopen namecopy after stripping",namecopy,0);
  635.     debug(F110,"netopen p after stripping",p,0);
  636.     service = getservbyname(namecopy,"tcp");
  637.     if (service || !xxstrcmp("rlogin",namecopy,NAMECPYL)) {
  638.         char temphost[80], tempservice[80];
  639.         char * q = p, *r = p, *w = p;
  640.         /* Check for userid and possibly password */
  641.         while (*p != '\0' && *p != '@') p++; /* look for @ */
  642.         if (*p == '@') {
  643.         /* found username and perhaps password */
  644.         debug(F110,"netopen namecopy found @","",0);
  645.         *p = '\0'; p++;
  646.         while (*w != '\0' && *w != ':')
  647.           w++;
  648.         if (*w == ':')
  649.           *w++ = '\0';
  650.         /* r now points to username, save it and discard password */
  651.         debug(F110,"netopen namecopy username",r,0);
  652.         debug(F110,"netopen namecopy password",w,0);
  653.         strncpy(uidbuf,r,64);
  654.         q = p;            /* Host after user and pwd */
  655.         } else {
  656.         p = q;            /* No username or password */
  657.         }
  658.         /* Now we must look for the optional port. */
  659.         debug(F110,"netopen x p",p,0);
  660.         debug(F110,"netopen x q",q,0);
  661.         while (*p != '\0' && *p != ':') /* Look for another colon */
  662.           p++;
  663.         if (*p == ':') {
  664.         debug(F110,"netopen found port",q,0);
  665.         *p++ = '\0';        /* Found a port name or number */
  666.         debug(F110,"netopen port",p,0);
  667.         if (ttnproto == NP_NONE) {
  668.             /* namecopy[] identifies a protocol, so use it */
  669.             if (!xxstrcmp("telnet",namecopy,NAMECPYL)) 
  670.             ttnproto = NP_TELNET;
  671. #ifdef RLOGCODE
  672.             else if (!xxstrcmp("login",namecopy,NAMECPYL) ||
  673.                  !xxstrcmp("rlogin",namecopy,NAMECPYL)) {
  674.             ttnproto = NP_RLOGIN;
  675.             }
  676. #endif /* RLOGCODE */
  677.         }
  678.         strncpy(tempservice,p,79);
  679.         strncpy(temphost,q,79);
  680.         strncpy(namecopy,temphost,NAMECPYL);
  681.         debug(F110,"netopen tempservice",tempservice,0);
  682.         debug(F110,"netopen temphost",temphost,0);
  683.         x = strlen(namecopy);
  684.         p = namecopy + x + 1;
  685.         strncpy(p, tempservice, NAMECPYL - x - 1);
  686.         } else {
  687.         /* We didn't find another port, but if q is a service */
  688.         /* then assume that namecopy is actually a host.      */
  689.         if (getservbyname(q,"tcp")) {
  690.             p = q;
  691.         } else {
  692. #ifdef RLOGCODE
  693.             /* rlogin is not a valid service */
  694.             if (!xxstrcmp("rlogin",namecopy,6)) {
  695.             strncpy(namecopy,"login",NAMECPYL);
  696.             }
  697. #endif /* RLOGCODE */
  698.             /* Reconstruct namecopy */
  699.             strncpy(tempservice,namecopy,79);
  700.             strncpy(temphost,q,79);
  701.             strncpy(namecopy,temphost,NAMECPYL);
  702.             debug(F110,"netopen tempservice",tempservice,0);
  703.             debug(F110,"netopen temphost",temphost,0);
  704.             x = strlen(namecopy);
  705.             p = namecopy + x + 1;
  706.             strncpy(p, tempservice, NAMECPYL - x - 1);
  707.         }
  708.         }
  709.         debug(F110,"netopen URL result",namecopy,0);
  710.     }
  711. #endif /* CK_URL */
  712.     } else {                /* Otherwise use telnet */
  713. #ifdef COMMENT
  714.     p = "telnet";
  715. #else
  716.     p = "23";
  717. #endif /* COMMENT */
  718.     }
  719. /*
  720.   By the time we get here, namecopy[] should hold the null-terminated
  721.   hostname or address, and p should point to the service name or number.
  722. */
  723.     debug(F110,"netopen host",namecopy,0);
  724.     debug(F110,"netopen service requested",p,0);
  725.     if (isdigit(*p)) {            /* Use socket number without lookup */
  726.     service = &servrec;
  727.     service->s_port = htons((unsigned short)atoi(p));
  728.     } else {                /* Otherwise lookup the service name */
  729.     service = getservbyname(p, "tcp");
  730.     }
  731.     if (!service) {
  732.     fprintf(stderr, "Cannot find port for service %s\n", p);
  733. #ifdef TGVORWIN
  734.     debug(F101,"netopen can't get service","",socket_errno);
  735. #else
  736.     debug(F101,"netopen can't get service","",errno);
  737. #endif /* TGVORWIN */
  738.     errno = 0;            /* rather than mislead */
  739.     return(-1);
  740.     }
  741.     strncpy(svcbuf,p,79);
  742.     svcbuf[79] = '\0';
  743.     debug(F110,"netopen service ok",svcbuf,0);
  744.  
  745. #ifdef RLOGCODE
  746.     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
  747.     fprintf(stderr,
  748.         "  Warning: login service on port %d instead of port 513\n", 
  749.          ntohs(service->s_port));
  750.     fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
  751.     debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
  752.     }
  753. #endif /* RLOGCODE */
  754.  
  755.  
  756.     /* Set up socket structure and get host address */
  757.  
  758.     memset((char *)&saddr, 0, sizeof(saddr));
  759.     if ((host = gethostbyname(namecopy)) != NULL) {
  760.             dns = 1;
  761.         saddr.sin_family = host->h_addrtype;
  762.         memcpy((caddr_t)&saddr.sin_addr, host->h_addr, host->h_length);
  763.     } else {
  764. #ifdef INADDRX
  765. /* inet_addr() is of type struct in_addr */
  766.         struct in_addr ina;
  767.         unsigned long uu;
  768.  
  769.         ina = inet_addr(namecopy);
  770.         uu = *(unsigned long *)&ina;
  771.  
  772. #else /* Not INADDRX */
  773. /* inet_addr() is unsigned long */
  774.         unsigned long uu;
  775.         uu = inet_addr(namecopy);
  776. #endif /* INADDRX */
  777.  
  778.         if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
  779.           saddr.sin_family = AF_INET;
  780.         else {
  781.           fprintf(stderr, "Can't get address for %s\n", namecopy);
  782.  
  783.           debug(F101,"netopen can't get address","",errno);
  784.  
  785.           errno = 0;            /* rather than mislead */
  786.           return(-1);
  787.       }
  788.     }
  789.  
  790.     /* Get a file descriptor for the connection. */
  791.  
  792.     saddr.sin_port = service->s_port;
  793.     sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr));
  794.     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
  795.  
  796.     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  797.         perror("TCP socket error");
  798.         debug(F101,"netopen socket error","",errno);
  799.         return (-1);
  800.     }
  801.     errno = 0;
  802.  
  803. #ifdef RLOGCODE                               
  804.        /* Not part of the RLOGIN RFC, but the BSD implementation     */
  805.        /* requires that the client port be a priviliged port (<1024) */
  806.        /* on a Unix system this would require SuperUser permissions  */
  807.        /* thereby saying that the root of the Unix system has given  */
  808.        /* permission for this connection to be created             */
  809.        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
  810.        struct sockaddr_in sin;
  811.        static unsigned short lport = 1024;    /* max reserved port */
  812.        int s_errno;
  813.  
  814.        lport--;            /* Make sure we do not reuse a port */
  815.        if (lport == 512)
  816.          lport = 1023;
  817.  
  818.        sin.sin_family = AF_INET;
  819.        sin.sin_addr.s_addr = INADDR_ANY;
  820.        while (1) {
  821.            sin.sin_port = htons(lport);
  822.            if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  823.          break;
  824.  
  825.          if (errno != EADDRINUSE)
  826.            {
  827.                printf("\nBind failed with errno %d  for port %d.\n",
  828.                   errno, lport);
  829.                debug(F101,"rlogin bind failed","",errno);
  830.                perror("rlogin bind");
  831.                netclos();
  832.                return -1;
  833.            }
  834.            lport--;
  835.            if (lport == 512 /* lowest reserved port to use */ ) {
  836.            printf("\nNo reserved ports available.\n");
  837.            netclos();
  838.            return -1;
  839.            }
  840.        }
  841.        debug(F101,"rlogin lport","",lport);
  842.        ttnproto = NP_RLOGIN;
  843.        }
  844. #endif /* RLOGCODE  */
  845.  
  846.     /* Now connect to the socket on the other end. */
  847.  
  848.     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  849.         i = errno;            /* save error code */
  850. #ifdef RLOGCODE
  851.           if (errno == EADDRINUSE && ttnproto == NP_RLOGIN) {
  852. #ifdef TCPIPLIB
  853.            socket_close(ttyfd); /* Close it. */
  854. #else
  855.            close(ttyfd);
  856. #endif /* TCPIPLIB */
  857.            continue;        /* Try a different lport */
  858.            }
  859. #endif /* RLOGCODE */
  860.         close(ttyfd);
  861.         ttyfd = -1;
  862.         wasclosed = 1;
  863.         errno = i;            /* and report this error */
  864.  
  865.         debug(F101,"netopen connect errno","",errno);
  866.         return(-1);
  867.     }
  868. #ifdef SO_OOBINLINE
  869.     /*
  870.       The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  871.       It means "leave out of band data inline".  The normal value is 0x0100,
  872.       but don't try this on systems where the symbol is undefined.
  873.     */
  874.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  875. #endif /* SO_OOBINLINE */
  876.  
  877.     /* See if the service is TELNET. */
  878.     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
  879.         ttnproto = NP_TELNET;    /* Yes, set global flag. */
  880.     debug(F101,"netopen service","",x);
  881.     ttnet = nett;            /* TCP/IP (sockets) network */
  882.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  883.     return(0);                /* Done. */
  884.     }
  885.  
  886. #ifndef NOTCPOPTS
  887. #ifdef SOL_SOCKET
  888. #ifdef TCP_NODELAY
  889.     no_delay(tcp_nodelay);
  890. #endif /* TCP_NODELAY */
  891. #ifdef SO_KEEPALIVE
  892.     keepalive(tcp_keepalive);
  893. #endif /* SO_KEEPALIVE */
  894. #ifdef SO_LINGER 
  895.     ck_linger(tcp_linger, tcp_linger_tmo);
  896. #endif /* SO_LINGER */
  897. #ifdef SO_SNDBUF
  898.     sendbuf(tcp_sendbuf);
  899. #endif /* SO_SNDBUF */
  900. #ifdef SO_RCVBUF
  901.     recvbuf(tcp_recvbuf);
  902. #endif /* SO_RCVBUF */
  903. #endif /* SOL_SOCKET */
  904. #endif /* NOTCPOPTS */
  905.  
  906.     ttnet = nett;            /* TCP/IP (sockets) network */
  907.  
  908.     x = ntohs((unsigned short)service->s_port);
  909.     svcnum = x;
  910.     /* See if the service is TELNET. */
  911.     if (x == TELNET_PORT) {
  912.     if (ttnproto != NP_TCPRAW)    /* Yes, so if raw port not requested */
  913.       ttnproto = NP_TELNET;        /* select TELNET protocol. */
  914.     }
  915. #ifdef RLOGCODE
  916.     else if (x == RLOGIN_PORT) {
  917.     ttnproto = NP_RLOGIN;
  918.     }
  919. #endif /* RLOGCODE */
  920. #ifdef COMMENT /* not yet */
  921.     else if (x == KERMIT_PORT) {
  922.     ttnproto = NP_KERMIT;
  923.     }
  924. #endif /* COMMENT */
  925.  
  926. #ifndef datageneral
  927. /* Find out our own IP address */
  928.     {
  929.     struct sockaddr_in sa;
  930.  
  931. #ifndef GSOCKNAME_T
  932. #define GSOCKNAME_T int
  933. #ifdef UNIXWARE
  934. #undef GSOCKNAME_T
  935. #define GSOCKNAME_T size_t
  936. #else
  937. #ifdef VMS
  938. #ifdef DEC_TCPIP
  939. #ifdef __DECC_VER
  940. #undef GSOCKNAME_T
  941. #define GSOCKNAME_T size_t
  942. #endif /* __DECC_VER */
  943. #endif /* DEC_TCPIP */
  944. #endif /* VMS */
  945. #endif /* UNIXWARE */
  946. #endif /* GSOCKNAME_T */
  947.  
  948.     GSOCKNAME_T slen;
  949.  
  950.     slen = sizeof(sa);
  951.         /* memset is not portable, but it exists on VOS */
  952.     memset(&sa, 0, slen);
  953.  
  954. #ifndef EXCELAN
  955.     if (!getsockname(ttyfd, (struct sockaddr *)&sa, &slen) ) {
  956.         sprintf(myipaddr,"%s", (char *)inet_ntoa(sa.sin_addr));
  957.         debug(F110,"getsockname",myipaddr,0);
  958.     }
  959. #endif /* EXCELAN */
  960.     }
  961. #endif /* datageneral */
  962.  
  963.     if (tcp_rdns && dns || tcp_rdns == SET_ON) {
  964.         if (!quiet) {
  965.         printf(" Reverse DNS Lookup... ");
  966.         fflush(stdout);
  967.     }
  968.         if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
  969.         debug(F100,"netopen gethostbyname != NULL","",0);
  970.         if (!quiet) {
  971.         printf("(OK)\n");
  972.         fflush(stdout);
  973.         }
  974.         strncpy(name,host->h_name,79);
  975.         strncat(name,":",80-strlen(name));
  976.         strncat(name,p,80-strlen(name));
  977.         if (!quiet) {
  978.         printf(" %s connected on port %s\n",host->h_name,p);
  979.         }
  980.     } else {
  981.         if (!quiet) printf("Failed.\n");
  982.     }
  983.     } else if (!quiet) printf("(OK)\n");
  984.     if (!quiet) fflush(stdout);
  985.  
  986.     /* This should already have been done but just in case */
  987.     sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  988.  
  989. #ifdef CK_AUTHENTICATION
  990.     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
  991.     ck_auth_init( namecopy, uidbuf, ttyfd );
  992. #endif /* CK_AUTHENTICATION */
  993.     tn_ini();                           /* Reset/Start Telnet negotiations */
  994.     if (ttchk() < 0)
  995.     return(-1);
  996. #ifdef RLOGCODE
  997.     if (ttnproto == NP_RLOGIN) {
  998.     if (rlog_ini() < 0) {
  999.         debug(F100,"rlogin initialization failed","",0);
  1000.         netclos();
  1001.         return -1;
  1002.     }
  1003.     }
  1004. #endif /* RLOGCODE */
  1005.  
  1006.     debug(F101,"netopen service","",svcnum);
  1007.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  1008.     return(0);
  1009. #endif /* TCPSOCKET */
  1010.  
  1011. /*
  1012.   Add support for other networks here.
  1013. */
  1014.     return(-1);                /* Unsupported Network type */
  1015. }
  1016.  
  1017. /*  N E T C L O S  --  Close current network connection.  */
  1018.  
  1019. int
  1020. netclos() {
  1021.     int x = 0;
  1022.     short vcid;
  1023.     short status;
  1024.     short diag;
  1025.  
  1026.     if (ttyfd < 0)            /* Was open? */
  1027.       return(0);            /* Wasn't. */
  1028.  
  1029. #ifdef STRATUSX25
  1030.     if (ttnet == NET_VX25) {
  1031.     if (ttyfd > -1) {
  1032.         vcid = ttyfd;
  1033.         diag = 0;
  1034.         s$vc_clear (&vcid, &diag, &status);
  1035.         debug(F101,"s$vc_clear status","",status);
  1036.  
  1037.         ttyfd = -1;
  1038.         wasclosed = 1;
  1039.         x = (status == 0) ? 0 : -1;
  1040.     }
  1041.     }
  1042. #endif /* STRATUSX25 */
  1043. #ifdef TCPSOCKET
  1044.     if (ttnet == NET_TCPB) {
  1045.     if (ttyfd > -1)            /* Was. */
  1046. #ifdef TNCODE
  1047.             tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
  1048.             TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
  1049. #endif /* TNCODE */
  1050.         x = net_close(ttyfd);
  1051.     }
  1052.     tn_init = 0;            /* Remember about telnet protocol... */
  1053.     *ipaddr = '\0';            /* Zero the IP address string */
  1054.     tcp_incoming = 0;                   /* No longer incoming */
  1055.     sstelnet = 0;            /* Client-side Telnet */
  1056.  
  1057. #endif /* TCPSOCKET */
  1058.     ttyfd = -1;                /* Mark it as closed. */
  1059.     wasclosed = 1;
  1060.  
  1061. #ifdef TCPIPLIB
  1062. /*
  1063.   Empty the internal buffers so they won't be used as invalid input on
  1064.   the next connect attempt (rlogin).
  1065. */
  1066.     ttibp = 0;
  1067.     ttibn = 0;
  1068. #endif /* TCPIPLIB */
  1069.     return(x);
  1070. }
  1071.  
  1072. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  1073. /*
  1074.   Returns number of bytes waiting, or -1 if connection has been dropped.
  1075. */
  1076. int                    /* Check how many bytes are ready */
  1077. nettchk() {                /* for reading from network */
  1078.     unsigned int count = 0;
  1079.     int x, y;
  1080.     char c;
  1081.  
  1082.     x = y = 0;
  1083.  
  1084. #ifdef COMMENT
  1085.     debug(F101,"nettchk entry ttxbn","",ttxbn);
  1086.     debug(F101,"nettchk entry ttxbp","",ttxbp);
  1087. #endif
  1088.     errno = 0;
  1089.  
  1090.     /* for X.25, just return count of buffered characters */
  1091.  
  1092. #ifdef TCPSOCKET
  1093.     if (ttnet == NET_TCPB) {
  1094.     if (net_ioctl(ttyfd,FIONREAD,(char *)&count) < 0) {
  1095.         debug(F101,"nettchk net_ioctl error","",errno);
  1096.         if (ttxbn < 1) return(-1);
  1097.         else return(ttxbn);
  1098.     }
  1099.     debug(F101,"nettchk count","",count);
  1100.     }
  1101. #endif /* TCPSOCKET */
  1102.  
  1103.     /* count what's in network and what we have buffered */
  1104.     debug(F101,"nettchk returns","",count+ttxbn);
  1105.     return(count + ttxbn);
  1106. }
  1107.  
  1108. /*  N E T I N C --  Input character from network */
  1109.  
  1110. int            
  1111. netinc(timo) int timo; {
  1112.     debug(F101,"WARNING: netinc called, timo","",timo);
  1113.     return(-1);
  1114. }
  1115.  
  1116. /*  N E T T O L  --  Output a string of bytes to the network  */
  1117. /*
  1118.   Call with s = pointer to string, n = length.
  1119.   Returns number of bytes actually written on success, or
  1120.   -1 on i/o error, -2 if called improperly.
  1121. */
  1122. int
  1123. nettol(s,n) char *s; int n; {
  1124.     int count = 0;
  1125.     short buflen = n;
  1126.  
  1127. #ifdef TCPSOCKET
  1128.     if (ttnet == NET_TCPB) {
  1129.     if ((count = net_write(ttyfd,s,n,0)) < 1) {
  1130.         debug(F101,"nettol net_write error","",errno);
  1131.         return(-1);
  1132.     }
  1133.     debug(F111,"nettol net_write",s,count);
  1134.     return(count);
  1135.     }
  1136. #endif /* TCPSOCKET */
  1137.  
  1138. #ifdef STRATUSX25
  1139.     if (ttnet == NET_VX25) {
  1140.     short mbit = 0;
  1141.     short vcid = ttyfd;
  1142.     short status;
  1143.  
  1144.     if (0 == x25qbit && padparms[PAD_DATA_FORWARD_TIMEOUT])
  1145.         mbit = 2; /* stream data, may combine packets */
  1146.  
  1147.         if (buflen > 1024)            /* only try to send 1K */
  1148.         buflen = 1024;
  1149.  
  1150.     s$vc_send_packet (&vcid, &buflen, s, &x25qbit, &mbit, &status);
  1151.     s[n] = '\0';
  1152.     debug(F111,"nettol s$vc_send_packet status",s,status);
  1153.  
  1154.     if (status) return (-1);
  1155.  
  1156.     count = buflen;
  1157.     return (count);
  1158.     }
  1159. #endif /* STRATUSX25 */
  1160.  
  1161.    return(-2);
  1162. }
  1163.  
  1164. /*  N E T T O C  --   Output character to network */
  1165. /*
  1166.   Call with character to be transmitted.
  1167.   Returns 0 if transmission was successful, or
  1168.   -1 upon i/o error, or -2 if called improperly.
  1169. */
  1170. int            
  1171. #ifdef CK_ANSIC
  1172. nettoc(char c)
  1173. #else
  1174. nettoc(c) char c;
  1175. #endif /* CK_ANSIC */
  1176. /* nettoc */ {
  1177.     unsigned char cc;
  1178.  
  1179.     cc = c;
  1180.  
  1181. #ifdef TCPSOCKET
  1182.     if (ttnet == NET_TCPB) {
  1183.     debug(F101,"nettoc cc","",cc);
  1184.     if (net_write(ttyfd,&cc,1,0) < 1) {
  1185.         debug(F101,"nettoc net_write error","",errno);
  1186.         return(-1);
  1187.     }
  1188.     debug(F101,"nettoc net_write","", cc);
  1189.     return(0);
  1190.     }
  1191. #endif /* TCPSOCKET */
  1192.  
  1193. #ifdef STRATUSX25
  1194.     if (ttnet == NET_VX25) {
  1195.     short mbit = 2;    /* may be joined with other packets before send */
  1196.     short vcid = ttyfd;
  1197.     short buflen = 1;
  1198.     short status;
  1199.  
  1200.     s$vc_send_packet (&vcid, &buflen, &cc, &x25qbit, &mbit, &status);
  1201.     if (status) {
  1202.         debug(F101,"nettoc s$vc_send_packet status",0,status);
  1203.     }
  1204.     return (status ? -2 : 0);
  1205.     }
  1206. #endif /* STRATUSX25 */
  1207.  
  1208.     return(-2);
  1209. }
  1210.  
  1211. /*  N E T F L U I  --  Flush network input buffer  */
  1212.  
  1213. int
  1214. netflui() {
  1215.     int n;
  1216.     CHAR ch;
  1217.  
  1218.     ttxbuf[ttxbp+1] = '\0';
  1219.     debug(F111,"netflui 1",ttxbuf,ttxbn);
  1220.  
  1221. #ifdef TNCODE
  1222.     if (ttnproto == NP_TELNET) {
  1223.         /* Netflui must process Telnet negotiations or get out of sync */
  1224.         if ((n = ttchk()) <= 0) return(0);
  1225.         while (n-- > 0) {
  1226.             ch = ttinc(1);
  1227.             if (ch == IAC) {
  1228.                 extern int duplex;  /* this really shouldn't be here but ... */
  1229.                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,ttinc);
  1230.                 if (tx == 1) duplex = 1;
  1231.                 else if (tx == 2) duplex = 0;
  1232.                 n = ttchk();
  1233.             }
  1234.         }
  1235.         return(0);
  1236.     } else 
  1237. #endif /* TNCODE */
  1238.     ttxbn = ttxbp = 0;            /* Flush internal buffer *FIRST* */
  1239.  
  1240.     if ((n = nettchk()) > 0) {        /* Now see what's waiting on the net */
  1241.     if (n > TTXBUFL) n = TTXBUFL;    /* and sponge it up */
  1242.     debug(F101,"netflui 2","",n);    /* ... */
  1243.  
  1244. #ifdef TCPSOCKET
  1245.     if (ttnet == NET_TCPB)
  1246.         n = net_read(ttyfd,ttxbuf,n,0) ; /* into our buffer */
  1247.         else
  1248.         n = 0;
  1249. #endif /* TCPSOCKET */
  1250.  
  1251. #ifdef STRATUSX25
  1252.     if (ttnet == NET_VX25)
  1253.         n = 0;    /* x25 don't read to flush */
  1254. #endif /* STRATUSX25 */
  1255.  
  1256.     if (n >= 0) ttxbuf[n] = '\0';
  1257.     debug(F111,"netflui 3",ttxbuf,n);
  1258.     ttxbuf[0] = '\0';
  1259.     }
  1260.  
  1261.     return(0);
  1262. }
  1263.  
  1264.  
  1265. /* N E T W A I T -- Set a network connection back and forth
  1266.                     between wait mode and nowait mode, used by
  1267.                     contti during network connections.  Assumes
  1268.                     the caller logs the statuses.
  1269.  
  1270. */
  1271. int
  1272. #ifdef CK_ANSIC
  1273. netwait(int no_wait, int sd, long *evid, long *evcnt)
  1274. #else
  1275. netwait(no_wait, sd, evid, evcnt) int no_wait; int sd; long *evid; long *evcnt;
  1276. #endif
  1277. /* netwait(int no_wait, int sd, long *evid, long *evcnt) */ {
  1278.  
  1279.     short status;
  1280.     int y;
  1281.     int x;
  1282.     short event_stat;
  1283.  
  1284.     status = 0;
  1285.     debug(F101,"netwait no_wait","",no_wait);
  1286.     debug(F101,"        sd","",sd);
  1287.  
  1288.     netnowait = no_wait;
  1289.  
  1290. #ifdef STRATUSX25
  1291.     /* X.25 we don't actually change the mode.  We stay in wait mode for
  1292.     everything except receiving packets.
  1293.     */
  1294.     if (ttnet == NET_VX25) {
  1295.     if (no_wait) { /* pass back the saved event information */
  1296.         *evid = vcid_event;
  1297.         s$read_event (evid, evcnt, &event_stat, &status);
  1298.     }
  1299.     }
  1300. #endif /* STRATUSX25 */
  1301.  
  1302. #ifdef TCPSOCKET
  1303.     if (ttnet == NET_TCPB) {
  1304.     if (no_wait) {
  1305.         if (0 > get_socket_event (sd, evid, evcnt)) {
  1306.         status = errno;
  1307.         return status;
  1308.         }
  1309.         y = 0;                /* Turn on nonblocking reads */
  1310.         x = net_ioctl(ttyfd,FIONBIO,(char*)&y);
  1311.         debug(F101,"netwait FIONBIO","",x);
  1312.         if (x < 0) status = errno;
  1313.     }
  1314.     else {
  1315.         y = 1;                /* Turn on blocking reads */
  1316.         x = net_ioctl(ttyfd,FIONBIO,(char*)&y);
  1317.         debug(F101,"netwait FIONBIO","",x);
  1318.         if (x < 0) status = errno;
  1319.     }
  1320.     }
  1321. #endif /* TCPSOCKET */
  1322.  
  1323.     return (status);
  1324. }
  1325.  
  1326. /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
  1327.  *   If the host is multi-homed it returns only one address.
  1328.  * 
  1329.  * Two techniques are used.  
  1330.  * (1) get the local host name and perform a reverse DNS lookup, then take
  1331.  *     the first entry;
  1332.  * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
  1333.  *    no data is sent), then retrieve the local address from the socket.
  1334.  * Note: the second technique won't work on Microsoft systems.  See 
  1335.  * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
  1336.  */
  1337.  
  1338. int
  1339. getlocalipaddr() {
  1340. #ifdef TCPSOCKET
  1341. #ifndef datageneral
  1342.     struct sockaddr_in l_sa;
  1343.     struct sockaddr_in r_sa;
  1344.     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
  1345.     int sock;
  1346.     int rc;
  1347.     struct in_addr laddr;
  1348.  
  1349.     /* if still not resolved, then try second strategy */
  1350.     /* This second strategy does not work on Windows */
  1351.  
  1352.     memset(&l_sa,0,slen);
  1353.     memset(&r_sa,0,slen);
  1354.  
  1355.     /* get a UDP socket */
  1356.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  1357.     if (sock != -1) {
  1358.     /* connect to arbirary port and address (NOT loopback) */
  1359.     r_sa.sin_family = AF_INET;
  1360.     r_sa.sin_port = htons(IPPORT_ECHO);
  1361.  
  1362.     /* The following is an "illegal conversion" in AOS/VS */
  1363.     /* (and who knows where else) */
  1364.  
  1365. #ifdef INADDRX
  1366.     inaddrx = inet_addr("128.127.50.1");
  1367.     r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
  1368. #else
  1369.     r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
  1370. #endif /* INADDRX */
  1371.     rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
  1372.     if (!rc) {            /* get local address */
  1373.         getsockname(sock,(struct sockaddr *)&l_sa,&slen);
  1374. #ifdef TCPIPLIB
  1375.         socket_close(sock);        /* We're done with the socket */
  1376. #else
  1377.         close(sock);
  1378. #endif /* TCPIPLIB */
  1379.         if (l_sa.sin_addr.s_addr != INADDR_ANY) {
  1380.         sprintf(myipaddr,"%s", (char *)inet_ntoa(l_sa.sin_addr));
  1381.         debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
  1382.         return(0);
  1383.         }
  1384.     }
  1385.     }
  1386.     return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
  1387. #else /* datageneral */
  1388.     return(-1);
  1389. #endif /* datageneral */
  1390. #else
  1391.     return(-1);
  1392. #endif /* TCPSOCKET */
  1393. }
  1394.  
  1395. int
  1396. getlocalipaddrs(buf,bufsz,index)
  1397.     char * buf;
  1398.     int    bufsz;
  1399.     int    index;
  1400. /* getlocalipaddrs */ {
  1401. #ifdef TCPSOCKET
  1402. #ifndef datageneral
  1403.     char localhost[256];
  1404.     struct hostent * host=NULL;
  1405.     struct sockaddr_in l_sa;
  1406.     struct sockaddr_in r_sa;
  1407.     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
  1408.     int sock;
  1409.     int rc;
  1410.     char messageBuf[60];
  1411.     struct in_addr laddr;
  1412.  
  1413.     memset(&l_sa,0,slen);
  1414.     memset(&r_sa,0,slen);
  1415.  
  1416.     /* init local address (to zero) */
  1417.     l_sa.sin_addr.s_addr = INADDR_ANY;
  1418.  
  1419. #ifdef CKGHNLHOST
  1420.     rc = gethostname(localhost, 256);
  1421.     debug(F110,"getlocalipaddrs localhost",localhost,0);
  1422. #else
  1423.     /* This doesn't work on some platforms, e.g. Solaris */
  1424.     rc = 0;
  1425.     localhost[0] = '\0';
  1426. #endif /* CKGHNLHOST */
  1427.     if (!rc) {
  1428.         /* resolve host name for local address */
  1429.         host = gethostbyname(localhost);
  1430.         if (host) {
  1431. #ifdef HADDRLIST
  1432.         if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
  1433.         buf[0] = '\0';
  1434.         return(-1);
  1435.         }
  1436.         l_sa.sin_addr.s_addr =
  1437.           *((unsigned long *) (host->h_addr_list[index]));
  1438.         sprintf(buf,"%s", (char *)inet_ntoa(l_sa.sin_addr));
  1439.         debug(F110,"getlocalipaddrs setting buf to",buf,0);
  1440. #else    /* HADDRLIST */
  1441.         if (index != 0) {
  1442.         buf[0] = '\0';
  1443.         return(-1);
  1444.         }
  1445.         l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
  1446.         sprintf(buf,"%s", (char *)inet_ntoa(l_sa.sin_addr));
  1447.         debug(F110,"getlocalipaddrs setting buf to",buf,0);
  1448. #endif    /* HADDRLIST */
  1449.             return(0);
  1450.         } else debug(F110,
  1451.              "getlocalipaddrs: gethostbyname() failed",
  1452.              localhost,
  1453.              0
  1454.              );
  1455.     }
  1456. #endif /* datageneral */
  1457. #else
  1458.     return(-1);
  1459. #endif /* TCPSOCKET */
  1460. }
  1461.  
  1462.  
  1463. #ifdef TCPSOCKET
  1464. #ifdef RLOGCODE            /* TCP/IP RLOGIN protocol support code */
  1465. static int
  1466. rlog_naws() {
  1467.     struct rlog_naws {
  1468.     char id[4];
  1469.     unsigned short rows, cols, ypix, xpix;
  1470.     } nawsbuf;
  1471.  
  1472.     if (ttnet != NET_TCPB)
  1473.       return 0;
  1474.     if (ttnproto != NP_RLOGIN)
  1475.       return 0;
  1476.     if (!nawsflg)
  1477.       return 0;
  1478.  
  1479.     debug(F100,"rlogin Window Size sent","",0);
  1480.  
  1481.     nawsbuf.id[0] = nawsbuf.id[1] = 0xFF;
  1482.     nawsbuf.id[2] = nawsbuf.id[3] = 's';
  1483.     nawsbuf.rows = htons((unsigned short) tt_rows);
  1484.     nawsbuf.cols = htons((unsigned short) tt_cols);
  1485.     nawsbuf.ypix = htons(0);        /* y pixels */
  1486.  
  1487.     nawsbuf.xpix = htons(0);        /* x pixels */
  1488.     if (ttol((CHAR *) &nawsbuf, 12) < 0)
  1489.       return -1;
  1490.     return 0;
  1491. }
  1492.  
  1493. static int
  1494. rlog_ini() {
  1495. #ifdef RLOGOUTBUF
  1496.     char outbuf[512];
  1497.     int  outbytes=0;
  1498. #endif /* RLOGOUTBUF */
  1499.     int flag = 0;
  1500. #define TERMLEN 16
  1501.     extern char uidbuf[];
  1502.     char localuser[255];
  1503.     int userlen = 0;
  1504.     char terminal[TERMLEN+1];
  1505. #ifdef CONGSPD
  1506. #define CONSPDLEN 16
  1507.     char conspeed[CONSPDLEN+1];
  1508.     long conspd = -1L;
  1509. #endif /* CONGSPD */
  1510.     int i, n;
  1511.  
  1512.     int rc = 0;
  1513.     tn_ini();                   /* This call will reset all of the Telnet */
  1514.                                 /* options and then quit.  We need to do  */
  1515.                                 /* this since we use the Telnet options   */
  1516.                                 /* to hold various state information      */
  1517.     duplex = 0;            /* Rlogin is always remote echo */
  1518.  
  1519. #ifdef CK_TTGWSIZ
  1520. /*
  1521.   But compute the values anyway before the first read since the out-
  1522.   of-band NAWS request would arrive before the first data byte (NULL).
  1523. */
  1524.  
  1525.     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
  1526.     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
  1527.     if (tt_rows < 0 || tt_cols < 0) {    /* Not known yet */
  1528.     ttgwsiz();            /* Try to find out */
  1529.     }
  1530.     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
  1531.     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
  1532. #endif /* CK_TTGWSIZ */
  1533.     ttflui();                           /* Start by flushing the buffers */
  1534.  
  1535.     rlog_mode = RL_COOKED;
  1536. #ifdef RLOGOUTBUF
  1537.     outbuf[outbytes++] = 0;
  1538. #else 
  1539.     ttoc(0);                /* Send an initial NUL as wake-up */
  1540. #endif /* RLOGOUTBUF */
  1541.  
  1542.     /* Followed by client username ... */
  1543.  
  1544.     localuser[0] = '\0';
  1545.     {
  1546.     char *s; char *p;
  1547.     char * user = getenv("USER");
  1548.     debug(F110,"rlogin getenv(USER)",user,0);
  1549.     if (!user)
  1550.       user = "";
  1551.     userlen = strlen(user);
  1552.     s = user;
  1553.     p = (char *)localuser;
  1554.     while (*p++ = *s++) 
  1555.       ;
  1556.     if (ck_lcname) {
  1557.         cklower((char *)localuser);
  1558.         debug(F110,"rlog_ini localuser 2",localuser,0);
  1559.     }
  1560. #ifdef RLOGOUTBUF
  1561.         strcpy(&outbuf[outbytes],localuser);
  1562.         outbytes += userlen+1;
  1563. #else
  1564.     rc = ttol((CHAR *)localuser,userlen+1); /* strlen + 1 */
  1565. #endif /* RLOGOUTBUF */
  1566.     debug(F111,"rlog_ini","ttol local user",rc);
  1567.     }
  1568.  
  1569.     /* Then the server userid... */
  1570.  
  1571.     if (uidbuf[0]) {
  1572. #ifdef RLOGOUTBUF
  1573.         strcpy(&outbuf[outbytes],uidbuf);
  1574.         outbytes += strlen(uidbuf) + 1;
  1575. #else
  1576.         rc = ttol((CHAR *) uidbuf,strlen(uidbuf)+1); /* strlen + 1 */
  1577. #endif /* RLOGOUTBUF */
  1578.     debug(F111,"rlog_ini","ttol server user",rc);
  1579.     } else if (localuser[0]) {
  1580. #ifdef RLOGOUTBUF
  1581.         strcpy(&outbuf[outbytes],localuser);
  1582.         outbytes += strlen(localuser) + 1;
  1583. #else
  1584.     rc = ttol((CHAR *) localuser,userlen+1);
  1585. #endif /* RLOGOUTBUF */
  1586.     debug(F111,"rlog_ini","ttol server user",rc);
  1587.     } else {
  1588. #ifdef RLOGOUTBUF
  1589.         outbuf[outbytes++]=0;
  1590. #else
  1591.     rc = ttoc(0);
  1592. #endif /* RLOGOUTBUF */
  1593.     debug(F111,"rlog_ini","ttoc NUL server user",rc);
  1594.     }
  1595.     /* Finally the terminal type and speed */
  1596.  
  1597.     terminal[0] = '\0';
  1598.     if (tn_term) {            /* SET TELNET TERMINAL-TYPE value */
  1599.     if (*tn_term) {            /* (if any) takes precedence. */
  1600.         strncpy(terminal, tn_term, TERMLEN);
  1601.         terminal[TERMLEN] = '\0';
  1602.         flag = 1;
  1603.     }
  1604.     } else {                /* Otherwise the local terminal type */
  1605.       /* we just look at the TERM environment variable */
  1606.       /* That's one that we understand in our getenv() replacement */
  1607.       char *p = getenv("TERM");
  1608.       if (p)
  1609.       strncpy(terminal,p,TERMLEN);
  1610.       else
  1611.       terminal[0] = '\0';
  1612.     }
  1613.     n = strlen(terminal);
  1614.     if (n > 0) {            /* We have a terminal type */
  1615.     if (!flag) {            /* If not user-specified */
  1616.         for (i = 0; i < n; i++)    /* then lowercase it.     */
  1617.           if (isupper(terminal[i]))
  1618.         terminal[i] = tolower(terminal[i]);
  1619.     }
  1620. #ifdef RLOGOUTBUF
  1621.         strcpy(&outbuf[outbytes],terminal);
  1622.         outbytes += n;
  1623. #else   
  1624.     rc = ttol((CHAR *)terminal,n);
  1625. #endif /* RLOGOUTBUF */
  1626.     debug(F111,"rlog_ini","ttol terminal",rc);
  1627. #ifdef CONGSPD
  1628.     /* conspd() is not yet defined in all ck*tio.c modules */
  1629.     /* And it will be defined at some point for us, but not now */
  1630.     conspd = congspd();
  1631.     if (conspd > 0L) {
  1632.         sprintf(conspeed,"/%ld",conspd);
  1633.         n = strlen(conspeed);
  1634. #ifdef RLOGOUTBUF
  1635.             strcpy(&outbuf[outbytes],conspeed);
  1636.             outbytes += n+1;
  1637. #else
  1638.         rc = ttol((CHAR *)conspeed,n+1);
  1639. #endif /* RLOGOUTBUF */
  1640.     } else 
  1641. #endif /* CONGSPD */
  1642.         {
  1643. #ifdef RLOGOUTBUF
  1644.             strcpy(&outbuf[outbytes],"/19200");
  1645.             outbytes += 7;
  1646. #else
  1647.             rc = ttol((CHAR *)"/19200",7); /* strlen + 1 */
  1648. #endif /* RLOGOUTBUF */
  1649.         }
  1650.     debug(F111,"rlog_ini","ttol speed",rc);
  1651.     } else {
  1652. #ifdef RLOGOUTBUF
  1653.         outbuf[outbytes++]=0;
  1654. #else
  1655.     rc = ttoc(0); 
  1656. #endif /* RLOGOUTBUF */
  1657.     debug(F111,"rlog_ini","ttoc NUL terminal/speed",rc);
  1658.     }
  1659.  
  1660. #ifdef RLOGOUTBUF
  1661.     ttol(outbuf,outbytes);
  1662. #endif /* RLOGOUTBUF */
  1663.  
  1664.     /* Now we are supposed to get back a single zero byte as confirmation */
  1665.     errno = 0;
  1666.     rc = ttinc(60);
  1667.     debug(F101,"rlogin first ttinc","",rc);
  1668.     if (rc > 0) {
  1669.     debug(F101,"rlogin ttinc 1","",rc);
  1670.     printf("Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
  1671.     return(-1);
  1672.     } else if (rc < 0) {
  1673.     debug(F101,"rlogin ttinc errno","",errno);
  1674.     /* printf("Network error: %d\n", errno); */
  1675.     return(-1);
  1676.     }    
  1677.     return(0);
  1678. }
  1679.  
  1680. static VOID
  1681. rlog_oob(oobdata, count) CHAR * oobdata; int count; {
  1682.     int i;
  1683.  
  1684.     for (i = 0; i<count; i++)    {
  1685.     debug(F101,"rlogin out_of_band","",oobdata[i]);
  1686.     if (oobdata[i] == 0x02) { /* Flush Buffered Data not yet displayed */
  1687.         debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
  1688.         ttflui();
  1689.     }
  1690.     if (oobdata[i] & 0x10) {    /* Switch to RAW mode */
  1691.         debug(F101,"rlogin Raw Mode command","",oobdata[i]);
  1692.         rlog_mode = RL_RAW;
  1693.     }
  1694.  
  1695.     if (oobdata[i] & 0x20) {    /* Switch to COOKED mode */
  1696.         debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
  1697.         rlog_mode = RL_COOKED;
  1698.     }
  1699.     if (oobdata[i] & 0x80) {    /* Send Window Size Info */
  1700.         debug(F101,"rlogin Window Size command","",oobdata[i]);
  1701.         /* Remember to send WS Info when Window Size changes */
  1702.         nawsflg = 1;
  1703.         rlog_naws();
  1704.     }
  1705.     }
  1706. }
  1707. #endif /* RLOGCODE */
  1708. #endif /* TCPSOCKET */
  1709.  
  1710. /* Send network BREAK */
  1711. /*
  1712.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  1713. */
  1714. int
  1715. netbreak() {
  1716.     CHAR buf[3];
  1717.  
  1718. #ifdef TCPSOCKET
  1719.     if (ttnet == NET_TCPB) {
  1720.     if (ttnproto == NP_TELNET) {
  1721. #ifdef TNCODE
  1722.         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK;
  1723.         if (ttol(buf,2) < 2) return(-1);
  1724.         debug(F101,"telnet BREAK ok","",BREAK);
  1725.         return(1);
  1726. #else
  1727.         debug(F100,"netbreak no TNCODE","",0);
  1728.         return(0);
  1729. #endif /* TNCODE */
  1730.     }
  1731.     /* Insert other TCP/IP protocols here */
  1732.     }
  1733. #endif /* TCPSOCKET */
  1734.  
  1735. #ifdef STRATUSX25
  1736.     if (ttnet == NET_VX25) {
  1737.     breakact ();
  1738.     }
  1739. #endif /* STRATUSX25 */
  1740.  
  1741.     /* Insert other networks here */
  1742.     return(0);
  1743. }
  1744.  
  1745. #ifdef STRATUSX25
  1746.  
  1747. /* PAD X.3, X.28 and X.29 support */
  1748.  
  1749. static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  1750.  
  1751. /* Initialize PAD */
  1752.  
  1753. extern CHAR padparms[MAXPADPARMS+1];
  1754. static long ccittspeeds[] =
  1755. {
  1756.     110, 134, 300, 1200, 600, 75, 150, 1800, 200, 100,
  1757.     50, 1200, 2400, 4800, 9600, 19200, 48000, 56000, 64000
  1758. };
  1759.  
  1760. VOID
  1761. initpad() {
  1762.   int i;
  1763.   long speed;
  1764.   int match;    /* may have to take closest match */
  1765.   long diff;
  1766.  
  1767.   padparms[PAD_BREAK_CHARACTER]        = 3;  /* Break character */
  1768.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  1769.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  1770.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  1771.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  1772.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  1773.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  1774.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  1775.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  1776.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  1777.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  1778.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  1779.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  1780.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  1781.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  1782.   padparms[PAD_EDITING]                = 1;  /* can edit */
  1783.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  1784.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  1785.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  1786.  
  1787.     speed = congspd();
  1788.     match = 0;
  1789.     for (i = 0; i < (sizeof ccittspeeds) / (sizeof ccittspeeds[0]); i++) {
  1790.     diff = speed - ccittspeeds[i];
  1791.     if (diff == 0) {
  1792.         match = i;
  1793.         break;
  1794.     }
  1795.     if (diff > 0 && diff < (speed - ccittspeeds[match]))
  1796.         match = i;
  1797.     }
  1798.  
  1799.     padparms[PAD_LINE_SPEED] = match;  /* line speed (as good as we can get) */
  1800. }
  1801.  
  1802. /* Set PAD parameters */
  1803.  
  1804. VOID
  1805. setpad(s,n) CHAR *s; int n; {
  1806.     int i;
  1807.     CHAR *ps = s;
  1808.     char buff[30];
  1809.  
  1810.     if (n) {
  1811.     for (i = 0; i < n; i++) {
  1812.         if(deblog) {
  1813.         sprintf(buff,"   set pad parm %d=%d",*ps,*(ps+1));
  1814.         debug(F100,buff,"",0);
  1815.         }
  1816.  
  1817.         /* out of range or read only */
  1818.         if (*ps > MAXPADPARMS || *ps == PAD_LINE_SPEED)
  1819.           x29err[i+2] = *ps;
  1820.         else
  1821.           padparms[*ps] = *(ps+1);
  1822.         ps += 2;
  1823.     }
  1824.     }
  1825.     else {
  1826.     debug(F100,"  setpad calling initpad","",0);
  1827.     initpad();
  1828.     }
  1829. }
  1830.  
  1831. /* Read PAD parameters */
  1832.  
  1833. VOID
  1834. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  1835.     int i;
  1836.     CHAR *ps = s;
  1837.     CHAR *pr = r;
  1838.     char buff[30];
  1839.  
  1840.     *pr++ = X29_PARAMETER_INDICATION;
  1841.     if (n == 0) {            /* All supported parameters */
  1842.     for (i = 1; i <= MAXPADPARMS; i++, ps++) {
  1843.         *pr++ = i;
  1844.         *pr++ = padparms[i];
  1845.         if(deblog) {
  1846.         sprintf(buff,"   read pad parm %d=%d",i,padparms[i]);
  1847.         debug(F100,buff,"",0);
  1848.         }
  1849.     }
  1850.     }
  1851.     else {                /* list of specific parameters */
  1852.     for (i = 0; i < n; i++, ps++) {
  1853.         if(deblog) {
  1854.         sprintf(buff,"   read pad parm %d=%d",
  1855.             *ps, (*ps <= MAXPADPARMS) ? padparms[i] : -1);
  1856.         debug(F100,buff,"",0);
  1857.         }
  1858.          if (*ps > MAXPADPARMS) {
  1859.          x29err[i+2] = *ps++;
  1860.          } else {
  1861.          *pr++ = *ps;
  1862.          *pr++ = padparms[*ps++];
  1863.          }
  1864.     }
  1865.     }
  1866. }
  1867.  
  1868. int
  1869. qbitpkt(s,n) CHAR *s; int n; {
  1870.     CHAR *ps = s;
  1871.     int x29cmd = *ps;
  1872.     CHAR *psa = s+1;
  1873.     CHAR x29resp[(MAXPADPARMS*2)+1];
  1874.  
  1875.     debug (F101,"qbitpkt, len","",n);
  1876.     switch (x29cmd) {
  1877.         case X29_SET_PARMS:
  1878.         debug(F100,"X29 SET PAD","",0);
  1879.             setpad (psa,n/2);
  1880.             if ((int)strlen(x29err) > 2) {
  1881.                 ttol (x29err,(int)strlen(x29err));
  1882.                 x29err[2] = '\0';
  1883.             }
  1884.         break;
  1885.         case X29_READ_PARMS:
  1886.         debug(F100,"X29 READ PAD","",0);
  1887.             readpad (psa,n/2,x29resp);
  1888.             setqbit ();
  1889.             ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1));
  1890.             if ((int)strlen(x29err) > 2) {
  1891.                 ttol (x29err,(int)strlen(x29err));
  1892.                 x29err[2] = '\0';
  1893.             }
  1894.             resetqbit();
  1895.             break;
  1896.         case X29_SET_AND_READ_PARMS:
  1897.         debug(F100,"X29 SET AND READ PAD","",0);
  1898.             setpad (psa,n/2);
  1899.             readpad (psa,n/2,x29resp);
  1900.             setqbit();
  1901.             ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1));
  1902.             if ((int)strlen(x29err) > 2) {
  1903.                 ttol (x29err,(int)strlen(x29err));
  1904.                 x29err [2] = '\0';
  1905.             }
  1906.             resetqbit();
  1907.         break;
  1908.         case X29_INVITATION_TO_CLEAR:
  1909.         debug(F100,"X29 INVITATION TO CLEAR","",0);
  1910.             (VOID) x25clear();
  1911.             return (-2) ; /* hang it up */
  1912.         case X29_INDICATION_OF_BREAK:
  1913.         debug(F100,"X29 INDICATION OF BREAK","",0);
  1914.         break;
  1915.     }
  1916.     return (0);
  1917. }
  1918.  
  1919. /* PAD break action processor */
  1920.  
  1921. VOID
  1922. breakact() {
  1923.     extern char x25obuf[];
  1924.     extern int obufl;
  1925.     extern int active;
  1926.     extern unsigned char tosend;
  1927.     static CHAR indbrk[3] = {
  1928.     X29_INDICATION_OF_BREAK,
  1929.     PAD_SUPPRESSION_OF_DATA,
  1930.     1
  1931.     };
  1932.     CHAR intudat, cause, diag;
  1933.  
  1934.     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
  1935.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  1936.         if (ttol(x25obuf,obufl) < 0) {
  1937.             perror ("\r\nCan't send characters");
  1938.             active = 0;
  1939.         } else {
  1940.             /* bzero (x25obuf,sizeof(x25obuf)); */ /**/
  1941.             obufl = 0;
  1942.             tosend = 0;
  1943.         };
  1944.  
  1945.     switch (padparms[PAD_BREAK_ACTION]) {
  1946.  
  1947.        case 0 : break;            /* do nothing */
  1948.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  1949.             intudat = 1;
  1950.                 x25intr (intudat);
  1951.                 break;
  1952.        case 2 : /* send reset packet with cause and diag = 0 */
  1953.         cause = diag = 0;
  1954.                 x25reset (cause,diag);
  1955.                 break;
  1956.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  1957.         intudat = 0;
  1958.                 x25intr (intudat) ;
  1959.                 setqbit ();
  1960.             /* send indication of break without a parameter field */
  1961.                 ttoc(X29_INDICATION_OF_BREAK);
  1962.                 resetqbit ();
  1963.                 break;
  1964.        case 8 : active = 0;        /* leave data transfer */
  1965.                 conol ("\r\n");
  1966.                 break;
  1967.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  1968.         intudat = 0;
  1969.                 x25intr (intudat);
  1970.                 setpad (indbrk+1,1);    /* set pad to discard input */
  1971.                 setqbit ();
  1972.         /* send indication of break with parameter field */
  1973.                 ttol (indbrk,sizeof(indbrk));
  1974.                 resetqbit ();
  1975.                 break;
  1976.      }
  1977. }
  1978.  
  1979. /* X.25 support functions */
  1980.  
  1981. /*
  1982.   Convert a null-terminated string representing an X.121 address
  1983.   to a packed BCD form.
  1984. */
  1985. #ifdef SUNX25 /* not used for Stratus X.25 */
  1986. int
  1987. pkx121(str,bcd) char *str; CHAR *bcd; {
  1988.     int i, j;
  1989.     u_char c;
  1990.  
  1991.     i = j = 0;
  1992.     while (str[i]) {
  1993.         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
  1994.       return (-1);
  1995.         c = str [i] - '0';
  1996.         if ( i & 1 )
  1997.       bcd [j++] |= c;
  1998.         else
  1999.       bcd [j] = c << 4;
  2000.         i++;
  2001.     }
  2002.     return (i);
  2003. }
  2004. #endif /* SUNX25 */
  2005.  
  2006. /* Reads and prints X.25 diagnostic */
  2007.  
  2008. int
  2009. x25diag () {
  2010.     int i;
  2011. #ifdef SUNX25
  2012.     bzero ((char *)&diag,sizeof(diag));
  2013.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  2014.         perror ("Reading X.25 diagnostic");
  2015.         return(-1);
  2016.     }
  2017.     if (diag.datalen > 0) {
  2018.         printf ("X.25 Diagnostic :");
  2019.         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
  2020.         printf ("\r\n");
  2021.     }
  2022. #endif /*  SUNX25 */
  2023.  
  2024.     return(0);
  2025. }
  2026.  
  2027. /* X.25 Out-of-Band Signal Handler */
  2028. #ifdef SUNX25
  2029. VOID
  2030. x25oobh() {
  2031.     int oobtype;
  2032.     u_char oobdata;
  2033.  
  2034.     (VOID) signal(SIGURG,x25oobh);
  2035.     do {
  2036.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  2037.             perror ("Getting signal type");
  2038.             return;
  2039.         }
  2040.         switch (oobtype) {
  2041.       case INT_DATA:
  2042.         if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
  2043.         perror ("Receiving X.25 interrupt data");
  2044.         return;
  2045.         }
  2046.         printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
  2047.         break;
  2048.       case VC_RESET:
  2049.         printf ("\r\nVirtual circuit reset\r\n");
  2050.         x25diag ();
  2051.         break;
  2052.       case N_RESETS:
  2053.         printf ("\r\nReset timeout\r\n");
  2054.         break;
  2055.       case N_CLEARS:
  2056.         printf ("\r\nClear timeout\r\n");
  2057.         break;
  2058.       case MSG_TOO_LONG:
  2059.         printf ("\r\nMessage discarded, too long\r\n");
  2060.         break;
  2061.       default:
  2062.         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  2063.         break;
  2064.     }
  2065.     } while (oobtype);
  2066. }
  2067. #endif /* SUNX25 */
  2068.  
  2069. /* Send a X.25 interrupt packet */
  2070.  
  2071. int
  2072. #ifdef CK_ANSIC
  2073. x25intr(char intr)
  2074. #else
  2075. x25intr(intr) char intr;
  2076. #endif /* CK_ANSIC */
  2077. /* x25intr */ {
  2078.     short vcid = ttyfd;
  2079.     short status;
  2080.     short diag;
  2081.  
  2082.     debug(F101,"X.25 intr, char","",(long) intr);
  2083.     s$vc_send_interrupt (&vcid, &intr, &status);
  2084.     debug(F101,"s$vc_send_interrupt status",0,status);
  2085.  
  2086.     s$vc_status (&vcid, &diag, &status);
  2087.     debug(F101,"s$vc_status status",0,status);
  2088.  
  2089.     return(0);
  2090. }
  2091.  
  2092. /* Reset X.25 virtual circuit */
  2093. int
  2094. #ifdef CK_ANSIC
  2095. x25reset(char cause, char diagn)
  2096. #else
  2097. x25reset(cause, diagn) char cause; char diagn;
  2098. #endif /* CK_ANSIC */
  2099. /* x25reset */ {
  2100.     short vcid = ttyfd;
  2101.     short status;
  2102.     short vc_diag;
  2103.     char  buff[50];
  2104.  
  2105.     sprintf (buff, "cause=%d[IGNORED], diag=%d", cause, diagn);
  2106.     vc_diag = (CHAR) diagn;
  2107.     s$vc_reset (&vcid, &vc_diag, &status);
  2108.     debug(F111,"X.25 reset, status",buff,status);
  2109.     return(0);
  2110. }
  2111.  
  2112. /* Clear X.25 virtual circuit */
  2113. int
  2114. x25clear() {
  2115.     short vcid = ttyfd;
  2116.     short diag = 0;
  2117.     short status;
  2118.  
  2119.     s$vc_clear (&vcid, &diag, &status);
  2120.     debug(F101,"X.25 clear status","",status);
  2121.     return(ttclos(0));            /* Close socket */
  2122. }
  2123.  
  2124. /* X.25 status */
  2125. int
  2126. x25stat() {
  2127.     if (ttyfd < 0) return (-1);
  2128.     return(0);
  2129. }
  2130.  
  2131. /* Set Q_BIT on */
  2132. VOID
  2133. setqbit() {
  2134.     x25qbit = 1;
  2135. }
  2136.  
  2137. /* Set Q_BIT off */
  2138. VOID
  2139. resetqbit() {
  2140.     x25qbit = 0;
  2141. }
  2142.  
  2143. /* Read n characters from X.25 circuit into buf */
  2144. int
  2145. x25xin(n,buf) int n; CHAR *buf; {
  2146.     register int x, c;
  2147.     int qpkt;
  2148.     short vcid = ttyfd;
  2149.     short buffsize = n;
  2150.     short packsize;
  2151.     short mbit;
  2152.     short qbit;
  2153.     char  intchar;
  2154.     short diag;
  2155.     short status;
  2156.  
  2157.     do {
  2158.     if (netnowait)    /* do this in no_wait mode */
  2159.         s$vc_set_no_wait_mode ();
  2160.  
  2161.     s$vc_recv_packet (&vcid, &buffsize, buf, &packsize,
  2162.         &qbit, &mbit, &status);
  2163.         debug(F101,"s$vc_recv_packet status","",status);
  2164.  
  2165.     if (netnowait) /* change it back for everything else */
  2166.         s$vc_set_wait_mode ();
  2167.  
  2168.     x = (status)? (-1) : packsize;
  2169.     switch (status) {
  2170.         case 0:
  2171.         break;
  2172.  
  2173.         case e$vc_interrupt_pending:
  2174.         s$vc_recv_interrupt (&vcid, &intchar, &status);
  2175.         debug(F101,"s$vc_recv_interrupt status","",status);
  2176.         break;
  2177.  
  2178.         case e$vc_reset_pending:
  2179.         s$vc_reset (&vcid, &diag, &status);
  2180.         debug(F101,"s$vc_reset status","",status);
  2181.         break;
  2182.  
  2183.         case e$caller_must_wait:
  2184.         x = 0;
  2185.         break;
  2186.  
  2187.         default:
  2188.         return (-2); /* I dunno, but it's broke */
  2189.     }
  2190.  
  2191.     if (x > 0 && qbit) { /* If Q_BIT packet, process it */
  2192.         if ((c=qbitpkt(buf,x)) < 0)
  2193.         return(c);
  2194.         qpkt = 1;
  2195.     } else qpkt = 0;
  2196.     } while (qpkt);
  2197.  
  2198.     if (x >= 0)
  2199.     buf[x] = '\0';
  2200.     else
  2201.     x = -1;
  2202.  
  2203.     debug(F101,"x25xin x","",x);
  2204.  
  2205.     return(x);
  2206. }
  2207. #endif /* STRATUSX25 */
  2208. #endif /* NETCONN */
  2209.