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

  1. #include "ckcsym.h"
  2. char *cknetv = "Stratus VOS Network Support, 5A(004) 19 Oct 94";
  3.  
  4. /*  C K C 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, 1993, Trustees of Columbia University in the City of New
  28.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  29.   sold for profit as a software product itself, nor may it be included in or
  30.   distributed with commercial products or otherwise distributed by commercial
  31.   concerns to their clients or customers without written permission of the
  32.   Office of Kermit Development and Distribution, Columbia University.  This
  33.   copyright notice must not be removed, altered, or obscured.
  34. */
  35.  
  36. #include "ckcdeb.h"
  37. #include "ckcker.h"
  38. #include "ckcnet.h"
  39.  
  40. #ifdef NETCONN
  41. /* Don't need these if there is no network support. */
  42.  
  43. #include <errno.h>
  44. #include <setjmp.h>
  45. #include <signal.h>
  46. #include <error_codes.h>
  47.  
  48. /* only need these includes if using OS TCP/IP */
  49. #ifdef TCPSOCKET
  50. #include <tcp_socket.h>
  51. #include <ioctl.h>
  52. #endif /* TCPSOCKET */
  53.  
  54. /* only need these for X.25 support */
  55. #ifdef STRATUSX25
  56. _PROTOTYP( extern VOID s$read_event, (long *event_id, long *event_count,
  57.     short *event_status, short *status) );
  58.  
  59. _PROTOTYP( extern VOID s$vc_call_full, (CV(32) *gateway, CV(15) *address, 
  60.     CV(63) *facilities, CV(128) *call_data, void *opts, long *timeout,
  61.     short *vcid, long *event_id, short *status) );
  62.  
  63. _PROTOTYP( extern VOID s$vc_call_full_sts, (CV(66) *destination, 
  64.     short *extension, CV(63) *facilities, CV(128) *call_data, void *opts,
  65.     long *timeout, short *vcid, long *event_id, short *status) );
  66.  
  67. _PROTOTYP( extern VOID s$vc_clear, (short *vcid, short *diag, short *status) );
  68.  
  69. _PROTOTYP( extern VOID s$vc_recv_packet, (short *vcid, short *buff_len,
  70.     void *buff, short *packet_size, short *level, short *more,
  71.     short *status) );
  72.  
  73. _PROTOTYP( extern VOID s$vc_recv_interrupt, (short *vcid, char *data,
  74.     short *status) );
  75.  
  76. _PROTOTYP( extern VOID s$vc_reset, (short *vcid, short *diag, short *status) );
  77.  
  78. _PROTOTYP( extern VOID s$vc_send_interrupt, (short *vcid, char *data,
  79.     short *status) );
  80.  
  81. _PROTOTYP( extern VOID s$vc_send_packet, (short *vcid, short *buff_len,
  82.     void *buff, short *level, short *more, short *status) );
  83.  
  84. _PROTOTYP( extern VOID s$vc_set_no_wait_mode, (void) );
  85.  
  86. _PROTOTYP( extern VOID s$vc_set_wait_mode, (void) );
  87.  
  88. _PROTOTYP( extern VOID s$vc_status, (short *vcid, short *diag_code,
  89.     short *status) );
  90.  
  91. extern int linkid, lcn, x25ver;
  92. extern int revcall, closgr, cudata;
  93. extern CHAR udata[MAXCUDATA];
  94. extern CHAR padparms[MAXPADPARMS+1];
  95.  
  96. static long vcid_event;    /* have to save this from open */
  97. static short x25qbit;    /* qbit out flag */
  98. #endif /* STRATUSX25 */
  99.  
  100. static int netnowait;
  101.  
  102. extern SIGTYP (*saval)();        /* For saving alarm handler */
  103.  
  104. _PROTOTYP( VOID bgchk, (void) );
  105. _PROTOTYP( long congspd, (void) ); /* returns speed of console device */
  106.  
  107. extern int                /* External variables */
  108.   duplex, debses, seslog, sessft, ttyfd, quiet, msgflg;
  109.  
  110. #define NAMECPYL 100            /* Local copy of hostname */
  111. static char namecopy[NAMECPYL];
  112. char ipaddr[20] = { '\0' };        /* Global copy of IP address */
  113. #endif /* NETCONN */
  114.  
  115. int ttnet = NET_NONE;            /* Network type */
  116. int ttnproto = NP_NONE;            /* Network virtual terminal protocol */
  117. int tn_init = 0;            /* Telnet protocol initialized flag */
  118. int tn_duplex = 1;            /* Initial echo status */
  119. char *tn_term = NULL;            /* Terminal type override */
  120. int tn_nlm = 1;                /* Telnet CR -> CR LF mode */
  121.  
  122. #ifndef NETCONN
  123. /*
  124.   Network support not defined.
  125.   Dummy functions here in case #ifdef's forgotten elsewhere.
  126. */
  127. int                    /* Open network connection */
  128. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  129.     return(-1);
  130. }
  131. int                    /* Close network connection */
  132. netclos() {
  133.     return(-1);
  134. }
  135. int                    /* Check network input buffer */
  136. nettchk() {
  137.     return(-1);
  138. }
  139. int                    /* Flush network input buffer */
  140. netflui() {
  141.     return(-1);
  142. }
  143. int                    /* Send network BREAK */
  144. netbreak() {
  145.     return(-1);
  146. }
  147. int                    /* Input character from network */
  148. netinc(timo) int timo; {
  149.     return(-1);
  150. }
  151. int                    /* Output character to network */
  152. #ifdef CK_ANSIC
  153. nettoc(char c)
  154. #else
  155. nettoc(c) char c;
  156. #endif /* CK_ANSIC */
  157. /* nettoc */ {
  158.     return(-1);
  159. }
  160. int
  161. nettol(s,n) char *s; int n; {
  162.     return(-1);
  163. }
  164.  
  165. #else /* NETCONN is defined (rest of this module...) */
  166.  
  167. /* For buffered network reads... */
  168. #define TTXBUFL 1024            /* Maybe 8K?... */
  169.  
  170. extern CHAR     ttxbuf[TTXBUFL+1];
  171. extern int     ttxbp, ttxbn = 0;
  172. /*
  173.   Read bytes from network into internal buffer ttxbuf[], the same buffer
  174.   that is used by ttbufr routine in ASYNC terminal io.
  175.   To be called when input buffer is empty, i.e. when ttxbn == 0.
  176.  
  177.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  178.   internal buffer first, and call this routine for a refill if necessary.
  179.  
  180.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  181.   returns number of bytes read, and sets global ttxbn to that number and
  182.   ttxbp (the buffer pointer) to zero.
  183. */
  184. int
  185. netbufr(int timo) {                /* TT Buffer Read */
  186.     int count;
  187.     short status;
  188.  
  189.     if (ttnet != NET_TCPB &&        /* First make sure current net is */
  190.     ttnet != NET_VX25) {        /* supported (VOS X.25 & OS TCP/IP) */
  191.     return(-1);            /* if not, do nothing. */
  192.     }
  193.  
  194.     if (ttxbn > 0)            /* Out internal buffer is not empty, */
  195.     return(ttxbn);            /* so keep using it. */
  196.  
  197.     count = nettchk();            /* Check network input buffer, */
  198.     if (ttxbn > 0) return(ttxbn);    /* which can put a char there! */
  199.     if (count < 0)            /* Read error */
  200.       return(-1);
  201.     else if (count > TTXBUFL)        /* Too many to read */
  202.       count = TTXBUFL;
  203.     else if (count == 0)        /* None, so read */
  204.       count = 1;
  205.  
  206.     debug(F101,"netbufr count 1","",count);
  207.  
  208. #ifdef TCPSOCKET
  209.     if (ttnet == NET_TCPB) {
  210.     /* This is for nonblocking reads */
  211.     if ((count = net_read(ttyfd,ttxbuf,count,0)) < 1) {
  212.         if (count == -1 && errno == e$caller_must_wait) {
  213.         debug(F100,"netbufr finds nothing","",0);
  214.         return(0);
  215.         } else if (count == 0) {
  216.         debug(F100,"netbufr socket eof","",0);        
  217.         return(-2);  /* this is really a disconnect */
  218.         } else {
  219.         debug(F101,"netbufr net_read error","",errno);
  220.         return(-2); /* say it's disconnected */
  221.         }
  222.     }
  223.     }
  224. #endif /* TCPSOCKET */
  225.  
  226. #ifdef STRATUSX25
  227.     if (ttnet == NET_VX25) {
  228.     count = x25xin(sizeof(ttxbuf), ttxbuf);
  229.     if (count <= 0)
  230.         return count;
  231.     }    
  232. #endif /* STRATUSX25 */
  233.  
  234.     ttxbp = 0;            /* Reset buffer pointer. */
  235.     ttxbn = count;
  236.  
  237. #ifdef DEBUG
  238.     debug(F101,"netbufr count 2","",count); /* Got some bytes. */
  239.     if (count > 0) ttxbuf[count] = '\0';
  240.     debug(F111,"netbufr ttxbuf",ttxbuf,ttxbp);
  241. #endif /* DEBUG */
  242.  
  243.     return(ttxbn);            /* Return buffer count. */
  244. }
  245.  
  246. /*
  247.   C-Kermit network open/close functions for OS TCP/IP & X.25/X.29 Networking.
  248. */
  249.  
  250. /*  N E T O P E N  --  Open a network connection.  */
  251.  
  252. /*  Returns 0 on success, -1 on failure.  */
  253.  
  254. #ifdef TCPSOCKET
  255. #define    TELNET_PORT    23       /* Should do lookup, but it won't change */
  256.  
  257. /* This symbol is not known to, e.g., Ultrix 2.0 */
  258. #ifndef TELOPT_TTYPE
  259. #define TELOPT_TTYPE 24
  260. #endif /* TELOPT_TTYPE */
  261. #endif /* TCPSOCKET */
  262.  
  263. /*  N E T O P E N  --  Open a network connection  */
  264. /*
  265.   Calling conventions same as ttopen(), except third argument is network
  266.   type rather than modem type.  Designed to be called from within ttopen.
  267. */
  268. int
  269. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  270.     char *p;
  271. #ifdef SO_OOBINLINE
  272.     int on = 1;
  273. #endif /* SO_OOBINLINE */
  274.     int i, x;
  275. #ifdef TCPSOCKET
  276.     struct servent *service, servrec;
  277.     struct hostent *host;
  278.     struct sockaddr_in saddr;
  279. #endif /* TCPSOCKET */
  280.  
  281. #ifdef STRATUSX25
  282.     CV(66) destination;
  283.     CV(15) address;
  284.     CV(63) facilities;
  285.     CV(128) call_data;
  286.     long x25_timeout;
  287.     short vcid;
  288.     short status;
  289.     struct {
  290.     short version;
  291.     short max_delay;
  292.     short send_size;
  293.     short recv_size;
  294.     } x25_options;
  295.     short sts_extension;
  296. #endif /* STRATUSX25 */
  297.  
  298.     debug(F101,"netopen nett","",nett);
  299.     *ipaddr = '\0';            /* Initialize IP address string */
  300.  
  301. #ifdef STRATUSX25
  302.     if (nett == NET_VX25) {        /* If network type is X.25 */
  303.         netclos();            /* Close any previous net connection */
  304.         ttnproto = NP_NONE;        /* No protocol selected yet */
  305.     sts_extension = -1;
  306.  
  307.     strncpy (namecopy, name, NAMECPYL);
  308.     p = strchr (namecopy, ':');
  309.     if (NULL == p) { /* no address given */
  310.         strcpy (&destination, namecopy);
  311.         strcpy (&address, "");
  312.     }
  313.     else { /* address in part of name */
  314.         *p++ = '\0';
  315.         strcpy (&destination, namecopy);
  316.         strcpy (&address, p);
  317.     }
  318.  
  319.     if (namecopy[0] == '%') {    /* STS with %system#module */
  320.          /* remove % from destination if no module name given */
  321.         if (NULL == strchr (namecopy, '#')) /* no module name */
  322.         strcpy (&destination, &namecopy[1]);
  323.  
  324.         sts_extension = (*p) ? atoi (p) : 255;
  325.         strcpy (&call_data, ""); /* STS includes protocol ID */
  326.     }
  327.     else
  328.         memcpy (&call_data, "\x00\x04\x01\x00\x00\x00", 6); /* KLUDGE! */
  329.  
  330.     /* Set call user data if specified */
  331.         if (cudata)
  332.             strcat(&call_data,udata);
  333.  
  334.     strcpy (&facilities, "");
  335.     
  336.         /* Set reverse charge call and closed user group if requested */
  337.     if (revcall) {        /* reverse charge requested */
  338.         strcat (&facilities, "\x01\x01");
  339.     }
  340.  
  341.     /* closed user group not supported */
  342.         if (closgr > -1) {
  343.         debug(F101,"x25 closed user group not supported","",closgr);
  344.         }
  345.  
  346.     x25_options.version = 1;
  347.     x25_options.max_delay = 0;
  348.     x25_options.send_size = 1024;
  349.     x25_options.recv_size = 1024;
  350.  
  351.     x25_timeout = 30 * 1024; /* lost timeout coming to netopen() */
  352.  
  353.         /* Open X.25 virtual circuit */
  354.     if (sts_extension > -1) {
  355.         s$vc_call_full_sts (&destination, &sts_extension, &facilities,
  356.         &call_data, &x25_options, &x25_timeout, &vcid,
  357.         &vcid_event, &status);
  358.         debug(F101,"netopen s$vc_call_full_sts status","",status);
  359.     }
  360.     else {
  361.         s$vc_call_full ((CV(32) *)&destination, &address, &facilities,
  362.         &call_data, &x25_options, &x25_timeout, &vcid,
  363.         &vcid_event, &status);
  364.         debug(F101,"netopen s$vc_call_full status","",status);
  365.     }
  366.  
  367.     if (status) {
  368.             return (-1);
  369.         }
  370.  
  371.     lcn = vcid;
  372.     ttyfd = vcid;
  373.     linkid = sts_extension;
  374.  
  375.         ttnet = nett;                   /* Stratus X.25 network */
  376.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  377.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  378.         return(0);
  379.     }
  380. #endif /* STRATUSX25 */
  381.  
  382. #ifdef TCPSOCKET
  383.     if (nett == NET_TCPB) {
  384.     netclos();            /* Close any previous connection. */
  385.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  386.     ttnproto = NP_NONE;        /* No protocol selected yet. */
  387.     debug(F110,"netopen namecopy",namecopy,0);
  388.  
  389.     p = namecopy;            /* Was a service requested? */
  390.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  391.     if (*p == ':') {        /* Have a colon */
  392.         *p++ = '\0';        /* Get service name or number */
  393.     } else {            /* Otherwise use telnet */
  394.         p = "telnet";
  395.     }
  396.     debug(F110,"netopen service requested",p,0);
  397.     if (isdigit(*p)) {        /* Use socket number without lookup */
  398.         service = &servrec;
  399.         service->s_port = htons((unsigned short)atoi(p));
  400.     } else {            /* Otherwise lookup the service name */
  401.         service = getservbyname(p, "tcp");
  402.     }
  403.     if (!service) {
  404.         fprintf(stderr, "Cannot find port for service %s\n", p);
  405.  
  406.         debug(F101,"netopen can't get service","",errno);
  407.  
  408.         errno = 0;            /* rather than mislead */
  409.         return(-1);
  410.     }
  411.     /* Set up socket structure and get host address */
  412.  
  413.     bzero((char *)&saddr, sizeof(saddr));
  414.     if ((host = gethostbyname(namecopy)) != NULL) {
  415.         saddr.sin_family = host->h_addrtype;
  416.         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
  417.     } else {
  418. #ifdef INADDRX
  419. /* inet_addr() is of type struct in_addr */
  420.         struct in_addr ina;
  421.         unsigned long uu;
  422.  
  423.         ina = inet_addr(namecopy);
  424.         uu = *(unsigned long *)&ina;
  425.  
  426. #else /* Not INADDRX */
  427. /* inet_addr() is unsigned long */
  428.         unsigned long uu;
  429.         uu = inet_addr(namecopy);
  430. #endif /* INADDRX */
  431.  
  432.         if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
  433.           saddr.sin_family = AF_INET;
  434.         else {
  435.           fprintf(stderr, "Can't get address for %s\n", namecopy);
  436.  
  437.           debug(F101,"netopen can't get address","",errno);
  438.  
  439.           errno = 0;            /* rather than mislead */
  440.           return(-1);
  441.       }
  442.     }
  443.  
  444.     /* Get a file descriptor for the connection. */
  445.  
  446.     saddr.sin_port = service->s_port;
  447.     sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr));
  448.     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
  449.  
  450.     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  451.         perror("TCP socket error");
  452.         debug(F101,"netopen socket error","",errno);
  453.         return (-1);
  454.     }
  455.     errno = 0;
  456.  
  457.     /* Now connect to the socket on the other end. */
  458.  
  459.     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  460.         i = errno;            /* save error code */
  461.         close(ttyfd);
  462.         ttyfd = -1;
  463.         errno = i;            /* and report this error */
  464.  
  465.         debug(F101,"netopen connect errno","",errno);
  466.         return(-1);
  467.     }
  468. #ifdef SO_OOBINLINE
  469.     /*
  470.       The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  471.       It means "leave out of band data inline".  The normal value is 0x0100,
  472.       but don't try this on systems where the symbol is undefined.
  473.     */
  474.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  475. #endif /* SO_OOBINLINE */
  476.  
  477.     /* See if the service is TELNET. */
  478.     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
  479.         ttnproto = NP_TELNET;    /* Yes, set global flag. */
  480.     debug(F101,"netopen service","",x);
  481.     ttnet = nett;            /* TCP/IP (sockets) network */
  482.     tn_init = 0;            /* Telnet protocol not init'd yet */
  483.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  484.     return(0);                /* Done. */
  485.     }
  486. #endif /* TCPSOCKET */
  487.  
  488. /*
  489.   Add support for other networks here.
  490. */
  491.     return(-1);                /* Unsupported Network type */
  492. }
  493.  
  494. /*  N E T C L O S  --  Close current network connection.  */
  495.  
  496. int
  497. netclos() {
  498.     int x = 0;
  499.     short vcid;
  500.     short status;
  501.     short diag;
  502.  
  503.     if (ttyfd < 0)            /* Was open? */
  504.       return(0);            /* Wasn't. */
  505.  
  506. #ifdef STRATUSX25
  507.     if (ttnet == NET_VX25) {
  508.     if (ttyfd > -1) {
  509.         vcid = ttyfd;
  510.         diag = 0;
  511.         s$vc_clear (&vcid, &diag, &status);
  512.         debug(F101,"s$vc_clear status","",status);
  513.  
  514.         ttyfd = -1;
  515.         x = (status == 0) ? 0 : -1;
  516.     }
  517.     }
  518. #endif /* STRATUSX25 */
  519. #ifdef TCPSOCKET
  520.     if (ttnet == NET_TCPB) {
  521.     if (ttyfd > -1)            /* Was. */
  522.         x = net_close(ttyfd);
  523.     }
  524. #endif /* TCPSOCKET */
  525.     ttyfd = -1;                /* Mark it as closed. */
  526.     tn_init = 0;            /* Remember about telnet protocol... */
  527.     *ipaddr = '\0';            /* Zero the IP address string */
  528.  
  529.     return(x);
  530. }
  531.  
  532. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  533. /*
  534.   Returns number of bytes waiting, or -1 if connection has been dropped.
  535. */
  536. int                    /* Check how many bytes are ready */
  537. nettchk() {                /* for reading from network */
  538.     unsigned int count = 0;
  539.     int x, y;
  540.     char c;
  541.  
  542.     x = y = 0;
  543.  
  544. #ifdef COMMENT
  545.     debug(F101,"nettchk entry ttxbn","",ttxbn);
  546.     debug(F101,"nettchk entry ttxbp","",ttxbp);
  547. #endif
  548.     errno = 0;
  549.  
  550.     /* for X.25, just return count of buffered characters */
  551.  
  552. #ifdef TCPSOCKET
  553.     if (ttnet == NET_TCPB) {
  554.     if (net_ioctl(ttyfd,FIONREAD,(char *)&count) < 0) {
  555.         debug(F101,"nettchk net_ioctl error","",errno);
  556.         if (ttxbn < 1) return(-1);
  557.         else return(ttxbn);
  558.     }
  559.     debug(F101,"nettchk count","",count);
  560.     }
  561. #endif /* TCPSOCKET */
  562.  
  563.     /* count what's in network and what we have buffered */
  564.     debug(F101,"nettchk returns","",count+ttxbn);
  565.     return(count + ttxbn);
  566. }
  567.  
  568. /*  N E T I N C --  Input character from network */
  569.  
  570. int            
  571. netinc(timo) int timo; {
  572.     debug(F101,"WARNING: netinc called, timo","",timo);
  573.     return(-1);
  574. }
  575.  
  576. /*  N E T T O L  --  Output a string of bytes to the network  */
  577. /*
  578.   Call with s = pointer to string, n = length.
  579.   Returns number of bytes actually written on success, or
  580.   -1 on i/o error, -2 if called improperly.
  581. */
  582. int
  583. nettol(s,n) char *s; int n; {
  584.     int count = 0;
  585.     short buflen = n;
  586.  
  587. #ifdef TCPSOCKET
  588.     if (ttnet == NET_TCPB) {
  589.     if ((count = net_write(ttyfd,s,n,0)) < 1) {
  590.         debug(F101,"nettol net_write error","",errno);
  591.         return(-1);
  592.     }
  593.     debug(F111,"nettol net_write",s,count);
  594.     return(count);
  595.     }
  596. #endif /* TCPSOCKET */
  597.  
  598. #ifdef STRATUSX25
  599.     if (ttnet == NET_VX25) {
  600.     short mbit = 0;
  601.     short vcid = ttyfd;
  602.     short status;
  603.  
  604.     if (0 == x25qbit && padparms[PAD_DATA_FORWARD_TIMEOUT])
  605.         mbit = 2; /* stream data, may combine packets */
  606.  
  607.         if (buflen > 1024)            /* only try to send 1K */
  608.         buflen = 1024;
  609.  
  610.     s$vc_send_packet (&vcid, &buflen, s, &x25qbit, &mbit, &status);
  611.     s[n] = '\0';
  612.     debug(F111,"nettol s$vc_send_packet status",s,status);
  613.  
  614.     if (status) return (-1);
  615.  
  616.     count = buflen;
  617.     return (count);
  618.     }
  619. #endif /* STRATUSX25 */
  620.  
  621.    return(-2);
  622. }
  623.  
  624. /*  N E T T O C  --   Output character to network */
  625. /*
  626.   Call with character to be transmitted.
  627.   Returns 0 if transmission was successful, or
  628.   -1 upon i/o error, or -2 if called improperly.
  629. */
  630. int            
  631. #ifdef CK_ANSIC
  632. nettoc(char c)
  633. #else
  634. nettoc(c) char c;
  635. #endif /* CK_ANSIC */
  636. /* nettoc */ {
  637.     unsigned char cc;
  638.  
  639.     cc = c;
  640.  
  641. #ifdef TCPSOCKET
  642.     if (ttnet == NET_TCPB) {
  643.     debug(F101,"nettoc cc","",cc);
  644.     if (net_write(ttyfd,&cc,1,0) < 1) {
  645.         debug(F101,"nettoc net_write error","",errno);
  646.         return(-1);
  647.     }
  648.     debug(F101,"nettoc net_write","", cc);
  649.     return(0);
  650.     }
  651. #endif /* TCPSOCKET */
  652.  
  653. #ifdef STRATUSX25
  654.     if (ttnet == NET_VX25) {
  655.     short mbit = 2;    /* may be joined with other packets before send */
  656.     short vcid = ttyfd;
  657.     short buflen = 1;
  658.     short status;
  659.  
  660.     s$vc_send_packet (&vcid, &buflen, &cc, &x25qbit, &mbit, &status);
  661.     if (status) {
  662.         debug(F101,"nettoc s$vc_send_packet status",0,status);
  663.     }
  664.     return (status ? -2 : 0);
  665.     }
  666. #endif /* STRATUSX25 */
  667.  
  668.     return(-2);
  669. }
  670.  
  671. /*  N E T F L U I  --  Flush network input buffer  */
  672.  
  673. int
  674. netflui() {
  675.     int n;
  676.  
  677.     ttxbuf[ttxbp+1] = '\0';
  678.     debug(F111,"netflui 1",ttxbuf,ttxbn);
  679.     ttxbn = ttxbp = 0;            /* Flush internal buffer *FIRST* */
  680.     if ((n = nettchk()) > 0) {        /* Now see what's waiting on the net */
  681.     if (n > TTXBUFL) n = TTXBUFL;    /* and sponge it up */
  682.     debug(F101,"netflui 2","",n);    /* ... */
  683.  
  684. #ifdef TCPSOCKET
  685.     if (ttnet == NET_TCPB)
  686.         n = net_read(ttyfd,ttxbuf,n,0) ; /* into our buffer */
  687.     else
  688.         n = 0;
  689. #endif /* TCPSOCKET */
  690.  
  691. #ifdef STRATUSX25
  692.     if (ttnet == NET_VX25)
  693.         n = 0;    /* x25 don't read to flush */
  694. #endif /* STRATUSX25 */
  695.  
  696.     if (n >= 0) ttxbuf[n] = '\0';
  697.     debug(F111,"netflui 3",ttxbuf,n);
  698.     ttxbuf[0] = '\0';
  699.     }
  700.  
  701.     return(0);
  702. }
  703.  
  704.  
  705. /* N E T W A I T -- Set a network connection back and forth
  706.                     between wait mode and nowait mode, used by
  707.                     contti during network connections.  Assumes
  708.                     the caller logs the statuses.
  709.  
  710. */
  711. int
  712. #ifdef CK_ANSIC
  713. netwait(int no_wait, int sd, long *evid, long *evcnt)
  714. #else
  715. netwait(no_wait, sd, evid, evcnt) int no_wait; int sd; long *evid; long *evcnt;
  716. #endif
  717. /* netwait(int no_wait, int sd, long *evid, long *evcnt) */ {
  718.  
  719.     short status;
  720.     int y;
  721.     int x;
  722.     short event_stat;
  723.  
  724.     status = 0;
  725.     debug(F101,"netwait no_wait","",no_wait);
  726.     debug(F101,"        sd","",sd);
  727.  
  728.     netnowait = no_wait;
  729.  
  730. #ifdef STRATUSX25
  731.     /* X.25 we don't actually change the mode.  We stay in wait mode for
  732.     everything except receiving packets.
  733.     */
  734.     if (ttnet == NET_VX25) {
  735.     if (no_wait) { /* pass back the saved event information */
  736.         *evid = vcid_event;
  737.         s$read_event (evid, evcnt, &event_stat, &status);
  738.     }
  739.     }
  740. #endif /* STRATUSX25 */
  741.  
  742. #ifdef TCPSOCKET
  743.     if (ttnet == NET_TCPB) {
  744.     if (no_wait) {
  745.         if (0 > get_socket_event (sd, evid, evcnt)) {
  746.         status = errno;
  747.         return status;
  748.         }
  749.         y = 0;                /* Turn on nonblocking reads */
  750.         x = net_ioctl(ttyfd,FIONBIO,(char*)&y);
  751.         debug(F101,"netwait FIONBIO","",x);
  752.         if (x < 0) status = errno;
  753.     }
  754.     else {
  755.         y = 1;                /* Turn on blocking reads */
  756.         x = net_ioctl(ttyfd,FIONBIO,(char*)&y);
  757.         debug(F101,"netwait FIONBIO","",x);
  758.         if (x < 0) status = errno;
  759.     }
  760.     }
  761. #endif /* TCPSOCKET */
  762.  
  763.     return (status);
  764. }
  765.  
  766. #ifdef TCPSOCKET
  767.  
  768. #ifdef TNCODE                /* Compile in telnet support code */
  769.  
  770. /* TCP/IP TELNET protocol negotiation support code */
  771.  
  772. static int sgaflg = 0;            /* SUPRRESS GO-AHEAD state */
  773. static int dosga  = 0;            /* 1 if I sent DO SGA from tn_ini() */
  774. static int wttflg = 0;            /* ditto for WILL TERMINAL TYPE */
  775.  
  776. #ifndef TELCMDS
  777. char *telcmds[] = {
  778.     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
  779.     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
  780. };
  781. int ntelcmds = sizeof(telcmds) / sizeof(char *);
  782. #endif /* TELCMDS */
  783.  
  784. #ifndef TELOPTS
  785. char *telopts[] = {
  786.     "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
  787.     "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
  788.     "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
  789.     "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
  790.     "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
  791.     "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD"
  792. #ifdef TELOPT_TUID
  793.     ,"TACACS UID"
  794. #ifdef TELOPT_OUTMRK
  795.     ,"OUTPUT MARKING"
  796. #ifdef TELOPT_TTYLOC
  797.     ,"TTYLOC"
  798. #ifdef TELOPT_3270REGIME
  799.     ,"3270 REGIME"
  800. #ifdef TELOPT_X3PAD
  801.     ,"X.3 PAD"
  802. #ifdef TELOPT_NAWS
  803.     ,"NAWS"
  804. #ifdef TELOPT_TSPEED
  805.     ,"TSPEED"
  806. #ifdef TELOPT_LFLOW
  807.     ,"LFLOW"
  808. #ifdef TELOPT_LINEMODE
  809.     ,"LINEMODE"
  810. #endif
  811. #endif
  812. #endif
  813. #endif
  814. #endif
  815. #endif
  816. #endif
  817. #endif
  818. #endif
  819. };
  820. #endif /* TELOPTS */
  821.  
  822. int ntelopts = sizeof(telopts) / sizeof(char *);
  823. #endif /* TNCODE */
  824. #endif /* TCPSOCKET */
  825.  
  826. /* Send network BREAK */
  827. /*
  828.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  829. */
  830. int
  831. netbreak() {
  832.     CHAR buf[3];
  833.  
  834. #ifdef TCPSOCKET
  835.     if (ttnet == NET_TCPB) {
  836.     if (ttnproto == NP_TELNET) {
  837. #ifdef TNCODE
  838.         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK;
  839.         if (ttol(buf,2) < 2) return(-1);
  840.         debug(F101,"telnet BREAK ok","",BREAK);
  841.         return(1);
  842. #else
  843.         debug(F100,"netbreak no TNCODE","",0);
  844.         return(0);
  845. #endif /* TNCODE */
  846.     }
  847.     /* Insert other TCP/IP protocols here */
  848.     }
  849. #endif /* TCPSOCKET */
  850.  
  851. #ifdef STRATUSX25
  852.     if (ttnet == NET_VX25) {
  853.     breakact ();
  854.     }
  855. #endif /* STRATUSX25 */
  856.  
  857.     /* Insert other networks here */
  858.     return(0);
  859. }
  860.  
  861. /* Send a telnet option, avoid loops. */
  862. /* Returns 1 if command was sent, 0 if not, -1 on error */
  863.  
  864. #ifdef TCPSOCKET
  865. int
  866. tn_sopt(cmd,opt) int cmd, opt; {    /* TELNET SEND OPTION */
  867.     CHAR buf[4];
  868.     int n;
  869.     if (ttnet != NET_TCPB) return(0);    /* Must be TCP/IP */
  870.     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
  871.     n = cmd - SE;
  872.     if (n < 0 || n > ntelcmds) return(0);
  873. #ifdef TNCODE
  874.     buf[0] = (CHAR) IAC;
  875.     buf[1] = (CHAR) cmd & 0xff;
  876.     buf[2] = (CHAR) opt & 0xff;
  877.     if (ttol(buf,3) < 3)
  878.       return(-1);
  879.     debug(F111,"telnet cmd >",telcmds[n],cmd);
  880.     debug(F111,"telnet opt >",
  881.       (opt < ntelopts) ? telopts[opt] : "UNKNOWN", opt );
  882.     if (debses && cmd != SB)
  883.       printf("[%s %s]",telcmds[n],
  884.          (opt < ntelopts) ? telopts[opt] : "UNKNOWN");
  885.     return(1);
  886. #else
  887.     debug(F100,"tn_sopt no TNCODE","",0);
  888.     return(0);
  889. #endif /* TNCODE */
  890. }
  891.  
  892. /* Initialize a telnet connection. */
  893. /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
  894.  
  895. int
  896. tn_ini() {
  897. #ifndef TNCODE
  898.     debug(F100,"tn_ini no TNCODE","",0);
  899.     return(0);
  900. #else /* TELNET protocol support */
  901.     debug(F101,"tn_ini ttnproto","",ttnproto);
  902.     debug(F101,"tn_ini tn_init","",tn_init);
  903.  
  904.     if (ttnet != NET_TCPB)        /* Make sure connection is TCP/IP. */
  905.       return(0);
  906.     if (tn_init)            /* Have we done this already? */
  907.       return(0);            /* Don't do it again. */
  908.     debug(F101,"tn_ini tn_duplex","",tn_duplex);
  909.     duplex = tn_duplex;            /* Assume local echo. */
  910.     sgaflg = 0;                /* Assume Go-Ahead suppressed. */
  911.     wttflg = 0;                /* Did not send WILL TERM TYPE yet. */
  912.     dosga  = 0;                /* Did not send DO SGA yet. */
  913.     if (ttnproto == NP_NONE) {        /* If not talking to a telnet port, */
  914.     ttnproto = NP_TELNET;        /* pretend it's telnet anyway, */
  915.     tn_init = 1;            /* but don't send initial options. */
  916.     debug(F100,"tn_ini skipping telnet negotiations","",0);
  917.     return(0);
  918.     }
  919.     /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */
  920.  
  921.     if (tn_sopt(WILL,TELOPT_TTYPE) < 0)    /* Will send terminal type. */
  922.       return(-1);
  923.     wttflg = 1;                /* Remember I said I would. */
  924.     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
  925.       return(-1);
  926.     dosga = 1;                /* Remember I send DO SGA */
  927.     tn_init = 1;            /* Set telnet-initialized flag. */
  928.  
  929.     /* Don't send anthing else! */
  930.  
  931.     debug(F101,"tn_ini duplex","",duplex);
  932.     return(1);
  933. #endif /* TNCODE */
  934. }
  935.  
  936. /*
  937.   Process in-band Telnet negotiation characters from the remote host.
  938.   Call with the telnet IAC character and the current duplex setting
  939.   (0 = remote echo, 1 = local echo).
  940.   Returns:
  941.     3 if server has sent us a quoted IAC
  942.     2 if local echo must be changed to remote
  943.     1 if remote echo must be changed to local
  944.     0 if nothing happens or no action necessary
  945.    -1 on failure (= internal or i/o error)
  946. */
  947.  
  948. #define TSBUFSIZ 41
  949. char sb[TSBUFSIZ];            /* Buffer for subnegotiations */
  950.  
  951. int
  952. #ifdef CK_ANSIC                /* TELNET DO OPTION */
  953. tn_doop( CHAR z, int echo, int (*fn)(int) )
  954. #else
  955. tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
  956. #endif /* CK_ANSIC */
  957. /* tn_doop */ {
  958.     int c, x, y, n, m, flag;
  959.  
  960. #ifndef TNCODE
  961.     debug(F100,"tn_doop no TNCODE","",0);
  962.     return(0);
  963. #else
  964.     if (z != (CHAR) IAC) {
  965.     debug(F101,"tn_doop bad call","",z);
  966.     return(-1);
  967.     }
  968.     if (ttnet != NET_TCPB) return(0);
  969.     if (ttnproto != NP_TELNET) return(0);     /* Check protocol */
  970.  
  971. /* Have IAC, read command character. */
  972.  
  973.     c = (*fn)(0) & 0xff;        /* Read command character */
  974.     m = c - SE;                /* Check validity */
  975.     if (m < 0 || m > ntelcmds) {
  976.     debug(F101,"tn_doop bad cmd","",c);
  977.     return(0);
  978.     }
  979.     if (seslog && sessft) {        /* Copy to session log, if any. */
  980.     if (zchout(ZSFILE, (char) z) < 0) seslog = 0; /* Log IAC. */
  981.     else if (zchout(ZSFILE, (char) c) < 0) seslog = 0; /* Log command */
  982.     }
  983.     debug(F111,"telnet cmd <",telcmds[m],c); /* Debug log. */
  984.  
  985.     if (c == (CHAR) IAC) return(3);    /* Quoted IAC */
  986.     if (c < SB) return(0);        /* Other command with no arguments. */
  987.  
  988. /* SB, WILL, WONT, DO, or DONT need more bytes... */
  989.  
  990.     if ((x = (*fn)(0)) < 0) return(-1);    /* Get the option. */
  991.     x &= 0xff;                /* Trim to 8 bits. */
  992.  
  993.     debug(F111,"telnet opt <",
  994.       (x < ntelopts) ? telopts[x] : "UNKNOWN", x );
  995.     if (seslog && sessft)        /* Session log */
  996.       if (zchout(ZSFILE, (char) x) < 0) seslog = 0;
  997.  
  998.     /* Now handle the command */
  999.  
  1000.     if (debses && c != SB)         /* Debug to screen. */
  1001.       printf("<%s %s>",telcmds[m],
  1002.          (x < ntelopts) ? telopts[x] : "UNKNOWN" );
  1003.     switch (x) {
  1004.       case TELOPT_ECHO:            /* ECHO negotiation. */
  1005.     switch (c) {            /* Command */
  1006.       case WILL:            /* Host says it will echo. */
  1007.         if (echo)            /* Only reply if change required. */
  1008.           return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */
  1009.         else return(0);        /* Otherwise no change. */
  1010.       case WONT:            /* Host says it won't echo. */
  1011.         if (!echo)            /* If I'm full duplex */
  1012.           return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
  1013.         else return(0);        /* Otherwise, no change.  */
  1014.       case DO:            /* Host wants me to echo */
  1015.         if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
  1016.           return(-1);        /* back to the server. */
  1017.       default:            /* Don't reply to anything else */
  1018.         return(0);
  1019.     }
  1020.  
  1021.       case TELOPT_SGA:            /* Suppress Go-Ahead */
  1022.     switch (c) {            /* Command... */
  1023.       case WONT:            /* Host says it won't. */
  1024.         if (!sgaflg) {
  1025.         sgaflg = 1;        /* Remember. */
  1026.         if (tn_sopt(DONT,x) < 0) /* acknowledge, */
  1027.           return(-1);
  1028.         }
  1029.         return(echo ? 0 : 1);    /* Switch to half duplex */
  1030.       case WILL:            /* Server says it will SGA */
  1031.         if (sgaflg || !dosga) {    /* ACK only if necessary */
  1032.         if (tn_sopt(DO,x) < 0)
  1033.           return(-1);
  1034.         sgaflg = 0;        /* Remember new SGA state. */
  1035.         }
  1036.         return(0);            /* But don't change echo state. */
  1037.     }
  1038.  
  1039. #ifdef TELOPT_TTYPE
  1040.       case TELOPT_TTYPE:        /* Terminal Type */
  1041.     switch (c) {
  1042.       case DO:            /* DO terminal type. */
  1043.         if (wttflg == 0) {        /* If I haven't said so before, */
  1044.         if (tn_sopt((CHAR)WILL,x) < 0) /* say I'll send it if asked. */
  1045.           return(-1);
  1046.         wttflg++;
  1047.         }
  1048.         return(0);
  1049.       case SB:
  1050.         debug(F100,"TELNET subnegotiation:","",0);
  1051.         n = flag = 0;        /* Flag for when done reading SB */
  1052.         while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
  1053.         if ((y = (*fn)(0)) < 0)    /* Read a byte */
  1054.           return(-1);
  1055.         y &= 0xff;        /* Make sure it's just 8 bits. */
  1056.         sb[n++] = y;        /* Deposit in buffer. */
  1057.         if (seslog && sessft)    /* Take care of session log */
  1058.           if (zchout(ZSFILE, (char) y) < 0)
  1059.             seslog = 0;
  1060.         if (y == IAC) {        /* If this is an IAC */
  1061.             if (flag) {        /* If previous char was IAC */
  1062.             n--;        /* it's quoted, keep one IAC */
  1063.             flag = 0;    /* and turn off the flag. */
  1064.             } else flag = 1;    /* Otherwise set the flag. */
  1065.         } else if (flag) {     /* Something else following IAC */
  1066.             if (y != SE)    /* If not SE, it's a protocol error */
  1067.               flag = 0;
  1068.             break;
  1069.         }
  1070.         }
  1071.         if (!flag) {        /* Make sure we got a valid SB */
  1072.         debug(F100, "TELNET Subnegotian prematurely broken", "",0);
  1073.         return(-1);
  1074.         }
  1075.         if (debses) {        /* Debug to screen. */
  1076.         int i;
  1077.         printf("<SB %s ",telopts[TELOPT_TTYPE]);
  1078.         for (i = 0; i < n-2; i++) printf("%02x",(unsigned int) sb[i]);
  1079.         printf(" IAC SE>");
  1080.         }
  1081.         debug(F101,"TELNET suboption<","",sb[0]);
  1082.         if (sb[0] == 1) {        /* SEND terminal type? */
  1083.         if (tn_sttyp() < 0)    /* Yes, so send it. */
  1084.           return(-1);
  1085.         }
  1086.       default:            /* Others, ignore */
  1087.         return(0);
  1088.     }
  1089. #endif /* TELOPT_TTYPE */
  1090.  
  1091.       default:                /* All others: refuse */
  1092.     switch(c) {
  1093.       case WILL:            /* You will? */
  1094.         if (tn_sopt(DONT,x) < 0)    /* Please don't. */
  1095.           return(-1);        /* (Could this cause a loop?) */
  1096.         break;
  1097.       case DO:            /* You want me to? */
  1098.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1099.           return(-1);
  1100.         break;
  1101.       case DONT:            /* You don't want me to? */
  1102.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1103.           return(-1);        /* (Could this cause a loop?) */
  1104.       case WONT:            /* You won't? */
  1105.         break;            /* I didn't want you to. */
  1106.     }                /* Anything else, treat as user data */
  1107.     return(0);
  1108.     }
  1109. #endif /* TNCODE */
  1110. }
  1111.  
  1112. /* Telnet send terminal type */
  1113. /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
  1114.  
  1115. int
  1116. tn_sttyp() {                /* Send telnet terminal type. */
  1117. #ifndef TNCODE
  1118.     debug(F100,"tn_sttyp no TNCODE","",0);
  1119.     return(0);
  1120. #else
  1121.     char *ttn; int ttl, i;        /* Name & length of terminal type. */
  1122.  
  1123.     if (ttnet != NET_TCPB) return(0);
  1124.     if (ttnproto != NP_TELNET) return(0);
  1125.  
  1126.     ttn = NULL;
  1127.  
  1128.     if (tn_term) {            /* Terminal type override? */
  1129.     debug(F110,"tn_sttyp",tn_term,0);
  1130.     if (*tn_term) ttn = tn_term;
  1131.     } else debug(F100,"tn_sttyp no term override","",0);
  1132.  
  1133.     if (!ttn)                /* If no override, */
  1134.       ttn = getenv("TERM");        /* get it from the "environment". */
  1135.  
  1136.     if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) {
  1137.     ttn = "UNKNOWN";
  1138.     ttl = 7;
  1139.     }
  1140.     sb[0] = IAC;            /* I Am a Command */
  1141.     sb[1] = SB;                /* Subnegotiation */
  1142.     sb[2] = TELOPT_TTYPE;        /* Terminal Type */
  1143.     sb[3] = (CHAR) 0;            /* Is... */
  1144.     for (i = 4; *ttn; ttn++,i++)    /* Copy and uppercase it */
  1145.       sb[i] = (islower(*ttn)) ? toupper(*ttn) : *ttn;
  1146.     ttn = sb;                /* Point back to beginning */
  1147.     sb[i++] = IAC;            /* End of Subnegotiation */
  1148.     sb[i++] = SE;            /* marked by IAC SE */
  1149.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  1150.       return(-1);
  1151. #ifdef DEBUG
  1152.     sb[i-2] = '\0';            /* For debugging */
  1153.     debug(F111,"telnet SB sent ttype",sb+4,ttl);
  1154. #endif /* DEBUG */
  1155.     if (debses)                /* Debug to screen. */
  1156.       printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb+4);
  1157.     return(1);
  1158. #endif /* TNCODE */
  1159. }
  1160. #endif /* TCPSOCKET */
  1161.  
  1162. #ifdef STRATUSX25
  1163.  
  1164. /* PAD X.3, X.28 and X.29 support */
  1165.  
  1166. static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  1167.  
  1168. /* Initialize PAD */
  1169.  
  1170. extern CHAR padparms[MAXPADPARMS+1];
  1171. static long ccittspeeds[] =
  1172. {
  1173.     110, 134, 300, 1200, 600, 75, 150, 1800, 200, 100,
  1174.     50, 1200, 2400, 4800, 9600, 19200, 48000, 56000, 64000
  1175. };
  1176.  
  1177. VOID
  1178. initpad() {
  1179.   int i;
  1180.   long speed;
  1181.   int match;    /* may have to take closest match */
  1182.   long diff;
  1183.  
  1184.   padparms[PAD_BREAK_CHARACTER]        = 3;  /* Break character */
  1185.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  1186.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  1187.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  1188.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  1189.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  1190.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  1191.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  1192.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  1193.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  1194.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  1195.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  1196.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  1197.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  1198.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  1199.   padparms[PAD_EDITING]                = 1;  /* can edit */
  1200.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  1201.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  1202.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  1203.  
  1204.     speed = congspd();
  1205.     match = 0;
  1206.     for (i = 0; i < (sizeof ccittspeeds) / (sizeof ccittspeeds[0]); i++) {
  1207.     diff = speed - ccittspeeds[i];
  1208.     if (diff == 0) {
  1209.         match = i;
  1210.         break;
  1211.     }
  1212.     if (diff > 0 && diff < (speed - ccittspeeds[match]))
  1213.         match = i;
  1214.     }
  1215.  
  1216.     padparms[PAD_LINE_SPEED] = match;  /* line speed (as good as we can get) */
  1217. }
  1218.  
  1219. /* Set PAD parameters */
  1220.  
  1221. VOID
  1222. setpad(s,n) CHAR *s; int n; {
  1223.     int i;
  1224.     CHAR *ps = s;
  1225.     char buff[30];
  1226.  
  1227.     if (n) {
  1228.     for (i = 0; i < n; i++) {
  1229.         if(deblog) {
  1230.         sprintf(buff,"   set pad parm %d=%d",*ps,*(ps+1));
  1231.         debug(F100,buff,"",0);
  1232.         }
  1233.  
  1234.         /* out of range or read only */
  1235.         if (*ps > MAXPADPARMS || *ps == PAD_LINE_SPEED)
  1236.           x29err[i+2] = *ps;
  1237.         else
  1238.           padparms[*ps] = *(ps+1);
  1239.         ps += 2;
  1240.     }
  1241.     }
  1242.     else {
  1243.     debug(F100,"  setpad calling initpad","",0);
  1244.     initpad();
  1245.     }
  1246. }
  1247.  
  1248. /* Read PAD parameters */
  1249.  
  1250. VOID
  1251. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  1252.     int i;
  1253.     CHAR *ps = s;
  1254.     CHAR *pr = r;
  1255.     char buff[30];
  1256.  
  1257.     *pr++ = X29_PARAMETER_INDICATION;
  1258.     if (n == 0) {            /* All supported parameters */
  1259.     for (i = 1; i <= MAXPADPARMS; i++, ps++) {
  1260.         *pr++ = i;
  1261.         *pr++ = padparms[i];
  1262.         if(deblog) {
  1263.         sprintf(buff,"   read pad parm %d=%d",i,padparms[i]);
  1264.         debug(F100,buff,"",0);
  1265.         }
  1266.     }
  1267.     }
  1268.     else {                /* list of specific parameters */
  1269.     for (i = 0; i < n; i++, ps++) {
  1270.         if(deblog) {
  1271.         sprintf(buff,"   read pad parm %d=%d",
  1272.             *ps, (*ps <= MAXPADPARMS) ? padparms[i] : -1);
  1273.         debug(F100,buff,"",0);
  1274.         }
  1275.          if (*ps > MAXPADPARMS) {
  1276.          x29err[i+2] = *ps++;
  1277.          } else {
  1278.          *pr++ = *ps;
  1279.          *pr++ = padparms[*ps++];
  1280.          }
  1281.     }
  1282.     }
  1283. }
  1284.  
  1285. int
  1286. qbitpkt(s,n) CHAR *s; int n; {
  1287.     CHAR *ps = s;
  1288.     int x29cmd = *ps;
  1289.     CHAR *psa = s+1;
  1290.     CHAR x29resp[(MAXPADPARMS*2)+1];
  1291.  
  1292.     debug (F101,"qbitpkt, len","",n);
  1293.     switch (x29cmd) {
  1294.         case X29_SET_PARMS:
  1295.         debug(F100,"X29 SET PAD","",0);
  1296.             setpad (psa,n/2);
  1297.             if ((int)strlen(x29err) > 2) {
  1298.                 ttol (x29err,(int)strlen(x29err));
  1299.                 x29err[2] = '\0';
  1300.             }
  1301.         break;
  1302.         case X29_READ_PARMS:
  1303.         debug(F100,"X29 READ PAD","",0);
  1304.             readpad (psa,n/2,x29resp);
  1305.             setqbit ();
  1306.             ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1));
  1307.             if ((int)strlen(x29err) > 2) {
  1308.                 ttol (x29err,(int)strlen(x29err));
  1309.                 x29err[2] = '\0';
  1310.             }
  1311.             resetqbit();
  1312.             break;
  1313.         case X29_SET_AND_READ_PARMS:
  1314.         debug(F100,"X29 SET AND READ PAD","",0);
  1315.             setpad (psa,n/2);
  1316.             readpad (psa,n/2,x29resp);
  1317.             setqbit();
  1318.             ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1));
  1319.             if ((int)strlen(x29err) > 2) {
  1320.                 ttol (x29err,(int)strlen(x29err));
  1321.                 x29err [2] = '\0';
  1322.             }
  1323.             resetqbit();
  1324.         break;
  1325.         case X29_INVITATION_TO_CLEAR:
  1326.         debug(F100,"X29 INVITATION TO CLEAR","",0);
  1327.             (VOID) x25clear();
  1328.             return (-2) ; /* hang it up */
  1329.         case X29_INDICATION_OF_BREAK:
  1330.         debug(F100,"X29 INDICATION OF BREAK","",0);
  1331.         break;
  1332.     }
  1333.     return (0);
  1334. }
  1335.  
  1336. /* PAD break action processor */
  1337.  
  1338. VOID
  1339. breakact() {
  1340.     extern char x25obuf[];
  1341.     extern int obufl;
  1342.     extern int active;
  1343.     extern unsigned char tosend;
  1344.     static CHAR indbrk[3] = {
  1345.     X29_INDICATION_OF_BREAK,
  1346.     PAD_SUPPRESSION_OF_DATA,
  1347.     1
  1348.     };
  1349.     CHAR intudat, cause, diag;
  1350.  
  1351.     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
  1352.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  1353.         if (ttol(x25obuf,obufl) < 0) {
  1354.             perror ("\r\nCan't send characters");
  1355.             active = 0;
  1356.         } else {
  1357.             /* bzero (x25obuf,sizeof(x25obuf)); */ /**/
  1358.             obufl = 0;
  1359.             tosend = 0;
  1360.         };
  1361.  
  1362.     switch (padparms[PAD_BREAK_ACTION]) {
  1363.  
  1364.        case 0 : break;            /* do nothing */
  1365.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  1366.             intudat = 1;
  1367.                 x25intr (intudat);
  1368.                 break;
  1369.        case 2 : /* send reset packet with cause and diag = 0 */
  1370.         cause = diag = 0;
  1371.                 x25reset (cause,diag);
  1372.                 break;
  1373.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  1374.         intudat = 0;
  1375.                 x25intr (intudat) ;
  1376.                 setqbit ();
  1377.             /* send indication of break without a parameter field */
  1378.                 ttoc(X29_INDICATION_OF_BREAK);
  1379.                 resetqbit ();
  1380.                 break;
  1381.        case 8 : active = 0;        /* leave data transfer */
  1382.                 conol ("\r\n");
  1383.                 break;
  1384.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  1385.         intudat = 0;
  1386.                 x25intr (intudat);
  1387.                 setpad (indbrk+1,1);    /* set pad to discard input */
  1388.                 setqbit ();
  1389.         /* send indication of break with parameter field */
  1390.                 ttol (indbrk,sizeof(indbrk));
  1391.                 resetqbit ();
  1392.                 break;
  1393.      }
  1394. }
  1395.  
  1396. /* X.25 support functions */
  1397.  
  1398. /*
  1399.   Convert a null-terminated string representing an X.121 address
  1400.   to a packed BCD form.
  1401. */
  1402. #ifdef SUNX25 /* not used for Stratus X.25 */
  1403. int
  1404. pkx121(str,bcd) char *str; CHAR *bcd; {
  1405.     int i, j;
  1406.     u_char c;
  1407.  
  1408.     i = j = 0;
  1409.     while (str[i]) {
  1410.         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
  1411.       return (-1);
  1412.         c = str [i] - '0';
  1413.         if ( i & 1 )
  1414.       bcd [j++] |= c;
  1415.         else
  1416.       bcd [j] = c << 4;
  1417.         i++;
  1418.     }
  1419.     return (i);
  1420. }
  1421. #endif /* SUNX25 */
  1422.  
  1423. /* Reads and prints X.25 diagnostic */
  1424.  
  1425. int
  1426. x25diag () {
  1427.     int i;
  1428. #ifdef SUNX25
  1429.     bzero ((char *)&diag,sizeof(diag));
  1430.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  1431.         perror ("Reading X.25 diagnostic");
  1432.         return(-1);
  1433.     }
  1434.     if (diag.datalen > 0) {
  1435.         printf ("X.25 Diagnostic :");
  1436.         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
  1437.         printf ("\r\n");
  1438.     }
  1439. #endif /*  SUNX25 */
  1440.  
  1441.     return(0);
  1442. }
  1443.  
  1444. /* X.25 Out-of-Band Signal Handler */
  1445. #ifdef SUNX25
  1446. VOID
  1447. x25oobh() {
  1448.     int oobtype;
  1449.     u_char oobdata;
  1450.  
  1451.     (VOID) signal(SIGURG,x25oobh);
  1452.     do {
  1453.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  1454.             perror ("Getting signal type");
  1455.             return;
  1456.         }
  1457.         switch (oobtype) {
  1458.       case INT_DATA:
  1459.         if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
  1460.         perror ("Receiving X.25 interrupt data");
  1461.         return;
  1462.         }
  1463.         printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
  1464.         break;
  1465.       case VC_RESET:
  1466.         printf ("\r\nVirtual circuit reset\r\n");
  1467.         x25diag ();
  1468.         break;
  1469.       case N_RESETS:
  1470.         printf ("\r\nReset timeout\r\n");
  1471.         break;
  1472.       case N_CLEARS:
  1473.         printf ("\r\nClear timeout\r\n");
  1474.         break;
  1475.       case MSG_TOO_LONG:
  1476.         printf ("\r\nMessage discarded, too long\r\n");
  1477.         break;
  1478.       default:
  1479.         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  1480.         break;
  1481.     }
  1482.     } while (oobtype);
  1483. }
  1484. #endif /* SUNX25 */
  1485.  
  1486. /* Send a X.25 interrupt packet */
  1487.  
  1488. int
  1489. #ifdef CK_ANSIC
  1490. x25intr(char intr)
  1491. #else
  1492. x25intr(intr) char intr;
  1493. #endif /* CK_ANSIC */
  1494. /* x25intr */ {
  1495.     short vcid = ttyfd;
  1496.     short status;
  1497.     short diag;
  1498.  
  1499.     debug(F101,"X.25 intr, char","",(long) intr);
  1500.     s$vc_send_interrupt (&vcid, &intr, &status);
  1501.     debug(F101,"s$vc_send_interrupt status",0,status);
  1502.  
  1503.     s$vc_status (&vcid, &diag, &status);
  1504.     debug(F101,"s$vc_status status",0,status);
  1505.  
  1506.     return(0);
  1507. }
  1508.  
  1509. /* Reset X.25 virtual circuit */
  1510. int
  1511. #ifdef CK_ANSIC
  1512. x25reset(char cause, char diagn)
  1513. #else
  1514. x25reset(cause, diagn) char cause; char diagn;
  1515. #endif /* CK_ANSIC */
  1516. /* x25reset */ {
  1517.     short vcid = ttyfd;
  1518.     short status;
  1519.     short vc_diag;
  1520.     char  buff[50];
  1521.  
  1522.     sprintf (buff, "cause=%d[IGNORED], diag=%d", cause, diagn);
  1523.     vc_diag = (CHAR) diagn;
  1524.     s$vc_reset (&vcid, &vc_diag, &status);
  1525.     debug(F111,"X.25 reset, status",buff,status);
  1526.     return(0);
  1527. }
  1528.  
  1529. /* Clear X.25 virtual circuit */
  1530. int
  1531. x25clear() {
  1532.     short vcid = ttyfd;
  1533.     short diag = 0;
  1534.     short status;
  1535.  
  1536.     s$vc_clear (&vcid, &diag, &status);
  1537.     debug(F101,"X.25 clear status","",status);
  1538.     return(ttclos(0));            /* Close socket */
  1539. }
  1540.  
  1541. /* X.25 status */
  1542. int
  1543. x25stat() {
  1544.     if (ttyfd < 0) return (-1);
  1545.     return(0);
  1546. }
  1547.  
  1548. /* Set Q_BIT on */
  1549. VOID
  1550. setqbit() {
  1551.     x25qbit = 1;
  1552. }
  1553.  
  1554. /* Set Q_BIT off */
  1555. VOID
  1556. resetqbit() {
  1557.     x25qbit = 0;
  1558. }
  1559.  
  1560. /* Read n characters from X.25 circuit into buf */
  1561. int
  1562. x25xin(n,buf) int n; CHAR *buf; {
  1563.     register int x, c;
  1564.     int qpkt;
  1565.     short vcid = ttyfd;
  1566.     short buffsize = n;
  1567.     short packsize;
  1568.     short mbit;
  1569.     short qbit;
  1570.     char  intchar;
  1571.     short diag;
  1572.     short status;
  1573.  
  1574.     do {
  1575.     if (netnowait)    /* do this in no_wait mode */
  1576.         s$vc_set_no_wait_mode ();
  1577.  
  1578.     s$vc_recv_packet (&vcid, &buffsize, buf, &packsize,
  1579.         &qbit, &mbit, &status);
  1580.         debug(F101,"s$vc_recv_packet status","",status);
  1581.  
  1582.     if (netnowait) /* change it back for everything else */
  1583.         s$vc_set_wait_mode ();
  1584.  
  1585.     x = (status)? (-1) : packsize;
  1586.     switch (status) {
  1587.         case 0:
  1588.         break;
  1589.  
  1590.         case e$vc_interrupt_pending:
  1591.         s$vc_recv_interrupt (&vcid, &intchar, &status);
  1592.         debug(F101,"s$vc_recv_interrupt status","",status);
  1593.         break;
  1594.  
  1595.         case e$vc_reset_pending:
  1596.         s$vc_reset (&vcid, &diag, &status);
  1597.         debug(F101,"s$vc_reset status","",status);
  1598.         break;
  1599.  
  1600.         case e$caller_must_wait:
  1601.         x = 0;
  1602.         break;
  1603.  
  1604.         default:
  1605.         return (-2); /* I dunno, but it's broke */
  1606.     }
  1607.  
  1608.     if (x > 0 && qbit) { /* If Q_BIT packet, process it */
  1609.         if ((c=qbitpkt(buf,x)) < 0)
  1610.         return(c);
  1611.         qpkt = 1;
  1612.     } else qpkt = 0;
  1613.     } while (qpkt);
  1614.  
  1615.     if (x >= 0)
  1616.     buf[x] = '\0';
  1617.     else
  1618.     x = -1;
  1619.  
  1620.     debug(F101,"x25xin x","",x);
  1621.  
  1622.     return(x);
  1623. }
  1624. #endif /* STRATUSX25 */
  1625.  
  1626. #endif /* NETCONN */
  1627.