home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckcnet.c < prev    next >
C/C++ Source or Header  |  1994-10-14  |  66KB  |  2,206 lines

  1. char *cknetv = "Network support, 5A(039) 30 Sep 94";
  2.  
  3. /*  C K C N E T  --  Network support  */
  4.  
  5. /*
  6.   NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
  7.   C-Kermit source files, must be compatible with C preprocessors that support
  8.   only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
  9.   logical operators, or other preprocessor features in any of the portable
  10.   C-Kermit modules.  You can, of course, use these constructions in
  11.   system-specific modules when you know they are supported.
  12. */
  13.  
  14. /*
  15.   Authors:
  16.  
  17.   Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  18.     Columbia University Academic Information Systems, New York City.
  19.   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  20.     (ken@cs.rochester.edu) (no longer at that address).
  21.   Missing pieces for Excelan sockets library from William Bader, Moravian
  22.     College <bader@moravian.edu>.
  23.   TELNET protocol by Frank da Cruz.
  24.   TGV MultiNet code by Frank da Cruz.
  25.   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  26.   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  27.   TCP/IP support adapted to IBM TCP/IP 1.2.1 for OS/2 by Kai Uwe Rommel.
  28.   CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
  29.   SunLink X.25 support by Marcello Frutig, Catholic University,
  30.     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from:
  31.     Stefaan Eeckels, Eurokom, Luxembourg;
  32.     David Lane, Status Computer.
  33.   Other contributions as indicated below.
  34.  
  35.   Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New
  36.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  37.   sold for profit as a software product itself, nor may it be included in or
  38.   distributed with commercial products or otherwise distributed by commercial
  39.   concerns to their clients or customers without written permission of the
  40.   Office of Kermit Development and Distribution, Columbia University.  This
  41.   copyright notice must not be removed, altered, or obscured.
  42. */
  43.  
  44. #include "ckcsym.h"
  45. #include "ckcdeb.h"
  46. #include "ckcker.h"
  47. #ifdef I386IX                /* Has to come before ckcnet.h in */
  48. #include <errno.h>            /* this version, but after in others */
  49. #endif /* I386IX */
  50. #include "ckcnet.h"
  51.  
  52. #ifdef NETCONN
  53. /* Don't need these if there is no network support. */
  54.  
  55. #ifdef CK_SOCKS                /* SOCKS Internet relay package */
  56. #define accept  Raccept
  57. #define bind    Rbind
  58. #define connect Rconnect
  59. #define getsockname Rgetsockname
  60. #define listen  Rlisten
  61. #endif /* CK_SOCKS */
  62.  
  63. #ifdef DEC_TCPIP
  64. #include <time.h>
  65. #endif /* DEC_TCPIP */
  66.  
  67. #ifdef CMU_TCPIP
  68. #include <time.h>
  69. #endif /* CMU_TCPIP */
  70.  
  71. #ifdef WINTCP
  72.  
  73. #include <errno.h>
  74. #include <setjmp.h>
  75. #include <signal.h>
  76. #include <sys/time.h>
  77. /*
  78.   The WIN/TCP code path is the same as that for MultiNet.
  79.   Only the routine names have changed ...
  80. */
  81. #define socket_errno     errno
  82. #define socket_read     netread
  83. #define socket_ioctl    ioctl
  84. #define socket_write     netwrite
  85. #define socket_perror   win$perror
  86. #define socket_close     netclose
  87.  
  88. #else /* Not WINTCP */
  89.  
  90. #ifndef I386IX
  91. #include <errno.h>            /* Already included above */
  92. #endif /* I386IX */
  93.  
  94. #include <signal.h>            /* Everybody needs this */
  95.  
  96. #ifdef ZILOG                /* Zilog has different name for this */
  97. #include <setret.h>
  98. #else /* !ZILOG */
  99. #include <setjmp.h>
  100. #ifdef CK_POSIX_SIG            /* POSIX signal handling */
  101. #endif /* CK_POSIX_SIG */
  102. #endif /* ZILOG */
  103.  
  104. #endif /* WINTCP */
  105.  
  106. #ifdef datageneral            /* Data General AOS/VS */
  107. #include <:usr:include:vs_tcp_errno.h>
  108. #include <:usr:include:sys:vs_tcp_types.h>
  109. #include <:usr:include:sys:socket.h>
  110. #include <:usr:include:netinet:in.h>
  111. #include <:usr:include:netdb.h>
  112. #endif /* datageneral */
  113.  
  114. extern SIGTYP (*saval)();        /* For saving alarm handler */
  115.  
  116. _PROTOTYP( VOID bgchk, (void) );
  117. _PROTOTYP( static VOID tn_debug, (char *) );
  118.  
  119. extern int                /* External variables */
  120.   duplex, debses, seslog, sessft, ttyfd, quiet, msgflg, deblog, what;
  121.  
  122. #ifdef CK_NAWS                /* Negotiate About Window Size */
  123. extern int tt_rows, tt_cols;
  124. _PROTOTYP( int ttgwsiz, (void) );
  125. _PROTOTYP( int tn_snaws, (void) );
  126. #endif /* CK_NAWS */
  127.  
  128. #ifdef OS2                /* For terminal type name string */
  129. #include "ckuusr.h"            /* For  */
  130. extern int tt_type, max_tt;
  131. extern struct tt_info_rec tt_info[];
  132. #endif /* OS2 */
  133.  
  134. #ifndef OS2                /* For timeout longjumps */
  135. #ifndef WINTCP
  136. #ifdef CK_POSIX_SIG
  137. static sigjmp_buf njbuf;
  138. #else
  139. static jmp_buf njbuf;
  140. #endif /* CK_POSIX_SIG */
  141. #endif /* OS2 */
  142. #endif /* WINTCP */
  143.  
  144. #define NAMECPYL 100            /* Local copy of hostname */
  145. static char namecopy[NAMECPYL];
  146.  
  147. char ipaddr[20] = { '\0' };        /* Global copy of IP address */
  148.  
  149. #endif /* NETCONN */
  150.  
  151. int ttnet = NET_NONE;            /* Network type */
  152. int ttnproto = NP_NONE;            /* Network virtual terminal protocol */
  153. int tn_init = 0;            /* Telnet protocol initialized flag */
  154. int tn_duplex = 1;            /* Initial echo status */
  155. char *tn_term = NULL;            /* Terminal type override */
  156. int tn_nlm = TNL_CRLF;            /* Telnet CR -> CR LF mode */
  157.  
  158. #ifdef TNCODE
  159. static char tn_msg[128];        /* For debugging */
  160. static char hexbuf[6];
  161. #endif /* TNCODE */
  162.  
  163. #ifndef NETCONN
  164. /*
  165.   Network support not defined.
  166.   Dummy functions here in case #ifdef's forgotten elsewhere.
  167. */
  168. int                    /* Open network connection */
  169. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  170.     return(-1);
  171. }
  172. int                    /* Close network connection */
  173. netclos() {
  174.     return(-1);
  175. }
  176. int                    /* Check network input buffer */
  177. nettchk() {
  178.     return(-1);
  179. }
  180. int                    /* Flush network input buffer */
  181. netflui() {
  182.     return(-1);
  183. }
  184. int                    /* Send network BREAK */
  185. netbreak() {
  186.     return(-1);
  187. }
  188. int                    /* Input character from network */
  189. netinc(timo) int timo; {
  190.     return(-1);
  191. }
  192. int                    /* Output character to network */
  193. #ifdef CK_ANSIC
  194. nettoc(char c)
  195. #else
  196. nettoc(c) char c;
  197. #endif /* CK_ANSIC */
  198. /* nettoc */ {
  199.     return(-1);
  200. }
  201. int
  202. nettol(s,n) char *s; int n; {
  203.     return(-1);
  204. }
  205.  
  206. #else /* NETCONN is defined (rest of this module...) */
  207.  
  208. #ifdef VMS
  209. /*
  210.   In edit 190, we moved tn_ini() to be called from within netopen().
  211.   But tn_ini() calls ttol(), and ttol() checks to see if it's a net 
  212.   connection, but the flag for that isn't set until after netopen()
  213.   is finished.  Since, in this module, we are always doing network
  214.   output anyway, we just call nettol() directly, instead of going thru
  215.   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
  216.   net connections just like regular connections in ttol(), and OS/2
  217.   has a special routine for this.
  218. */
  219. #define ttol nettol
  220. #endif /* VMS */
  221.  
  222. static int wnawsflg = 0;        /* WILL/WONT NAWS has been sent */
  223.  
  224. #ifndef NOSIGWINCH
  225. #ifdef CK_NAWS                /* Window size business */
  226. #ifdef SIGWINCH
  227. #ifdef UNIX
  228. static int sw_armed = 0;        /* SIGWINCH armed flag */
  229. SIGTYP
  230. winchh(foo) int foo; {
  231.     int x;
  232.     debug(F100,"SIGWINCH caught","",0);
  233.     signal(SIGWINCH,winchh);        /* Re-arm the signal */
  234.     if (ttyfd < 0)
  235.       return;
  236.     x = ttgwsiz();            /* Get new window size */
  237. /*
  238.   This should be OK.  It might seem that sending this from
  239.   interrupt level could interfere with another TELNET IAC string
  240.   that was in the process of being sent.  But we always send
  241.   TELNET strings with a single write(), which should prevent mixups.
  242. */
  243.     if (x > 0 && tt_rows > 0 && tt_cols > 0)
  244.       tn_snaws();
  245.     return;
  246. }
  247. #endif /* UNIX */
  248. #endif /* SIGWINCH */
  249. #endif /* CK_NAWS */
  250. #endif /* NOSIGWINCH */
  251.  
  252. /*
  253.   TCPIPLIB means use separate socket calls, while on UNIX the
  254.   normal file system calls are used for TCP/IP sockets too,
  255.   i.e. "DEC_TCPIP or MULTINET or WINTCP or OS2" (defined in ckcnet.h).
  256. */
  257. #ifdef TCPIPLIB
  258.  
  259. /* For buffered network reads... */
  260. /*
  261.   If the buffering code is written right, it shouldn't matter
  262.   how long this buffer is.
  263. */
  264. #define TTIBUFL 8192            /* Let's use 8K. */
  265.  
  266. CHAR     ttibuf[TTIBUFL+1];
  267. int     ttibp = 0, ttibn = 0;
  268. /*
  269.   Read bytes from network into internal buffer ttibuf[].
  270.   To be called when input buffer is empty, i.e. when ttibn == 0.
  271.  
  272.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  273.   internal buffer first, and call this routine for a refill if necessary.
  274.  
  275.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  276.   returns number of bytes read, and sets global ttibn to that number and
  277.   ttibp (the buffer pointer) to zero.
  278. */
  279. int
  280. ttbufr() {                /* TT Buffer Read */
  281.     int count;
  282.  
  283.     if (ttnet != NET_TCPB) {        /* First make sure current net is */
  284.     return(-1);            /* TCP/IP; if not, do nothing. */
  285.     } else {
  286.     if (ttibn > 0)            /* Out internal buffer is not empty, */
  287.       return(ttibn);        /* so keep using it. */
  288. #ifdef WINTCP
  289.     count = 512;            /* This works for WIN/TCP */
  290. #else
  291. #ifdef DEC_TCPIP
  292.     count = 512;            /* UCX */
  293. #else                    /* Multinet, etc. */
  294.     count = nettchk();        /* Check network input buffer, */
  295.     if (ttibn > 0) return(ttibn);    /* which can put a char there! */
  296.     if (count < 0)            /* Read error */
  297.       return(-1);
  298.     else if (count > TTIBUFL)    /* Too many to read */
  299.       count = TTIBUFL;
  300.     else if (count == 0)        /* None, so force blocking read */
  301.       count = 1;
  302. #endif /* DEC_TCPIP */
  303. #endif /* WINTCP */
  304.     debug(F101,"ttbufr count 1","",count);
  305.  
  306. #ifdef COMMENT
  307. /*
  308.  This is for nonblocking reads, which we don't do any more.  This code didn't
  309.  work anyway, in the sense that a broken connection was never sensed.
  310. */
  311.     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
  312.         if (count == -1 && socket_errno == EWOULDBLOCK) {
  313.         debug(F100,"ttbufr finds nothing","",0);
  314.         return(0);
  315.         } else {
  316.             debug(F101,"ttbufr socket_read error","",socket_errno);
  317.         return(-1);
  318.         }
  319.     } else if (count == 0) {
  320.         debug(F100,"ttbufr socket eof","",0);        
  321.         return(-1);
  322.     }
  323. #else
  324. /* This is for blocking reads */
  325.     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
  326.         debug(F101,"ttbufr socket_read","",count);
  327.         debug(F101,"ttbufr socket_errno","",socket_errno);
  328.         netclos();            /* *** *** */
  329.         return(-1);
  330.     }
  331. #endif /* COMMENT */
  332.     ttibp = 0;            /* Reset buffer pointer. */
  333.     ttibn = count;
  334. #ifdef DEBUG
  335.     debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
  336.     if (count > 0) ttibuf[count] = '\0';
  337.     debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
  338. #endif /* DEBUG */
  339.     return(ttibn);            /* Return buffer count. */
  340.     }
  341. }
  342. #endif /* TCPIPLIB */
  343.  
  344. /*
  345.   C-Kermit network open/close functions for BSD-sockets.
  346.   Much of this code shared by SunLink X.25, which also uses the socket library.
  347. */
  348.  
  349. /*  N E T O P E N  --  Open a network connection.  */
  350.  
  351. /*  Returns 0 on success, -1 on failure.  */
  352.  
  353. #define    TELNET_PORT    23       /* Should do lookup, but it won't change */
  354.  
  355. /* This symbol is not known to, e.g., Ultrix 2.0 */
  356. #ifndef TELOPT_TTYPE
  357. #define TELOPT_TTYPE 24
  358. #endif /* TELOPT_TTYPE */
  359.  
  360. /*  N E T O P N  --  Open a network connection.  */
  361. /*
  362.   Call with:
  363.     name of host (or host:service),
  364.     lcl - local-mode flag to be set if this function succeeds,
  365.     network type - value defined in ckunet.h.
  366. */
  367.  
  368. #ifdef TCPSOCKET
  369. #ifdef EXCELAN
  370. /*
  371.   Most other BSD sockets implementations define these in header files
  372.   and libraries.
  373. */
  374. struct servent {
  375.     unsigned short s_port;
  376. };
  377.  
  378. struct hostent {
  379.     short h_addrtype;
  380.     struct in_addr h_addr;
  381.     int h_length;
  382. };
  383.  
  384. struct servent *
  385. getservbyname(service, connection) char *service,*connection; {
  386.     static struct servent servrec;
  387.     int port;
  388.  
  389.     port = 0;
  390.     if (strcmp(service, "telnet") == 0) port = 23;
  391.     else if (strcmp(service, "smtp") == 0) port = 25;
  392.     else port = atoi(service);
  393.  
  394.     debug(F101,"getservbyname return port ","",port);
  395.  
  396.     if (port > 0) {
  397.         servrec.s_port = htons(port);
  398.         return( &servrec );
  399.     }
  400.     return( (struct servent *) NULL );
  401. }
  402.  
  403. struct hostent *
  404. gethostbyname(hostname) char *hostname; {
  405.     return( (struct hostent *) NULL );
  406. }
  407.  
  408. unsigned long
  409. inet_addr(name) char *name; {
  410.     unsigned long addr;
  411.  
  412.     addr = rhost(&name);
  413.     debug(F111,"inet_addr ",name,(int)addr);
  414.     return(addr);
  415. }
  416.  
  417. char *
  418. inet_ntoa(in) struct in_addr in; {
  419.     static char name[80];
  420.     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
  421.     return(name);
  422. }
  423. #endif /* EXCELAN */
  424. #endif /* TCPSOCKET */
  425.  
  426. #ifdef SUNX25
  427. #ifndef X25_WR_FACILITY
  428. /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
  429. void
  430. bzero(s,n) char *s; int n; {
  431.     memset(s,0,n);
  432. }
  433. #endif /* X25_WR_FACILITY */
  434. #endif /* SUNX25 */
  435.  
  436. /*  N E T O P E N  --  Open a network connection  */
  437. /*
  438.   Calling conventions same as ttopen(), except third argument is network
  439.   type rather than modem type.  Designed to be called from within ttopen.
  440. */
  441. int
  442. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  443.     char *p;
  444.     int i, x;
  445. #ifdef TCPSOCKET
  446. #ifdef SO_OOBINLINE
  447.     int on = 1;
  448. #endif /* SO_OOBINLINE */
  449.     struct servent *service, servrec;
  450.     struct hostent *host;
  451.     struct sockaddr_in saddr;
  452. #ifdef EXCELAN
  453.     struct sockaddr_in send_socket;
  454. #endif /* EXCELAN */
  455. #endif /* TCPSOCKET */
  456.  
  457. #ifdef SUNX25                /* Code for SunLink X.25 support */
  458. #define X29PID 1            /* X.29 Protocol ID */
  459. _PROTOTYP( SIGTYP x25oobh, (int) );
  460.     CONN_DB x25host;
  461. #ifndef X25_WR_FACILITY
  462.     FACILITY x25facil;
  463. #else
  464.     FACILITY_DB x25facil;
  465. #endif /* X25_WR_FACILITY */
  466.     static int needh = 1;
  467.     PID_T pid;
  468.     extern int linkid, lcn, x25ver;
  469.     extern int revcall, closgr, cudata;
  470.     extern char udata[MAXCUDATA];
  471. #endif /* SUNX25 */
  472.  
  473.     debug(F101,"netopen nett","",nett);
  474.     *ipaddr = '\0';            /* Initialize IP address string */
  475.  
  476. #ifdef SUNX25
  477.     if (nett == NET_SX25) {        /* If network type is X.25 */
  478.         netclos();            /* Close any previous net connection */
  479.         ttnproto = NP_NONE;        /* No protocol selected yet */
  480.  
  481.         /* Set up host structure */
  482.         bzero ((char *)&x25host,sizeof(x25host));
  483.         if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) {
  484.             fprintf (stderr,"Invalid X.121 host address %s\n",name);
  485.             errno = 0;
  486.             return (-1);
  487.         }
  488.         x25host.datalen = X29PIDLEN;
  489.         x25host.data[0] = X29PID;
  490.  
  491.     /* Set call user data if specified */
  492.         if (cudata) {
  493.             strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata));
  494.             x25host.datalen += (int)strlen(udata);
  495.         }
  496.  
  497.         /* Open SunLink X.25 socket */
  498.         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
  499.         debug(F101,"netopen socket error","",errno);
  500.             perror ("X.25 socket error");
  501.             return (-1);
  502.         }
  503.  
  504.         /* Setting X.25 out-of-band data handler */
  505.         pid = getpid();
  506.         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
  507.             perror("X.25 set process group id error");
  508.             return(-1);
  509.         }
  510.         (VOID) signal(SIGURG,x25oobh);
  511.  
  512.         /* Set reverse charge call and closed user group if requested */
  513.         bzero ((char *)&x25facil,sizeof(x25facil));
  514.  
  515. #ifndef X25_WR_FACILITY
  516. /*  New SunLink (7.0 or 8.0, not sure which)... */
  517.     x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
  518.     x25facil.f_reverse_charge = revcall ? 1 : 0;
  519.         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  520.             perror ("Setting X.25 reverse charge");
  521.             return (-1);
  522.         }
  523.     if (closgr > -1) {        /* Closed User Group (Outgoing) */
  524.         bzero ((char *)&x25facil,sizeof(x25facil));
  525.         x25facil.type = T_CUG;
  526.         x25facil.f_cug_req = CUG_REQ_ACS;
  527.         x25facil.f_cug_index = closgr;
  528.         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  529.         perror ("Setting X.25 closed user group");
  530.         return (-1);
  531.         }
  532.     }
  533. #else
  534. /*  Old SunLink 6.0 (or 7.0?)... */
  535.         if (revcall) x25facil.reverse_charge = revcall;
  536.         if (closgr > -1) {
  537.             x25facil.cug_req = 1;
  538.             x25facil.cug_index = closgr;
  539.         }
  540.         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
  541.             perror ("Setting X.25 facilities");
  542.             return (-1);
  543.         }
  544. #endif /* X25_WR_FACILITY */
  545.  
  546.         /*  Need X.25 header with bits Q and M */
  547.         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
  548.             perror ("Setting X.25 header");
  549.             return (-1);
  550.         }
  551.  
  552.         /* Connects to remote host via SunLink X.25 */
  553.         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
  554.             debug(F101,"netopen connect errno","",errno);
  555.             i = errno;
  556.         if (errno) {
  557.                 perror("netopen x25 connect");
  558.                 x25diag();
  559.             }
  560.             (VOID) close (ttyfd);
  561.             ttyfd = -1;
  562.             errno = i;
  563.             return (-1);
  564.         }
  565.  
  566.         /* Get X.25 link identification used for the connection */
  567.         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
  568.             perror ("Getting X.25 link id");
  569.             return (-1);
  570.         }
  571.  
  572.         /* Get X.25 logical channel number used for the connection */
  573.         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
  574.             perror ("Getting X.25 lcn");
  575.             return (-1);
  576.         }
  577.  
  578.         /* Get SunLink X.25 version */
  579.         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
  580.             perror ("Getting SunLink X.25 version");
  581.             return (-1);
  582.         }
  583.         ttnet = nett;                   /* Sunlink X.25 network */
  584.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  585.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  586.         return(0);
  587.     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
  588. #endif /* SUNX25 */
  589. /*
  590.   Add support for other networks here.
  591. */
  592.       if (nett != NET_TCPB) return(-1);    /* BSD socket support */
  593.  
  594. #ifdef TCPSOCKET
  595.     netclos();                /* Close any previous connection. */
  596.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  597.     ttnproto = NP_NONE;            /* No protocol selected yet. */
  598.     debug(F110,"netopen namecopy",namecopy,0);
  599.  
  600.     p = namecopy;            /* Was a service requested? */
  601.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  602.     if (*p == ':') {            /* Have a colon */
  603.     *p++ = '\0';            /* Get service name or number */
  604.     } else {                /* Otherwise use telnet */
  605.     p = "telnet";
  606.     }
  607.     debug(F110,"netopen service requested",p,0);
  608.     if (isdigit(*p)) {            /* Use socket number without lookup */
  609.     service = &servrec;
  610.     service->s_port = htons((unsigned short)atoi(p));
  611.     } else {                /* Otherwise lookup the service name */
  612.     service = getservbyname(p, "tcp");
  613.     }
  614.     if (!service) {
  615.     fprintf(stderr, "Cannot find port for service %s\n", p);
  616. #ifdef MULTINET
  617.     debug(F101,"netopen can't get service","",socket_errno);
  618. #else
  619.     debug(F101,"netopen can't get service","",errno);
  620. #endif /* MULTINET */
  621.     errno = 0;            /* rather than mislead */
  622.     return(-1);
  623.     }
  624.  
  625.     /* Set up socket structure and get host address */
  626.  
  627.     bzero((char *)&saddr, sizeof(saddr));
  628.     debug(F100,"netopen bzero ok","",0);
  629.     if ((host = gethostbyname(namecopy)) != NULL) {
  630.     debug(F100,"netopen gethostbyname != NULL","",0);
  631.     saddr.sin_family = host->h_addrtype;
  632.     bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
  633.     debug(F111,"BCOPY","host->h_addr",host->h_addr);
  634.     debug(F111,"BCOPY"," (caddr_t)&saddr.sin_addr",
  635.           (caddr_t)&saddr.sin_addr);
  636.     debug(F111,"BCOPY","host->h_length",host->h_length);
  637.     } else {
  638. #ifdef INADDRX
  639. /* inet_addr() is of type struct in_addr */
  640.     struct in_addr ina;
  641.     unsigned long uu;
  642. #ifdef datageneral
  643.     extern struct in_addr inet_addr();
  644. #endif /* datageneral */
  645.     debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
  646.     ina = inet_addr(namecopy);
  647.     uu = *(unsigned long *)&ina;
  648. #else /* Not INADDRX */
  649. /* inet_addr() is unsigned long */
  650.     unsigned long uu;
  651.     debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
  652.     uu = inet_addr(namecopy);
  653. #endif /* INADDRX */
  654.     debug(F101,"netopen uu","",uu);
  655.     if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
  656.       saddr.sin_family = AF_INET;
  657.     else {
  658.         fprintf(stderr, "Can't get address for %s\n", namecopy);
  659. #ifdef MULTINET
  660.         debug(F101,"netopen can't get address","",socket_errno);
  661. #else
  662.         debug(F101,"netopen can't get address","",errno);
  663. #endif /* MULTINET */
  664.         errno = 0;        /* Rather than mislead */
  665.         return(-1);
  666.     }
  667.     }
  668.  
  669.     /* Get a file descriptor for the connection. */
  670.  
  671.     saddr.sin_port = service->s_port;
  672.     sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  673.     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
  674.  
  675. #ifdef EXCELAN
  676.     send_socket.sin_family = AF_INET;
  677.     send_socket.sin_addr.s_addr = 0;
  678.     send_socket.sin_port = 0;
  679.     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
  680.             &send_socket, SO_REUSEADDR)) < 0)
  681. #else
  682.       if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  683. #endif /* EXCELAN */
  684.     {
  685. #ifdef EXCELAN
  686.         experror("TCP socket error");
  687. #else
  688. #ifdef MULTINET
  689.         socket_perror("TCP socket error");
  690.         debug(F101,"netopen socket error","",socket_errno);
  691. #else
  692.         perror("TCP socket error");
  693.         debug(F101,"netopen socket error","",errno);
  694. #endif /* MULTINET */
  695. #endif /* EXCELAN */
  696.         return (-1);
  697.     }
  698.     errno = 0;
  699.  
  700.     /* Now connect to the socket on the other end. */
  701.  
  702. #ifdef EXCELAN
  703.     if (connect(ttyfd, &saddr) < 0)
  704. #else
  705.       if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  706. #endif /* EXCELAN */
  707.     {
  708.         i = errno;            /* save error code */
  709.         close(ttyfd);
  710.         ttyfd = -1;
  711.         errno = i;            /* and report this error */
  712. #ifdef EXCELAN
  713.         if (errno) experror("netopen connect");
  714. #else
  715. #ifdef MULTINET
  716.         debug(F101,"netopen connect error","",socket_errno);
  717.         if (errno) socket_perror("netopen connect");
  718. #else
  719.         debug(F101,"netopen connect errno","",errno);
  720. #ifdef    WINTCP
  721.         perror("netopen connect");
  722. #endif    /* WINTCP */
  723. #ifdef DEC_TCPIP
  724.         perror("netopen connect");
  725. #endif /* DEC_TCPIP */
  726. #ifdef CMU_TCPIP
  727.         perror("netopen connect");
  728. #endif /* CMU_TCPIP */
  729. #endif /* MULTINET */
  730. #endif /* EXCELAN */
  731.         return(-1);
  732.     }
  733. #ifdef SO_OOBINLINE
  734. /*
  735.   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  736.   It means "leave out of band data inline".  The normal value is 0x0100,
  737.   but don't try this on systems where the symbol is undefined.
  738. */
  739. #ifdef datageneral
  740.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  741. #else
  742. #ifdef BSD43
  743.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  744. #else
  745. #ifdef OSF1
  746.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  747. #else
  748. #ifdef POSIX
  749.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  750. #else
  751. #ifdef SOLARIS
  752. /*
  753.   Maybe this applies to all SVR4 versions, but the other (else) way has been
  754.   compiling and working fine on all the others, so best not to change it.
  755. */
  756.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  757. #else
  758. #ifdef OS2
  759.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  760. #else
  761. #ifdef VMS /* or, at least, VMS with gcc */
  762.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  763. #else
  764.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  765. #endif /* VMS */
  766. #endif /* OS2 */
  767. #endif /* SOLARIS */
  768. #endif /* POSIX */
  769. #endif /* BSD43 */
  770. #endif /* OSF1 */
  771. #endif /* datageneral */
  772. #endif /* SO_OOBINLINE */
  773.  
  774. #ifdef CK_LINGER
  775. /*
  776.   The following, from William Bader, turns off the socket linger parameter,
  777.   which makes a close() block until all data is sent.  "I don't think that
  778.   disabling linger can ever cause kermit to lose data, but you telnet to a
  779.   flaky server (or to our modem server when the modem is in use), disabling
  780.   linger prevents kermit from hanging on the close if you try to exit."
  781.   Define CK_LINGER if you want to use this code.
  782. */
  783. #ifdef SOL_SOCKET
  784. #ifdef SO_LINGER
  785.     {
  786.       struct linger linger_opt;
  787.       x = sizeof(linger_opt);
  788.       if (getsockopt(ttyfd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, &x)) {
  789.       perror("could not get SO_LINGER");
  790.       } else if (x != sizeof(linger_opt)) {
  791.       debug(F101,"netopen error: SO_LINGER len","",x);
  792.       debug(F101,"netopen SO_LINGER expected len","",sizeof(linger_opt));
  793.       } else if (linger_opt.l_onoff) {
  794.       linger_opt.l_onoff = 0;
  795.       if (setsockopt(ttyfd,
  796.              SOL_SOCKET,
  797.              SO_LINGER,
  798.              (char *)&linger_opt,
  799.              sizeof(linger_opt))) {
  800.           perror("error clearing SO_LINGER");
  801.       } else {
  802.           debug(F101,"netopen new SO_LINGER","",linger_opt.l_onoff);
  803.       }
  804.       } else {
  805.       debug(F101,"netopen SO_LINGER unchanged","",linger_opt.l_onoff);
  806.       }
  807.   }
  808. #else
  809.     debug(F100,"SO_LINGER not defined","",0);
  810. #endif /* SO_LINGER */
  811. #endif /* SOL_SOCKET */
  812. #endif /* CK_LINGER */
  813.  
  814. /*
  815.   The following, from William Bader, allows changing of socket buffer sizes,
  816.   in case that might affect performance.
  817. */
  818. #ifdef CK_SOCKBUF
  819. #ifdef SOL_SOCKET
  820. #ifdef SO_SNDBUF
  821.     x = sizeof(i);
  822.     if (getsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
  823.     perror("could not get SO_SNDBUF");
  824.     } else if (x != sizeof(i)) {
  825.     debug(F101,"netopen error: SO_SNDBUF len","",x);
  826.     debug(F101,"netopen SO_SNDBUF expected len","",sizeof(i));
  827.     } else if (i < 32768) {
  828.     x = 32768;
  829.     if (setsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&x, sizeof(x))) {
  830.         perror("error setting SO_SNDBUF");
  831.     } else {
  832.         debug(F101,"netopen old SO_SNDBUF","",i);
  833.         debug(F101,"netopen new SO_SNDBUF","",x);
  834.     }
  835.     } else {
  836.     debug(F101,"netopen SO_SNDBUF unchanged","",i);
  837.     }
  838. #else
  839.     debug(F100,"SO_SNDBUF not defined","",0);
  840. #endif /* SO_SNDBUF */
  841. #ifdef SO_RCVBUF
  842.     x = sizeof(i);
  843.     if (getsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
  844.     perror("could not get SO_RCVBUF");
  845.     } else if (x != sizeof(i)) {
  846.     debug(F101,"netopen error: SO_RCVBUF len","",x);
  847.     debug(F101,"netopen SO_RCVBUF expected len","",sizeof(i));
  848.     } else if (i < 32768) {
  849.     x = 32768;
  850.     if (setsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&x, sizeof(x))) {
  851.         perror("error setting SO_RCVBUF");
  852.     } else {
  853.         debug(F101,"netopen old SO_RCVBUF","",i);
  854.         debug(F101,"netopen new SO_RCVBUF","",x);
  855.     }
  856.     } else {
  857.     debug(F101,"netopen SO_RCVBUF unchanged","",i);
  858.     }
  859. #else
  860.     debug(F100,"SO_RCVBUF not defined","",0);
  861. #endif /* SO_RCVBUF */
  862. #endif /* SOL_SOCKET */
  863. #endif /* CK_SOCKBUF */
  864.  
  865.     /* See if the service is TELNET. */
  866.     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
  867.       ttnproto = NP_TELNET;        /* Yes, set global flag. */
  868.     debug(F101,"netopen service","",x);
  869.     ttnet = nett;            /* TCP/IP (sockets) network */
  870.     tn_ini();                /* Start TELNET negotiations. */
  871.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  872. #endif /* TCPSOCKET */
  873.     return(0);                /* Done. */
  874. }
  875.  
  876. /*  N E T C L O S  --  Close current network connection.  */
  877.  
  878. int
  879. netclos() {
  880.     int x = 0;
  881.     debug(F101,"netclos","",ttyfd);
  882.     if (ttyfd < 0)            /* Was open? */
  883.       return(0);            /* Wasn't. */
  884.     if (ttyfd > -1)            /* Was. */
  885. #ifdef TCPIPLIB
  886.       x = socket_close(ttyfd);        /* Close it. */
  887. #else
  888.       x = close(ttyfd);
  889. #endif /* TCPIPLIB */
  890.     ttyfd = -1;                /* Mark it as closed. */
  891.     debug(F100,"netclose setting tn_init = 0","",0);
  892.     tn_init = 0;            /* Remember about telnet protocol... */
  893.     *ipaddr = '\0';            /* Zero the IP address string */
  894.     return(x);
  895. }
  896.  
  897. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  898. /*
  899.   Returns number of bytes waiting, or -1 if connection has been dropped.
  900. */
  901. int                    /* Check how many bytes are ready */
  902. nettchk() {                /* for reading from network */
  903. #ifdef TCPIPLIB
  904.     unsigned long count = 0;
  905.     int x;
  906.     long y;
  907.     char c;
  908.  
  909.     debug(F101,"nettchk entry ttibn","",ttibn);
  910.     debug(F101,"nettchk entry ttibp","",ttibp);
  911.     socket_errno = 0;
  912. /*
  913.   Note: this socket_ioctl() call does NOT return an error if the
  914.   connection has been broken.  (At least not in MultiNet.)
  915. */
  916. #ifdef COMMENT
  917. /*  Another trick that can be tried here is something like this: */
  918.  
  919.     if (ttnet == NET_TCPB) {
  920.     char dummy;
  921.     x = read(ttyfd,&dummy,0);    /* Try to read nothing */
  922.     if (x < 0) {            /* "Connection reset by peer" */
  923.         perror("TCP/IP");        /* or somesuch... */
  924.         ttclos();            /* Close our end too. */
  925.         return(-1);
  926.     }
  927.     }
  928. #endif /* COMMENT */
  929.  
  930.     if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) {
  931.     debug(F101,"nettchk socket_ioctl error","",socket_errno);
  932.     if (ttibn < 1) {
  933.         netclos();            /* *** *** */
  934.         return(-1);
  935.     } else return(ttibn);
  936.     }
  937.     debug(F101,"nettchk count","",count);
  938.  
  939. #ifndef DEC_TCPIP
  940. #ifndef CMU_TCPIP
  941. /*
  942.   Let's see if we can skip this for UCX, since it seems to cause trouble.
  943.   Ditto for CMU-OpenVMS/IP.
  944. */
  945.     if (count == 0) {
  946. /*
  947.   Here we need to tell the difference between a 0 count on an active
  948.   connection, and a 0 count because the remote end of the socket broke the
  949.   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
  950.   the status of the connection, so we have to do a read.  -1 means there was
  951.   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
  952.   down.  But if, by chance, we actually get a character, we have to put it
  953.   where it won't be lost.
  954. */
  955.     y = 1;                /* Turn on nonblocking reads */
  956.     debug(F101,"nettchk before FIONBIO","",x);
  957.     x = socket_ioctl(ttyfd,FIONBIO,&y);
  958.     debug(F101,"nettchk FIONBIO","",x);
  959.     x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
  960.     debug(F101,"nettchk socket_read","",x);
  961.     y = 0;                /* Turn them back off */
  962.     socket_ioctl(ttyfd,FIONBIO,&y);
  963.     if (x == 0) {
  964.         netclos();            /* *** *** */
  965.         return(-1);            /* Connection is broken. */
  966.     }
  967.     if (x == 1) {            /* Oops, actually got a byte? */
  968.         debug(F101,"nettchk socket_read char","",c);
  969.         debug(F101,"nettchk ttibp","",ttibp);
  970.         debug(F101,"nettchk ttibn","",ttibn);
  971. /*
  972.   So put the byte we got into the buffer at the current position.
  973.   Increment the buffer count, but DON'T increment the buffer pointer.
  974. */
  975.         ttibuf[ttibp+ttibn] = c;
  976.         ttibn++;
  977. #ifdef DEBUG
  978.         ttibuf[ttibp+ttibn] = '\0';
  979.         debug(F111,"nettchk ttibn",ttibuf,ttibn);
  980. #endif /* DEBUG */
  981.     }
  982.     }
  983. #endif /* !CMU_TCPIP */
  984. #endif /* !DEC_TCPIP */
  985.     debug(F101,"nettchk returns","",count+ttibn);
  986.     return(count + ttibn);
  987.  
  988. #else /* Not TCPIPLIB */
  989. /*
  990.   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
  991.   seem to work OK.
  992. */
  993.     return(0);
  994. #endif /* TCPIPLIB */
  995. /*
  996.   But what about X.25?
  997. */
  998. }
  999.  
  1000. #ifndef OS2
  1001. #ifndef WINTCP
  1002. VOID
  1003. nettout(i) int i; {            /* Catch the alarm interrupts */
  1004.     debug(F100,"nettout caught timeout","",0);
  1005.     ttimoff();
  1006. #ifdef CK_POSIX_SIG
  1007.     siglongjmp(njbuf, -1);
  1008. #else
  1009.     longjmp(njbuf, -1);
  1010. #endif /* CK_POSIX_SIG */
  1011. }
  1012. #endif /* !WINTCP */
  1013. #endif /* !OS2 */
  1014.  
  1015. /*  N E T I N C --  Input character from network */
  1016.  
  1017. int            
  1018. netinc(timo) int timo; {
  1019. #ifdef TCPIPLIB
  1020.     int x; unsigned char c;        /* The locals. */
  1021.  
  1022.     if (ttibn > 0) {            /* Something in internal buffer? */
  1023.     debug(F100,"netinc char in buf","",0); /* Yes. */
  1024.     x = 0;                /* Success. */
  1025.     } else {                /* Else must read from network. */
  1026.     x = -1;                /* Assume failure. */
  1027. #ifdef DEBUG
  1028.     debug(F101,"netinc goes to net, timo","",timo);
  1029.     ttibuf[ttibp+1] = '\0';
  1030.     debug(F111,"netinc ttibuf",ttibuf,ttibp);
  1031. #endif /* DEBUG */
  1032.     if (timo == 0) {        /* Untimed case. */
  1033.         while (1) {            /* Wait forever if necessary. */
  1034.         if (ttbufr() < 0)    /* Refill buffer. */
  1035.           break;        /* Error, fail. */
  1036.         if (ttibn > 0) {    /* Success. */
  1037.             x = 0;
  1038.             break;
  1039.         }
  1040.         }
  1041.     } else {            /* Timed case... */
  1042. /*
  1043.   select() is used in preference to alarm()/signal(), but different systems
  1044.   use different forms of select()...
  1045. */
  1046. #ifdef WINTCP                /* VMS with Wollongong WIN/TCP */
  1047. #define BSDSELECT
  1048. #else
  1049. #ifdef CMU_TCPIP            /* LIBCMU can do select */
  1050. #define BSDSELECT
  1051. #else
  1052. #ifdef DEC_TCPIP
  1053. #define BSDSELECT
  1054. #else
  1055. #ifdef OS2                /* OS/2 with TCP/IP */
  1056. #define IBMSELECT
  1057. #endif /* OS2 */
  1058. #endif /* DEC_TCPIP */
  1059. #endif /* CMU_TCPIP */
  1060. #endif /* WINTCP */
  1061.  
  1062. /*
  1063.   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
  1064.   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
  1065.   NOTE: If any of these can be converted to select(), they should be for two
  1066.   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
  1067.   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
  1068.   to fail with EBUSY.  This happened in the UCX case before it was converted
  1069.   to use select().
  1070. */
  1071.  
  1072. #ifdef BSDSELECT
  1073.             fd_set rfds;
  1074.             struct timeval tv;
  1075.             FD_ZERO(&rfds);
  1076.             FD_SET(ttyfd, &rfds);
  1077.             tv.tv_sec  = tv.tv_usec = 0L;
  1078.             if (timo < 0)
  1079.               tv.tv_usec = (long) -timo * 10000L;
  1080.             else
  1081.               tv.tv_sec = timo;
  1082.         debug(F101,"netinc BSDSELECT","",timo);
  1083.             if ( select(FD_SETSIZE, &rfds, NULL, NULL, &tv) &&
  1084.                  FD_ISSET(ttyfd, &rfds) )
  1085. #else /* !BSDSELECT */
  1086. #ifdef IBMSELECT
  1087. /* Was used by OS/2, currently not used, but might come in handy some day... */
  1088. /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
  1089. /* and timeval stuff since this is the only place where it is used. */
  1090.           int socket = ttyfd;
  1091.         debug(F101,"netinc IBMSELECT","",timo);
  1092.             if ( select(&socket, 1, 0, 0,
  1093.                         timo < 0 ? -timo * 10 : timo * 1000L) == 1)
  1094. #else /* !IBMSELECT */
  1095. /*
  1096.   If we can't use select(), then we use the regular alarm()/signal()
  1097.   timeout mechanism.
  1098. */
  1099.         debug(F101,"netinc alarm","",timo);
  1100.         saval = signal(SIGALRM,nettout); /* Enable timer interrupt */
  1101.         alarm(timo);        /* for requested interval. */
  1102.         if (
  1103. #ifdef CK_POSIX_SIG
  1104.         sigsetjmp(njbuf,1)
  1105. #else
  1106.         setjmp(njbuf)
  1107. #endif /* CK_POSIX_SIG */
  1108.         ) {            /* Timer went off? */
  1109.         x = -1;            /* Yes, fail. */
  1110.         } else {
  1111. #endif /* IBMSELECT */
  1112. #endif /* BSDSELECT */
  1113.         while (1) {
  1114.             if (ttbufr() < 0)    /* Keep trying to refill it. */
  1115.               break;        /* Till we get an error. */
  1116.             if (ttibn > 0) {    /* Or we get a character. */
  1117.             x = 0;
  1118.             break;
  1119.             }
  1120.         }
  1121. #ifndef BSDSELECT
  1122. #ifndef IBMSELECT
  1123.         }
  1124.         ttimoff();            /* Timer off. */
  1125. #endif /* IBMSELECT */
  1126. #endif /* BSDSELECT */
  1127.     }
  1128.     }
  1129.     if (x < 0) {            /* Return -1 if we failed. */
  1130.     debug(F100,"netinc timed out","",0);
  1131.     return(-1);
  1132.     } else {                /* Otherwise */
  1133.     ttibn--;            /* Return what we got. */
  1134.     c = ttibuf[ttibp++];
  1135.     if (deblog) {
  1136.         debug(F101,"netinc returning","",c);
  1137.         if (c == 0) {
  1138.         debug(F101,"netinc 0 ttibn","",ttibn);
  1139.         debug(F101,"netinc 0 ttibp","",ttibp);
  1140.         }
  1141.     }
  1142.     return((c & 0xff));
  1143.     }
  1144. #else /* Not MULTINET or WINTCP */
  1145.     return(-1);
  1146. #endif /* TCPIPLIB */
  1147. }
  1148.  
  1149. /*  N E T T O L  --  Output a string of bytes to the network  */
  1150. /*
  1151.   Call with s = pointer to string, n = length.
  1152.   Returns number of bytes actually written on success, or
  1153.   -1 on i/o error, -2 if called improperly.
  1154. */
  1155. int
  1156. nettol(s,n) char *s; int n; {
  1157. #ifdef TCPIPLIB
  1158.     int count;
  1159.     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
  1160.     if (ttnet == NET_TCPB) {
  1161.     if ((count = socket_write(ttyfd,s,n)) < 1) {
  1162.         debug(F101,"nettol socket_write error","",socket_errno);
  1163.         return(-1);
  1164.     }
  1165.     debug(F111,"nettol socket_write",s,count);
  1166.     return(count);
  1167.     } else return(-2);
  1168. #else
  1169.     debug(F100,"nettol TCPIPLIB not defined","",0);
  1170.     return(-2);
  1171. #endif /* TCPIPLIB */
  1172. }
  1173.  
  1174. /*  N E T T O C  --   Output character to network */
  1175. /*
  1176.   Call with character to be transmitted.
  1177.   Returns 0 if transmission was successful, or
  1178.   -1 upon i/o error, or -2 if called improperly.
  1179. */
  1180. int            
  1181. #ifdef CK_ANSIC
  1182. nettoc(char c)
  1183. #else
  1184. nettoc(c) char c;
  1185. #endif /* CK_ANSIC */
  1186. /* nettoc */ {
  1187. #ifdef TCPIPLIB
  1188.     unsigned char cc;
  1189.     cc = c;
  1190.     if (ttnet == NET_TCPB) {
  1191.     debug(F101,"nettoc cc","",cc);
  1192.     if (socket_write(ttyfd,&cc,1) < 1) {
  1193.         debug(F101,"nettoc socket_write error","",socket_errno);
  1194.         return(-1);
  1195.     }
  1196.     debug(F101,"nettoc socket_write","", cc);
  1197.     return(0);
  1198.     } else return(-2);
  1199. #else
  1200.     return(-2);
  1201. #endif /* TCPIPLIB */
  1202. }
  1203.  
  1204. /*  N E T F L U I  --  Flush network input buffer  */
  1205.  
  1206. int
  1207. netflui() {
  1208.     int n;
  1209. #ifdef TCPIPLIB
  1210.     ttibuf[ttibp+1] = '\0';
  1211.     debug(F111,"netflui 1",ttibuf,ttibn);
  1212.     ttibn = ttibp = 0;            /* Flush internal buffer *FIRST* */
  1213.     if ((n = nettchk()) > 0) {        /* Now see what's waiting on the net */
  1214.     if (n > TTIBUFL) n = TTIBUFL;    /* and sponge it up */
  1215.     debug(F101,"netflui 2","",n);    /* ... */
  1216.     n = socket_read(ttyfd,ttibuf,n) ; /* into our buffer */
  1217.     if (n >= 0) ttibuf[n] = '\0';
  1218.     debug(F111,"netflui 3",ttibuf,n);
  1219.     ttibuf[0] = '\0';
  1220.     }
  1221. #else
  1222. /*
  1223.   It seems the UNIX ioctl()s don't do the trick, so we have to read the
  1224.   stuff ourselves.  This should be pretty much portable, if not elegant.
  1225. */
  1226.     if ((n = ttchk()) > 0) {
  1227.     debug(F101,"netflui","",n);
  1228.     while ((n--) && ttinc(0) > -1) ; /* Don't worry, it's buffered. */
  1229.     }
  1230. #endif /* TCPIPLIB */
  1231.     return(0);
  1232. }
  1233.  
  1234. #ifdef TNCODE                /* Compile in telnet support code */
  1235.  
  1236. /* TCP/IP TELNET protocol negotiation support code */
  1237.  
  1238. static int sgaflg = 0;            /* SUPRRESS GO-AHEAD state */
  1239. static int dosga  = 0;            /* 1 if I sent DO SGA from tn_ini() */
  1240. static int wttflg = 0;            /* ditto for WILL TERMINAL TYPE */
  1241.  
  1242. #ifndef TELCMDS
  1243. char *telcmds[] = {
  1244.     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
  1245.     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
  1246. };
  1247. int ntelcmds = sizeof(telcmds) / sizeof(char *);
  1248. #endif /* TELCMDS */
  1249.  
  1250. char *tnopts[] = {
  1251.     "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
  1252.     "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
  1253.     "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
  1254.     "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
  1255.     "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
  1256.     "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
  1257.     "TACACS UID","OUTPUT MARKING","TTYLOC","3270 REGIME",
  1258.     "X.3 PAD","NAWS","TSPEED","LFLOW","LINEMODE"
  1259. };
  1260. int ntnopts = sizeof(tnopts) / sizeof(char *);
  1261. #endif /* TNCODE */
  1262.  
  1263. /* Send network BREAK */
  1264. /*
  1265.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  1266. */
  1267. int
  1268. netbreak() {
  1269.     CHAR buf[3];
  1270.     if (ttnet == NET_TCPB) {
  1271.     if (ttnproto == NP_TELNET) {
  1272. #ifdef TNCODE
  1273.         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
  1274.         if (
  1275. #ifdef OS2
  1276.         nettol((char *) buf, 2)
  1277. #else
  1278.         ttol(buf, 2)
  1279. #endif /* OS2 */
  1280.         < 2)
  1281.           return(-1);
  1282.         debug(F101,"telnet BREAK ok","",BREAK);
  1283.         return(1);
  1284. #else
  1285.         debug(F100,"netbreak no TNCODE","",0);
  1286.         return(0);
  1287. #endif /* TNCODE */
  1288.     }
  1289.     /* Insert other TCP/IP protocols here */
  1290.     }
  1291.     /* Insert other networks here */
  1292.     return(0);
  1293. }
  1294.  
  1295. /* Send a telnet option, avoid loops. */
  1296. /* Returns 1 if command was sent, 0 if not, -1 on error */
  1297.  
  1298. int
  1299. tn_sopt(cmd,opt) int cmd, opt; {    /* TELNET SEND OPTION */
  1300.     CHAR buf[5];
  1301.     int n;
  1302.     if (ttnet != NET_TCPB) return(0);    /* Must be TCP/IP */
  1303.     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
  1304. #ifdef TNCODE
  1305.     n = cmd - SE;
  1306.     if (n < 0 || n > ntelcmds) return(0);
  1307.     buf[0] = (CHAR) IAC;
  1308.     buf[1] = (CHAR) cmd & 0xff;
  1309.     buf[2] = (CHAR) opt & 0xff;
  1310.     buf[3] = (CHAR) 0;
  1311.     if (ttol(buf,3) < 3)
  1312.       return(-1);
  1313.     if ((debses || deblog) && cmd != SB) {
  1314.     sprintf(tn_msg,"TELNET SENT %s %s",telcmds[n],
  1315.         (opt < ntnopts) ? tnopts[opt] : "UNKNOWN");
  1316.     debug(F101,tn_msg,"",opt);
  1317.     if (debses) tn_debug(tn_msg);
  1318.     }
  1319.     return(1);
  1320. #else
  1321.     debug(F100,"tn_sopt no TNCODE","",0);
  1322.     return(0);
  1323. #endif /* TNCODE */
  1324. }
  1325.  
  1326. /* Initialize a telnet connection. */
  1327. /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
  1328.  
  1329. int
  1330. tn_ini() {
  1331.     int x;
  1332. #ifndef TNCODE
  1333.     debug(F100,"tn_ini no TNCODE","",0);
  1334.     return(0);
  1335. #else /* TELNET protocol support */
  1336.     debug(F101,"tn_ini ttnproto","",ttnproto);
  1337.     debug(F101,"tn_ini tn_init","",tn_init);
  1338.  
  1339.     if (ttnet != NET_TCPB)        /* Make sure connection is TCP/IP */
  1340.       return(0);
  1341.     if (tn_init)            /* Have we done this already? */
  1342.       return(0);            /* Don't do it again. */
  1343.     debug(F101,"tn_ini tn_duplex","",tn_duplex);
  1344.     duplex = tn_duplex;            /* Assume local echo. */
  1345.     sgaflg = 0;                /* Assume Go-Ahead suppressed. */
  1346.     wttflg = 0;                /* Did not send WILL TERM TYPE yet. */
  1347.     wnawsflg = 0;            /* Did not send WILL/WONT NAWS yet. */
  1348.     dosga  = 0;                /* Did not send DO SGA yet. */
  1349.     if (ttnproto == NP_NONE) {        /* If not talking to a telnet port, */
  1350.     ttnproto = NP_TELNET;        /* pretend it's telnet anyway, */
  1351.     tn_init = 1;            /* but don't send initial options. */
  1352.     debug(F100,"tn_ini skipping telnet negotiations","",0);
  1353.     return(0);
  1354.     }
  1355.     debug(F100,"tn_ini about to send WILL TTYPE","",0);
  1356. /* 
  1357.   Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA.
  1358.   Also send WILL NAWS if we know our screen dimensions.
  1359. */
  1360.     if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) { /* Will send terminal type. */
  1361.     debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x);
  1362.     return(-1);
  1363.     }
  1364.     debug(F100,"tn_ini sent WILL TTYPE ok","",0);
  1365.     wttflg = 1;                /* Remember I said I would. */
  1366. #ifdef CK_NAWS
  1367.     /* Console terminal screen rows and columns */
  1368.     debug(F101,"tn_ini tt_rows 1","",tt_rows);
  1369.     debug(F101,"tn_ini tt_cols 1","",tt_cols);
  1370.     if (tt_rows < 0 || tt_cols < 0) {    /* Not known yet */
  1371.         ttgwsiz();            /* Try to find out */
  1372.     }
  1373.     debug(F101,"tn_ini tt_rows 2","",tt_rows);
  1374.     debug(F101,"tn_ini tt_cols 2","",tt_cols);
  1375.     if (tt_rows > 0 && tt_cols > 0) {    /* Now do we know? */
  1376.     if (tn_sopt(WILL, TELOPT_NAWS) < 0)
  1377.       return(-1);
  1378.     wnawsflg = 1;            /* Remember I said I would. */
  1379.     }
  1380. #endif /* CK_NAWS */
  1381.  
  1382.     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
  1383.       return(-1);
  1384.     dosga = 1;                /* Remember I said DO SGA */
  1385.     tn_init = 1;            /* Set telnet-initialized flag. */
  1386.  
  1387.     /* Don't send anthing else! */
  1388.  
  1389.     debug(F101,"tn_ini duplex","",duplex);
  1390.     debug(F101,"tn_ini done, tn_init","",tn_init);
  1391.     return(1);
  1392. #endif /* TNCODE */
  1393. }
  1394.  
  1395. static VOID
  1396. tn_debug(s) char *s; {
  1397. #ifdef OS2
  1398.     void cwrite(unsigned char);
  1399.     char *p = s;
  1400.     _PROTOTYP (void os2bold, (void) );
  1401. #endif /* OS2 */
  1402.  
  1403.     debug(F111,"tn_debug",s,what);
  1404.     if (what != W_CONNECT || debses == 0) /* CONNECT command must be active */
  1405.       return;
  1406.  
  1407. #ifdef OS2
  1408.     os2bold();                /* Toggle boldness */
  1409.     while (*p) cwrite((CHAR) *p++);    /* Go boldly ... */
  1410.     os2bold();                /* Toggle boldness back */
  1411.     debses = 0;
  1412.     cwrite((CHAR) '\015');
  1413.     cwrite((CHAR) '\012');
  1414.     debses = 1;
  1415. #else
  1416.     conoll(s);
  1417. #endif /* OS2 */
  1418. }
  1419.  
  1420. /*
  1421.   Process in-band Telnet negotiation characters from the remote host.
  1422.   Call with the telnet IAC character and the current duplex setting
  1423.   (0 = remote echo, 1 = local echo), and a pointer to a function to call
  1424.   to read more characters.  Returns:
  1425.     3 if server has sent us a quoted IAC
  1426.     2 if local echo must be changed to remote
  1427.     1 if remote echo must be changed to local
  1428.     0 if nothing happens or no action necessary
  1429.    -1 on failure (= internal or i/o error)
  1430. */
  1431.  
  1432. #define TSBUFSIZ 41
  1433. char sb[TSBUFSIZ];            /* Buffer for subnegotiations */
  1434.  
  1435. int
  1436. #ifdef CK_ANSIC                /* TELNET DO OPTION */
  1437. tn_doop( CHAR z, int echo, int (*fn)(int) )
  1438. #else
  1439. tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
  1440. #endif /* CK_ANSIC */
  1441. /* tn_doop */ {
  1442.     int c, x, y, n, m, flag;
  1443.  
  1444. #ifndef TNCODE
  1445.     debug(F100,"tn_doop no TNCODE","",0);
  1446.     return(0);
  1447. #else
  1448.     if (z != (CHAR) IAC) {
  1449.     debug(F101,"tn_doop bad call","",z);
  1450.     return(-1);
  1451.     }
  1452.     if (ttnet != NET_TCPB) return(0);
  1453.     if (ttnproto != NP_TELNET) return(0);     /* Check protocol */
  1454.  
  1455. /* Have IAC, read command character. */
  1456.  
  1457.     c = (*fn)(0) & 0xff;        /* Read command character */
  1458.     m = c - SE;                /* Check validity */
  1459.     if (m < 0 || m > ntelcmds) {
  1460.     debug(F101,"tn_doop bad cmd","",c);
  1461.     return(0);
  1462.     }
  1463.     if (seslog && sessft) {        /* Copy to session log, if any. */
  1464.     if (zchout(ZSFILE, (char) z) < 0) seslog = 0; /* Log IAC. */
  1465.     else if (zchout(ZSFILE, (char) c) < 0) seslog = 0; /* Log command */
  1466.     }
  1467.     if (c == (CHAR) IAC) return(3);    /* Quoted IAC */
  1468.     if (c < SB) return(0);        /* Other command with no arguments. */
  1469.  
  1470. /* SB, WILL, WONT, DO, or DONT need more bytes... */
  1471.  
  1472.     if ((x = (*fn)(0)) < 0) return(-1);    /* Get the option. */
  1473.     x &= 0xff;                /* Trim to 8 bits. */
  1474.  
  1475.     if (seslog && sessft)        /* Session log */
  1476.       if (zchout(ZSFILE, (char) x) < 0) seslog = 0;
  1477.  
  1478.     if ((deblog || debses) && c != SB) {
  1479.     sprintf(tn_msg,"TELNET RCVD %s %s",telcmds[m],
  1480.         (x < ntnopts) ? tnopts[x] : "UNKNOWN");
  1481.     debug(F101,tn_msg,"",x);
  1482.     if (debses) tn_debug(tn_msg);
  1483.     }
  1484.  
  1485.     /* Now handle the command */
  1486.  
  1487.     switch (x) {
  1488.       case TELOPT_ECHO:            /* ECHO negotiation. */
  1489.     switch (c) {            /* Command */
  1490.       case WILL:            /* Host says it will echo. */
  1491.         if (echo) {            /* Only reply if change required. */
  1492.         int t;
  1493.         debug(F101,"tn_doop got WILL ECHO, echo","",echo);
  1494.         t = tn_sopt(DO,x);    /* Please do. */
  1495.         debug(F101,"tn_sopt returns","",t);
  1496.         t = (t < 0) ? -1 : 2;
  1497.         debug(F101,"tn_doop returns","",t);
  1498.         return(t);
  1499.         } else return(0);        /* Otherwise no change. */
  1500.       case WONT:            /* Host says it won't echo. */
  1501.         if (!echo)            /* If I'm full duplex */
  1502.           return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
  1503.         else return(0);        /* Otherwise, no change.  */
  1504.       case DO:            /* Host wants me to echo */
  1505.         if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
  1506.           return(-1);        /* back to the server. */
  1507.       default:            /* Don't reply to anything else */
  1508.         return(0);
  1509.     }
  1510.  
  1511.       case TELOPT_SGA:            /* Suppress Go-Ahead */
  1512.     switch (c) {            /* Command... */
  1513.       case WONT:            /* Host says it won't. */
  1514.         if (!sgaflg) {
  1515.         sgaflg = 1;        /* Remember. */
  1516.         if (tn_sopt(DONT,x) < 0) /* acknowledge, */
  1517.           return(-1);
  1518.         }
  1519.         return(echo ? 0 : 1);    /* Switch to half duplex */
  1520.       case WILL:            /* Server says it will SGA */
  1521.         if (sgaflg || !dosga) {    /* ACK only if necessary */
  1522.         if (tn_sopt(DO,x) < 0)
  1523.           return(-1);
  1524.         sgaflg = 0;        /* Remember new SGA state. */
  1525.         }
  1526.         return(0);            /* But don't change echo state. */
  1527.   
  1528.       case DONT:
  1529. /*
  1530.   Note: The following is proper behavior, and required for talking to the
  1531.   Apertus interface to the NOTIS library system, e.g. at Iowa State U:
  1532.   scholar.iastate.edu.  Without this reply, the server hangs forever.  This
  1533.   code should not be loop-inducing, since C-Kermit never sends WILL SGA as
  1534.   an initial bid, so if DO SGA comes, it is never an ACK.
  1535. */
  1536.       case DO:            /* Server wants me to SGA. */
  1537.         if (tn_sopt(WILL,x) < 0)    /* I have to say WILL SGA, */
  1538.           return(-1);        /* even tho I'm not changing state */
  1539.         return(0);            /* or else server might hang. */
  1540.     }
  1541.  
  1542. #ifdef TELOPT_TTYPE
  1543.       case TELOPT_TTYPE:        /* Terminal Type */
  1544.     switch (c) {
  1545.       case DO:            /* DO terminal type. */
  1546.         if (wttflg == 0) {        /* If I haven't said so before, */
  1547.         if (tn_sopt((CHAR)WILL,x) < 0) /* say I'll send it if asked. */
  1548.           return(-1);
  1549.         wttflg++;
  1550.         }
  1551.         return(0);
  1552.       case SB:
  1553.         n = flag = 0;        /* Flag for when done reading SB */
  1554.         while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
  1555.         if ((y = (*fn)(0)) < 0)    /* Read a byte */
  1556.           return(-1);
  1557.         y &= 0xff;        /* Make sure it's just 8 bits. */
  1558.         sb[n++] = y;        /* Deposit in buffer. */
  1559.         if (seslog && sessft)    /* Take care of session log */
  1560.           if (zchout(ZSFILE, (char) y) < 0)
  1561.             seslog = 0;
  1562.         if (y == IAC) {        /* If this is an IAC */
  1563.             if (flag) {        /* If previous char was IAC */
  1564.             n--;        /* it's quoted, keep one IAC */
  1565.             flag = 0;    /* and turn off the flag. */
  1566.             } else flag = 1;    /* Otherwise set the flag. */
  1567.         } else if (flag) {     /* Something else following IAC */
  1568.             if (y != SE)    /* If not SE, it's a protocol error */
  1569.               flag = 0;
  1570.             break;
  1571.         }
  1572.         }
  1573.         if (!flag) {        /* Make sure we got a valid SB */
  1574.         debug(F100, "TELNET Subnegotian prematurely broken", "",0);
  1575.         return(-1);
  1576.         }
  1577.         if (deblog || debses) {
  1578.         int i;
  1579.         sprintf(tn_msg,"TELNET RCVD SB %s ",tnopts[TELOPT_TTYPE]);
  1580.         for (i = 0; i < n-2; i++) {
  1581.             sprintf(hexbuf,"%02x",(unsigned int) sb[i]);
  1582.             strcat(tn_msg,hexbuf);
  1583.         }
  1584.         strcat(tn_msg," IAC SE");
  1585.         debug(F100,tn_msg,"",0);
  1586.         if (debses) tn_debug(tn_msg);
  1587.         }
  1588.         if (sb[0] == 1) {        /* SEND terminal type? */
  1589.         if (tn_sttyp() < 0)    /* Yes, so send it. */
  1590.           return(-1);
  1591.         }
  1592.       default:            /* Others, ignore */
  1593.         return(0);
  1594.     }
  1595. #endif /* TELOPT_TTYPE */
  1596.  
  1597. #ifdef CK_NAWS
  1598.       case TELOPT_NAWS:            /* Terminal width and height */
  1599.     if (c == DO) {
  1600.         /* Get window size again in case it changed */
  1601.         ttgwsiz();
  1602.         if (wnawsflg == 0) {    /* Haven't said WILL/WONT before? */
  1603.         if (tn_sopt( (tt_rows < 0 || tt_cols < 0) ?
  1604.                 (CHAR) WONT :
  1605.                 (CHAR) WILL
  1606.                 , x) < 0)    /* Say it */
  1607.           return(-1);
  1608.         wnawsflg = 1;        /* And remember I said it. */
  1609.         }
  1610.         if (tt_rows > 0 && tt_cols > 0) {
  1611. #ifndef NOSIGWINCH
  1612. #ifdef SIGWINCH
  1613. #ifdef UNIX
  1614.         if (sw_armed++ < 1) {    /* Catch window-size changes. */ 
  1615.             debug(F100,"tn_doop arming SIGWINCH","",0);
  1616.             signal(SIGWINCH,winchh);
  1617.         }
  1618. #else
  1619.         debug(F100,"SIGWINCH defined but not used","",0);
  1620. #endif /* UNIX */    
  1621. #endif /* SIGWINCH */
  1622. #endif /* NOSIGWINCH */
  1623.         tn_snaws();        /* And now actually do it. */
  1624.         }
  1625.     }
  1626.     return(0);
  1627. #endif /* CK_NAWS */
  1628.  
  1629.       default:                /* All others: refuse */
  1630.     switch(c) {
  1631.       case WILL:            /* You will? */
  1632.         if (tn_sopt(DONT,x) < 0)    /* Please don't. */
  1633.           return(-1);        /* (Could this cause a loop?) */
  1634.         break;
  1635.       case DO:            /* You want me to? */
  1636.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1637.           return(-1);
  1638.         break;
  1639.       case DONT:            /* You don't want me to? */
  1640.         if (tn_sopt(WONT,x) < 0)    /* I won't. */
  1641.           return(-1);        /* (Could this cause a loop?) */
  1642.       case WONT:            /* You won't? */
  1643.         break;            /* I didn't want you to. */
  1644.     }                /* Anything else, treat as user data */
  1645.     return(0);
  1646.     }
  1647. #endif /* TNCODE */
  1648. }
  1649.  
  1650. /* Telnet send terminal type */
  1651. /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
  1652.  
  1653. int
  1654. tn_sttyp() {                /* Send telnet terminal type. */
  1655. #ifndef TNCODE
  1656.     debug(F100,"tn_sttyp no TNCODE","",0);
  1657.     return(0);
  1658. #else
  1659.     char *ttn;                /* Name of terminal type. */
  1660.     int i;                /* Worker. */
  1661.  
  1662.     if (ttnet != NET_TCPB) return(0);
  1663.     if (ttnproto != NP_TELNET) return(0);
  1664.  
  1665.     ttn = NULL;
  1666.  
  1667. #ifdef OS2
  1668.     if (tt_type >= 0 && tt_type <= max_tt)
  1669.       ttn = tt_info[tt_type].x_name;
  1670. #endif /* OS2 */
  1671.  
  1672.     if (tn_term) {            /* Terminal type override? */
  1673.     debug(F110,"tn_sttyp",tn_term,0);
  1674.     if (*tn_term) ttn = tn_term;
  1675.     } else debug(F100,"tn_sttyp no term override","",0);
  1676.  
  1677. #ifndef datageneral
  1678.     if (!ttn)                /* If no override, */
  1679.       ttn = getenv("TERM");        /* get it from the environment. */
  1680. #endif /* datageneral */
  1681.     if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ))
  1682.       ttn = "UNKNOWN";
  1683.     sb[0] = (CHAR) IAC;            /* I Am a Command */
  1684.     sb[1] = (CHAR) SB;            /* Subnegotiation */
  1685.     sb[2] = TELOPT_TTYPE;        /* Terminal Type */
  1686.     sb[3] = (CHAR) 0;            /* Is... */
  1687.     for (i = 4; *ttn; ttn++,i++)    /* Copy and uppercase it */
  1688.       sb[i] = (islower(*ttn)) ? toupper(*ttn) : *ttn;
  1689.     ttn = sb;                /* Point back to beginning */
  1690.     sb[i++] = (CHAR) IAC;        /* End of Subnegotiation */
  1691.     sb[i++] = (CHAR) SE;        /* marked by IAC SE */
  1692.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  1693.       return(-1);
  1694.     sb[i-2] = '\0';            /* For debugging */
  1695.     if (deblog || debses) {
  1696.     sprintf(tn_msg,"TELNET SENT SB TERMINAL TYPE 00 %s IAC SE",sb+4);
  1697.     debug(F100,tn_msg,"",0);
  1698.     if (debses) tn_debug(tn_msg);
  1699.     }
  1700.     return(1);
  1701. #endif /* TNCODE */
  1702. }
  1703.  
  1704. #ifdef CK_NAWS            /*  NAWS = Negotiate About Window Size  */
  1705. int
  1706. tn_snaws() {            /*  Send terminal width and height, RFC 1073 */
  1707. #ifndef TNCODE
  1708.     debug(F100,"tn_snaws no TNCODE","",0);
  1709. #else
  1710.     int i = 0;
  1711.     int x = tt_cols, y = tt_rows;
  1712.  
  1713.     if (ttnet != NET_TCPB) return(0);
  1714.     if (ttnproto != NP_TELNET) return(0);
  1715.  
  1716.     if (x < 0) x = 0;
  1717.     if (y < 0) y = 0;
  1718.  
  1719.     sb[i++] = (CHAR) IAC;        /* Send a subnegotiation */
  1720.     sb[i++] = (CHAR) SB;
  1721.     sb[i++] = TELOPT_NAWS;
  1722.     sb[i++] = (CHAR) (x >> 8) & 0xff;
  1723.     /* IAC in data must be doubled */
  1724.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  1725.     sb[i++] = (CHAR) (x & 0xff);
  1726.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  1727.     sb[i++] = (CHAR) (y >> 8) & 0xff;
  1728.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  1729.     sb[i++] = (CHAR) (y & 0xff);
  1730.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  1731.     sb[i++] = (CHAR) IAC;
  1732.     sb[i++] = (CHAR) SE;
  1733.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  1734.       return(-1);
  1735.     if (deblog || debses) {
  1736.     sprintf(tn_msg,"TELNET SENT SB NAWS %d %d IAC SE",x,y);
  1737.     debug(F100,tn_msg,"",0);
  1738.     if (debses) tn_debug(tn_msg);
  1739.     }
  1740. #endif /* TNCODE */
  1741.     return (0);
  1742. }
  1743. #endif /* CK_NAWS */
  1744.  
  1745. #ifdef SUNX25
  1746. /*
  1747.   SunLink X.25 support by Marcello Frutig, Catholic University,
  1748.   Rio de Janeiro, Brazil, 1990.
  1749. */
  1750.  
  1751. /* PAD X.3, X.28 and X.29 support */
  1752.  
  1753. static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  1754.  
  1755.  
  1756. /* Initialize PAD */
  1757.  
  1758. extern CHAR padparms[MAXPADPARMS+1];
  1759.  
  1760. VOID
  1761. initpad() {
  1762.   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
  1763.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  1764.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  1765.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  1766.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  1767.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  1768.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  1769.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  1770.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  1771.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  1772.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  1773.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  1774.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  1775.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  1776.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  1777.   padparms[PAD_EDITING]                = 1;  /* can edit */
  1778.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  1779.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  1780.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  1781. }
  1782.  
  1783.  
  1784. /* Set PAD parameters */
  1785.  
  1786. VOID
  1787. setpad(s,n) CHAR *s; int n; {
  1788.     int i;
  1789.     CHAR *ps = s;
  1790.  
  1791.     if (n < 1) {
  1792.     initpad();
  1793.     } else {
  1794.     for (i = 0; i < n; i++) {
  1795.         if (*ps > MAXPADPARMS)
  1796.           x29err[i+2] = *ps;
  1797.         else
  1798.           padparms[*ps] = *(ps+1);
  1799.         ps += 2;
  1800.     }
  1801.     }
  1802. }
  1803.  
  1804. /* Read PAD parameters */
  1805.  
  1806. VOID
  1807. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  1808.     int i;
  1809.     CHAR *ps = s;
  1810.     CHAR *pr = r;
  1811.  
  1812.     *pr++ = X29_PARAMETER_INDICATION;
  1813.     if (n > 0) {
  1814.     for (i = 0; i < n; i++, ps++) {
  1815.         if (*ps > MAXPADPARMS) {
  1816.         x29err[i+2] = *ps++;
  1817.         } else {
  1818.         *pr++ = *ps;
  1819.         *pr++ = padparms[*ps++];
  1820.         }
  1821.     }
  1822.     } else {
  1823.     for (i = 1; i < MAXPADPARMS; i++) {
  1824.         *pr++ = i;
  1825.         *pr++ = padparms[i];
  1826.     }
  1827.     }
  1828. }
  1829.  
  1830. int
  1831. qbitpkt(s,n) CHAR *s; int n; {
  1832.     CHAR *ps = s;
  1833.     int x29cmd = *ps;
  1834.     CHAR *psa = s+1;
  1835.     CHAR x29resp[(MAXPADPARMS*2)+1];
  1836.  
  1837.     switch (x29cmd) {
  1838.  
  1839.         case X29_SET_PARMS:
  1840.             setpad (ps+1,n/2);
  1841.             if ((int)strlen(x29err) > 2) {
  1842.                 ttol (x29err,(int)strlen(x29err));
  1843.                 x29err[2] = '\0';
  1844.             }
  1845.             return (-2);
  1846.         case X29_READ_PARMS:
  1847.             readpad (ps+1,n/2,x29resp);
  1848.             setqbit ();
  1849.             ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  1850.             if ((int)strlen(x29err) > 2) {
  1851.                 ttol (x29err,(int)strlen(x29err));
  1852.                 x29err[2] = '\0';
  1853.             }
  1854.             resetqbit();
  1855.             break;
  1856.         case X29_SET_AND_READ_PARMS:
  1857.             setpad (ps+1,n/2);
  1858.             readpad (ps+1,n/2,x29resp);
  1859.             setqbit();
  1860.             ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  1861.             if ((int)strlen(x29err) > 2) {
  1862.                 ttol (x29err,(int)strlen(x29err));
  1863.                 x29err [2] = '\0';
  1864.             }
  1865.             resetqbit();
  1866.             return (-2);
  1867.         case X29_INVITATION_TO_CLEAR:
  1868.             (VOID) x25clear();
  1869.             return (-1) ;
  1870.         case X29_INDICATION_OF_BREAK:
  1871.         break;
  1872.     }
  1873.     return (0);
  1874. }
  1875.  
  1876. /* PAD break action processor */
  1877.  
  1878. VOID
  1879. breakact() {
  1880.     extern char x25obuf[MAXOX25];
  1881.     extern int obufl;
  1882.     extern int active;
  1883.     extern unsigned char tosend;
  1884.     static CHAR indbrk[3] = {
  1885.     X29_INDICATION_OF_BREAK,
  1886.     PAD_SUPPRESSION_OF_DATA,
  1887.     1
  1888.     };
  1889.     CHAR intudat, cause, diag;
  1890.  
  1891.     if (x25stat() < 0) return;    /* Ignore if no virtual call established */
  1892.  
  1893.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  1894.         if (ttol(x25obuf,obufl) < 0) {
  1895.             perror ("\r\nCan't send characters");
  1896.             active = 0;
  1897.         } else {
  1898.             bzero (x25obuf,sizeof(x25obuf));
  1899.             obufl = 0;
  1900.             tosend = 0;
  1901.         };
  1902.  
  1903.     switch (padparms[PAD_BREAK_ACTION]) {
  1904.  
  1905.        case 0 : break;            /* do nothing */
  1906.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  1907.             intudat = 1;
  1908.                 x25intr (intudat);
  1909.                 break;
  1910.        case 2 : /* send reset packet with cause and diag = 0 */
  1911.         cause = diag = 0;
  1912.                 x25reset (cause,diag);
  1913.                 break;
  1914.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  1915.         intudat = 0;
  1916.                 x25intr (intudat) ;
  1917.                 setqbit ();
  1918.             /* send indication of break without a parameter field */
  1919.                 ttoc(X29_INDICATION_OF_BREAK);
  1920.                 resetqbit ();
  1921.                 break;
  1922.        case 8 : active = 0;        /* leave data transfer */
  1923.                 conol ("\r\n");
  1924.                 break;
  1925.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  1926.         intudat = 0;
  1927.                 x25intr (intudat);
  1928.                 setpad (indbrk+1,2);    /* set pad to discard input */
  1929.                 setqbit ();
  1930.         /* send indication of break with parameter field */
  1931.                 ttol (indbrk,sizeof(indbrk));
  1932.                 resetqbit ();
  1933.                 break;
  1934.      }
  1935. }
  1936.  
  1937. /* X.25 support functions */
  1938.  
  1939. X25_CAUSE_DIAG diag;
  1940.  
  1941. /*
  1942.   Convert a null-terminated string representing an X.121 address
  1943.   to a packed BCD form.
  1944. */
  1945.  
  1946. int
  1947. pkx121(str,bcd) char *str; CHAR *bcd; {
  1948.     int i, j;
  1949.     u_char c;
  1950.  
  1951.     i = j = 0;
  1952.     while (str[i]) {
  1953.         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
  1954.       return (-1);
  1955.         c = str [i] - '0';
  1956.         if ( i & 1 )
  1957.       bcd [j++] |= c;
  1958.         else
  1959.       bcd [j] = c << 4;
  1960.         i++;
  1961.     }
  1962.     return (i);
  1963. }
  1964.  
  1965. /* Reads and prints X.25 diagnostic */
  1966.  
  1967. int
  1968. x25diag () {
  1969.     int i;
  1970.  
  1971.     bzero ((char *)&diag,sizeof(diag));
  1972.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  1973.         perror ("Reading X.25 diagnostic");
  1974.         return(-1);
  1975.     }
  1976.     if (diag.datalen > 0) {
  1977.         printf ("X.25 Diagnostic :");
  1978.         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
  1979.         printf ("\r\n");
  1980.     }
  1981.     return(0);
  1982. }
  1983.  
  1984. /* X.25 Out-of-Band Signal Handler */
  1985.  
  1986. SIGTYP
  1987. x25oobh(foo) int foo; {
  1988.     int oobtype;
  1989.     u_char oobdata;
  1990.     int t;
  1991.  
  1992.     (VOID) signal(SIGURG,x25oobh);
  1993.     do {
  1994.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  1995.             perror ("Getting signal type");
  1996.             return;
  1997.         }
  1998.         switch (oobtype) {
  1999.       case INT_DATA:
  2000.         if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
  2001.         perror ("Receiving X.25 interrupt data");
  2002.         return;
  2003.         }
  2004.         t = oobdata;
  2005.         printf ("\r\nInterrupt received, data = %d\r\n", t);
  2006.         break;
  2007.       case VC_RESET:
  2008.         printf ("\r\nVirtual circuit reset\r\n");
  2009.         x25diag ();
  2010.         break;
  2011.       case N_RESETS:
  2012.         printf ("\r\nReset timeout\r\n");
  2013.         break;
  2014.       case N_CLEARS:
  2015.         printf ("\r\nClear timeout\r\n");
  2016.         break;
  2017.       case MSG_TOO_LONG:
  2018.         printf ("\r\nMessage discarded, too long\r\n");
  2019.         break;
  2020.       default:
  2021.         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  2022.         break;
  2023.     }
  2024.     } while (oobtype);
  2025. }
  2026.  
  2027. /* Send a X.25 interrupt packet */
  2028.  
  2029. int
  2030. #ifdef CK_ANSIC
  2031. x25intr(char intr)
  2032. #else
  2033. x25intr(intr) char intr;
  2034. #endif /* CK_ANSIC */
  2035. /* x25intr */ {
  2036.     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
  2037.     debug(F100,"X.25 intr","",0);
  2038.     return(0);
  2039. }
  2040.  
  2041. /* Reset X.25 virtual circuit */
  2042. int
  2043. #ifdef CK_ANSIC
  2044. x25reset(char cause, char diagn)
  2045. #else
  2046. x25reset(cause, diagn) char cause; char diagn;
  2047. #endif /* CK_ANSIC */
  2048. /* x25reset */ {
  2049.     bzero ((char *)&diag,sizeof(diag));
  2050.     diag.flags   = 0;
  2051.     diag.datalen = 2;
  2052.     diag.data[0] = cause;
  2053.     diag.data[1] = diagn;
  2054.     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
  2055.       return(-1);
  2056.     debug(F100,"X.25 reset","",0);
  2057.     return(0);
  2058. }
  2059.  
  2060. /* Clear X.25 virtual circuit */
  2061. int
  2062. x25clear() {
  2063.     int i;
  2064.     debug(F100,"X.25 clear","",0);
  2065.     bzero ((char *)&diag,sizeof(diag));
  2066.     diag.flags = (1 << DIAG_TYPE);
  2067.     diag.datalen = 2;
  2068.     diag.data[0] = 0;
  2069.     diag.data[1] = 0;
  2070.     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
  2071.     return(ttclos(0));            /* Close socket */
  2072. }
  2073.  
  2074. /* X.25 status */
  2075. int
  2076. x25stat() {
  2077.     if (ttyfd < 0) return (-1);
  2078.     return(0);
  2079. }
  2080.  
  2081. /* Set Q_BIT on */
  2082. VOID
  2083. setqbit() {
  2084.     static int qbiton = 1 << Q_BIT;
  2085.     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
  2086. }
  2087.  
  2088. /* Set Q_BIT off */
  2089. VOID
  2090. resetqbit() {
  2091.     static int qbitoff = 0;
  2092.     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
  2093. }
  2094.  
  2095. /* Read n characters from X.25 circuit into buf */
  2096.  
  2097. int
  2098. x25xin(n,buf) int n; CHAR *buf; {
  2099.     register int x, c;
  2100.     int qpkt;
  2101.  
  2102.     do {
  2103.     x = read(ttyfd,buf,n);
  2104.     if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
  2105.         /* If return -1 : invitation to clear; -2 : PAD changes */
  2106.         if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
  2107.         qpkt = 1;
  2108.     } else qpkt = 0;
  2109.     } while (qpkt);
  2110.     if (x > 0) buf[x] = '\0';
  2111.     if (x < 1) x = -1;
  2112.     debug(F101,"x25xin x","",x);
  2113.  
  2114.     return(x);
  2115. }
  2116.  
  2117. #ifdef COMMENT /* NO LONGER NEEDED! */
  2118. /* X.25 read a line */
  2119.  
  2120. int
  2121. #ifdef PARSENSE
  2122. #ifdef CK_ANSIC
  2123. x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
  2124. #else
  2125. x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
  2126. #endif /* CK_ANSIC */
  2127. #else /* not PARSENSE */
  2128. #ifdef CK_ANSIC
  2129. x25inl(CHAR *dest, int max,int timo, CHAR eol)
  2130. #else
  2131. x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  2132. #endif /* __SDTC__ */
  2133. #endif /*PARSENSE */
  2134.  /* x25inl */ {
  2135.     CHAR *pdest;
  2136.     int pktype, goteol, rest, n;
  2137.     int i, flag = 0;
  2138.     extern int ttprty, ttpflg;
  2139.     int ttpmsk;
  2140.  
  2141.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
  2142.  
  2143.     debug(F101,"x25inl max","",max);
  2144.     debug(F101,"x25inl eol","",eol);
  2145.     pdest  = dest;
  2146.     rest   = max;
  2147.     goteol = 0;
  2148.     do {
  2149.     n = read(ttyfd,pdest,rest);
  2150.     n--;
  2151.     pktype = *pdest & 0x7f;
  2152.     switch (pktype) {
  2153.       case 1 << Q_BIT:
  2154.         if (qbitpkt(pdest+1,--n) < 0) return(-2);
  2155.         break;
  2156.       default:
  2157.         if (flag == 0) { /* if not in packet, search start */
  2158.         for (i = 1; (i < n) &&
  2159.              !(flag = ((dest[i] & 0x7f) == start));
  2160.              i++);
  2161.         if (flag == 0) { /* not found, discard junk */
  2162.             debug(F101,"x25inl skipping","",n);
  2163.             continue;
  2164.         } else {        /* found, discard junk before start */
  2165.             int k;
  2166.             n = n - i + 1;
  2167.             for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
  2168.         }
  2169.         }
  2170.         for (i = 0; (i < n) && /* search for eol */
  2171.          !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
  2172.          i++,pdest++);
  2173.         *pdest = '\0';
  2174.         rest -= n;
  2175.     }
  2176.     } while ( (rest > 0) && (!goteol) );
  2177.  
  2178.     if (goteol) {
  2179.     n = max - rest;
  2180.     debug (F111,"x25inl X.25 got",(char *) dest,n);
  2181.     if (timo) ttimoff();
  2182.     if (ttpflg++ == 0 && ttprty == 0) {
  2183.         if ((ttprty = parchk(dest,start,n)) > 0) {
  2184.         int j;
  2185.         debug(F101,"x25inl senses parity","",ttprty);
  2186.         debug(F110,"x25inl packet before",(char *)dest,0);
  2187.         ttpmsk = 0x7f;
  2188.         for (j = 0; j < n; j++)
  2189.           dest[j] &= 0x7f; /* Strip parity from packet */
  2190.         debug(F110,"x25inl packet after ",dest,0);
  2191.         } else {
  2192.         debug(F101,"parchk","",ttprty);
  2193.         if (ttprty < 0) { ttprty = 0; n = -1; }
  2194.         }
  2195.     }
  2196.     ttimoff();
  2197.     return(n);
  2198.     }
  2199.     ttimoff();
  2200.     return(-1);
  2201. }
  2202. #endif /* COMMENT */
  2203. #endif /* SUNX25 */
  2204.  
  2205. #endif /* NETCONN */
  2206.