Annotation of coherent/e/bin/cku179/ckcnet.c, revision 1.1

1.1     ! root        1: char *cknetv = "Network support, 5A(007) 8 Feb 91";
        !             2: 
        !             3: /*  C K C N E T  --  Network support  */
        !             4: /*
        !             5:  Authors:
        !             6: 
        !             7:  Frank da Cruz ([email protected], [email protected]),
        !             8:    Columbia University Center for Computing Activities.
        !             9:  netopen() routine for TCP/IP originally by Ken Yap, Rochester University
        !            10:    ([email protected]) (no longer at that address).
        !            11:  SunLink X.25 support by Marcello Frutig, Catholic University,
        !            12:    Rio de Janeiro, Brazil ([email protected]).
        !            13:  Missing pieces for Excelan sockets library from William Bader, Moravian
        !            14:    College <[email protected]>.
        !            15:  telnet protocol support by Frank da Cruz.
        !            16:  TGV MultiNet code by Frank da Cruz.
        !            17:  Other contributions as indicated below.
        !            18: 
        !            19:  Copyright (C) 1991, 1992, Trustees of Columbia University in the City of New 
        !            20:  York.  Permission is granted to any individual or institution to use, copy, or
        !            21:  redistribute this software as long as it is not sold for profit, provided this
        !            22:  copyright notice is retained. 
        !            23: */
        !            24: 
        !            25: #include "ckcdeb.h"
        !            26: #include "ckcker.h"
        !            27: #include "ckcnet.h"
        !            28: 
        !            29: #ifdef NETCONN
        !            30: /* Don't need these if there is no network support. */
        !            31: 
        !            32: #include <errno.h>
        !            33: #include <signal.h>
        !            34: #ifndef ZILOG
        !            35: #include <setjmp.h>
        !            36: #else
        !            37: #include <setret.h>
        !            38: #endif /* ZILOG */
        !            39: 
        !            40: extern SIGTYP (*saval)();              /* For saving alarm handler */
        !            41: extern int duplex, debses, seslog, ttyfd, quiet; /* External variables */
        !            42: 
        !            43: #ifdef SVR4
        !            44: /*
        !            45:   These suggested by Rob Healey, [email protected], to avoid
        !            46:   bugs in Berkeley compatibility library on Sys V R4 systems, but untested
        !            47:   by me (fdc).  Remove this bit if it gives you trouble.
        !            48:   (Later corrected by Marc Boucher <[email protected]> because
        !            49:   bzero/bcopy are not argument-compatible with memset/memcpy|memmove.)
        !            50: */
        !            51: #define bzero(s,n) memset(s,0,n) 
        !            52: #define bcopy(h,a,l) memmove(a,h,l)
        !            53: #endif /* SVR4 */
        !            54: 
        !            55: #define NAMECPYL 100                   /* Local copy of hostname */
        !            56: static char namecopy[NAMECPYL];
        !            57: 
        !            58: char ipaddr[20] = { '\0' };            /* Global copy of IP address */
        !            59: 
        !            60: #ifdef MULTINET
        !            61: /*
        !            62:   General global variables, but so far used only by MultiNet.
        !            63:   Kept within #ifdef MULTINET..#endif to keep strict compilers (and lint)
        !            64:   from complaining about unused variables.
        !            65: */
        !            66: static jmp_buf njbuf;                  /* For timeout longjumps */
        !            67: #endif /* MULTINET */
        !            68: 
        !            69: #endif /* NETCONN */
        !            70: 
        !            71: int ttnet = NET_NONE;                  /* Network type */
        !            72: int ttnproto = NP_NONE;                        /* Network virtual terminal protocol */
        !            73: int tn_init = 0;                       /* Telnet protocol initialized flag */
        !            74: 
        !            75: #ifndef NETCONN
        !            76: /*
        !            77:   Network support not defined.  
        !            78:   Dummy functions here in case #ifdef's forgotten elsewhere.
        !            79: */
        !            80: int                                    /* Open network connection */
        !            81: netopen(name, lcl, nett) char *name; int *lcl, nett; {
        !            82:     return(-1);
        !            83: }
        !            84: int                                    /* Close network connection */
        !            85: netclos() {
        !            86:     return(-1);
        !            87: }
        !            88: int                                    /* Check network input buffer */
        !            89: nettchk() {
        !            90:     return(-1);
        !            91: }
        !            92: int                                    /* Flush network input buffer */
        !            93: netflui() {
        !            94:     return(-1);
        !            95: }
        !            96: int                                    /* Send network BREAK */
        !            97: netbreak() {
        !            98:     return(-1);
        !            99: }
        !           100: int                                    /* Input character from network */
        !           101: netinc(timo) int timo; {
        !           102: }
        !           103: int                                    /* Output character to network */
        !           104: #ifdef CK_ANSIC
        !           105: nettoc(char c)
        !           106: #else
        !           107: nettoc(c) char c;
        !           108: #endif /* CK_ANSIC */
        !           109: /* nettoc */ {
        !           110:     return(-1);
        !           111: }
        !           112: int
        !           113: nettol(s,n) char *s; int n; {
        !           114:     return(-1);
        !           115: }
        !           116: 
        !           117: #else /* NETCONN is defined (rest of this module...) */
        !           118: 
        !           119: #ifdef MULTINET
        !           120: 
        !           121: /* For buffered network reads... */
        !           122: /*
        !           123:   If the buffering code is written right, it shouldn't matter how long this
        !           124:   buffer is -- it could even be shorter than a Kermit packet.
        !           125: */
        !           126: #define TTIBUFL 8192                   /* Maybe 8K?... */
        !           127: static CHAR ttibuf[TTIBUFL+1];
        !           128: static int ttibp = 0, ttibn = 0;
        !           129: 
        !           130: /*
        !           131:   Read bytes from network into internal buffer ttibuf[].
        !           132:   To be called when input buffer is empty, i.e. when ttibn == 0.
        !           133: 
        !           134:   Other network reading routines, like ttinc, ttinl, ttxin, should check the
        !           135:   internal buffer first, and call this routine for a refill if necessary.
        !           136: 
        !           137:   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
        !           138:   returns number of bytes read, and sets global ttibn to that number and
        !           139:   ttibp (the buffer pointer) to zero.
        !           140: */
        !           141: int
        !           142: ttbufr() {                             /* TT Buffer Read */
        !           143:     int x, count;
        !           144:     if (ttnet != NET_TCPB) {           /* First make sure current net is */
        !           145:        /* Fill in support for DECnet, etc, here */
        !           146:        return(-1);                     /* TCP/IP; if not, do nothing. */
        !           147:     } else {
        !           148:        /* Read as much as there us, up to our buffer size. */
        !           149:        count = nettchk();
        !           150:        if (count < 0) return(-1);
        !           151:        if (count > TTIBUFL) count = TTIBUFL;
        !           152:        if (count == 0) count = 1;
        !           153:        debug(F101,"ttbufr count","",count);
        !           154: 
        !           155: #ifdef COMMENT
        !           156: /*
        !           157:  This is for nonblocking reads, which we don't do any more.  This code didn't
        !           158:  work anyway, in the sense that a broken connection was never sensed.
        !           159: */
        !           160:        if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
        !           161:            if (count == -1 && socket_errno == EWOULDBLOCK) {
        !           162:                debug(F100,"ttbufr finds nothing","",0);
        !           163:                return(0);
        !           164:            } else if (count == 0) {
        !           165:                debug(F100,"ttbufr socket eof","",0);           
        !           166:                return(-1);
        !           167:            } else {
        !           168:                debug(F101,"ttbufr socket_read error","",socket_errno);
        !           169:                return(-1);
        !           170:            }
        !           171:        }
        !           172: #else
        !           173: /* This is for blocking reads */
        !           174:        if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
        !           175:            debug(F101,"ttbufr socket_read","",count);
        !           176:            debug(F101,"ttbufr socket_errno","",socket_errno);
        !           177:            return(-1);
        !           178:        }
        !           179: #endif /* COMMENT */
        !           180:        debug(F101,"ttbufr","",count);  /* Got some bytes. */
        !           181:        ttibp = 0;                      /* Reset buffer pointer. */
        !           182:        return(ttibn = count);          /* Set and return buffer count. */
        !           183:     }
        !           184: }
        !           185: #endif /* MULTINET */
        !           186: 
        !           187: /*
        !           188:   C-Kermit network open/close functions for BSD-sockets.
        !           189:   Much of this code shared by SunLink X.25, which also uses the socket library.
        !           190: */
        !           191: 
        !           192: /*  N E T O P E N  --  Open a network connection.  */
        !           193: 
        !           194: /*  Returns 0 on success, -1 on failure.  */
        !           195: 
        !           196: #define        TELNET_PORT     23         /* Should do lookup, but it won't change */
        !           197: 
        !           198: /* This symbol is not known to, e.g., Ultrix 2.0 */
        !           199: #ifndef TELOPT_TTYPE
        !           200: #define TELOPT_TTYPE 24
        !           201: #endif /* TELOPT_TTYPE */
        !           202: 
        !           203: /*  N E T O P N  --  Open a network connection.  */
        !           204: /*
        !           205:   Call with:
        !           206:     name of host (or host:service),
        !           207:     lcl - local-mode flag to be set if this function succeeds,
        !           208:     network type - value defined in ckunet.h.
        !           209: */
        !           210: 
        !           211: #ifdef EXCELAN
        !           212: /*
        !           213:   Most other BSD sockets implementations define these in header files
        !           214:   and libraries.
        !           215: */
        !           216: struct servent {
        !           217:     unsigned short s_port;
        !           218: };
        !           219: 
        !           220: struct hostent {
        !           221:     short h_addrtype;
        !           222:     struct in_addr h_addr;
        !           223:     int h_length;
        !           224: };
        !           225: 
        !           226: struct servent *
        !           227: getservbyname(service, connection) char *service,*connection; {
        !           228:     static struct servent servrec;
        !           229:     int port;
        !           230: 
        !           231:     port = 0;
        !           232:     if (strcmp(service, "telnet") == 0) port = 23;
        !           233:     else if (strcmp(service, "smtp") == 0) port = 25;
        !           234:     else port = atoi(service);
        !           235: 
        !           236:     debug(F101,"getservbyname return port ","",port);
        !           237: 
        !           238:     if (port > 0) {
        !           239:        servrec.s_port = htons(port);
        !           240:        return( &servrec );
        !           241:     }
        !           242:     return( (struct servent *) NULL );
        !           243: }
        !           244: 
        !           245: struct hostent *
        !           246: gethostbyname(hostname) char *hostname; {
        !           247:     return( (struct hostent *) NULL );
        !           248: }
        !           249: 
        !           250: unsigned long
        !           251: inet_addr(name) char *name; {
        !           252:     unsigned long addr;
        !           253: 
        !           254:     addr = rhost(&name);
        !           255:     debug(F111,"inet_addr ",name,(int)addr);
        !           256:     return(addr);
        !           257: }
        !           258: 
        !           259: char *
        !           260: inet_ntoa(in) struct in_addr in; {
        !           261:     static char name[80];
        !           262:     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
        !           263:     return(name);
        !           264: }
        !           265: #endif /* EXCELAN */
        !           266: 
        !           267: /*  N E T O P E N  --  Open a network connection  */
        !           268: /*
        !           269:   Calling conventions same as ttopen(), except third argument is network
        !           270:   type rather than modem type.  Designed to be called from within ttopen.
        !           271: */
        !           272: int
        !           273: netopen(name, lcl, nett) char *name; int *lcl, nett; {
        !           274:     char *p;
        !           275:     int on = 1, i, x;
        !           276:     struct servent *service, servrec;
        !           277:     struct hostent *host;
        !           278:     struct sockaddr_in saddr;
        !           279: #ifdef EXCELAN
        !           280:     struct sockaddr_in send_socket;
        !           281: #endif /* EXCELAN */
        !           282: 
        !           283: #ifdef SUNX25                          /* Code for SunLink X.25 support */
        !           284: #define X29PID 1                       /* X.29 Protocol ID */
        !           285:     VOID x25oobh(); 
        !           286:     CONN_DB x25host;
        !           287:     FACILITY_DB x25facil;
        !           288:     static int needh = 1;
        !           289:     PID_T pid;
        !           290:     extern int linkid, lcn, x25ver;
        !           291:     extern int revcall, closgr, cudata;
        !           292:     extern char udata[MAXCUDATA];
        !           293: #endif /* SUNX25 */
        !           294: 
        !           295:     debug(F101,"netopen nett","",nett);
        !           296:     *ipaddr = '\0';                    /* Initialize IP address string */
        !           297: 
        !           298: #ifdef SUNX25 
        !           299:     if (nett == NET_SX25) {            /* If network type is X.25 */
        !           300:         netclos();                     /* Close any previous net connection */
        !           301:         ttnproto = NP_NONE;            /* No protocol selected yet */
        !           302: 
        !           303:         /* Set up host structure */
        !           304:         bzero ((char *)&x25host,sizeof(x25host));
        !           305:         if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) {
        !           306:             fprintf (stderr,"Invalid X.121 host address %s\n",name);
        !           307:             errno = 0;
        !           308:             return (-1);
        !           309:         }
        !           310:         x25host.datalen = X29PIDLEN;
        !           311:         x25host.data[0] = X29PID;
        !           312: 
        !           313:        /* Set call user data if specified */
        !           314:         if (cudata) {
        !           315:             strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata));
        !           316:             x25host.datalen += (int)strlen(udata);
        !           317:         }
        !           318: 
        !           319:         /* Open SunLink X.25 socket */
        !           320:         if ((ttyfd = socket (AF_X25, SOCK_STREAM, 0)) < 0) {
        !           321:            debug(F101,"netopen socket error","",errno);
        !           322:             perror ("X.25 connect socket error");
        !           323:             return (-1);
        !           324:         }
        !           325: 
        !           326:         /* Setting X.25 out-of-band data handler */
        !           327:         pid = getpid();
        !           328:         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
        !           329:             perror("Setting process group id");
        !           330:             return(-1);
        !           331:         }    
        !           332:         (VOID) signal(SIGURG,x25oobh);
        !           333: 
        !           334:         /* Set reverse charge call and closed user group if requested */
        !           335:         bzero ((char *)&x25facil,sizeof(x25facil));
        !           336:         if (revcall) x25facil.reverse_charge = revcall;
        !           337:         if (closgr > -1) {
        !           338:             x25facil.cug_req = 1;
        !           339:             x25facil.cug_index = closgr;
        !           340:         }
        !           341:         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
        !           342:             perror ("Setting X.25 facilities");
        !           343:             return (-1);
        !           344:         }
        !           345: 
        !           346:         /*  Need X.25 header with bits Q and M */
        !           347:         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
        !           348:             perror ("Setting X.25 header");
        !           349:             return (-1);
        !           350:         }
        !           351: 
        !           352:         /* Connects to remote host via SunLink X.25 */
        !           353:         if (connect(ttyfd,&x25host,sizeof(x25host)) < 0) {
        !           354:             debug(F101,"netopen connect errno","",errno);
        !           355:             i = errno;
        !           356:            if (errno) {
        !           357:                 perror("netopen");
        !           358:                 x25diag();
        !           359:             }
        !           360:             (VOID) close (ttyfd);
        !           361:             ttyfd = -1;
        !           362:             errno = i;
        !           363:             return (-1);
        !           364:         }
        !           365:         
        !           366:         /* Get X.25 link identification used for the connection */
        !           367:         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
        !           368:             perror ("Getting X.25 link id");
        !           369:             return (-1);
        !           370:         }
        !           371: 
        !           372:         /* Get X.25 logical channel number used for the connection */
        !           373:         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
        !           374:             perror ("Getting X.25 lcn");
        !           375:             return (-1);
        !           376:         }
        !           377: 
        !           378:         /* Get SunLink X.25 version */
        !           379:         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
        !           380:             perror ("Getting SunLink X.25 version");
        !           381:             return (-1);
        !           382:         }
        !           383:         ttnet = nett;                   /* Sunlink X.25 network */
        !           384:         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
        !           385:         if (*lcl < 0) *lcl = 1;         /* Local mode */
        !           386:         return(0);
        !           387:     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
        !           388: #endif /* SUNX25 */
        !           389: /*
        !           390:   Add support for other networks here.
        !           391: */
        !           392:     if (nett != NET_TCPB) return(-1);  /* BSD socket support */
        !           393: 
        !           394:     netclos();                         /* Close any previous connection. */
        !           395:     strncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
        !           396:     ttnproto = NP_NONE;                        /* No protocol selected yet. */
        !           397:     debug(F110,"netopen namecopy",namecopy,0);
        !           398: 
        !           399:     p = namecopy;                      /* Was a service requested? */
        !           400:     while (*p != '\0' && *p != ':') p++; /* Look for colon */
        !           401:     if (*p == ':') {                   /* Have a colon */
        !           402:        *p++ = '\0';                    /* Get service name or number */
        !           403:     } else {                           /* Otherwise use telnet */
        !           404:        p = "telnet";
        !           405:     }
        !           406:     debug(F110,"netopen service requested",p,0);
        !           407:     if (isdigit(*p)) {                 /* Use socket number without lookup */
        !           408:        service = &servrec;
        !           409:        service->s_port = htons((unsigned short)atoi(p));
        !           410:     } else {                           /* Otherwise lookup the service name */
        !           411:        service = getservbyname(p, "tcp");
        !           412:     }
        !           413:     if (!service) {
        !           414:        fprintf(stderr, "Cannot find port for service %s\n", p);
        !           415: #ifdef MULTINET
        !           416:        debug(F101,"netopen can't get service","",socket_errno);
        !           417: #else
        !           418:        debug(F101,"netopen can't get service","",errno);
        !           419: #endif /* MULTINET */
        !           420:        errno = 0;                      /* rather than mislead */
        !           421:        return(-1);
        !           422:     }
        !           423:     /* Set up socket structure and get host address */
        !           424: 
        !           425:     bzero((char *)&saddr, sizeof(saddr));
        !           426:     if ((host = gethostbyname(namecopy)) != NULL) {
        !           427:        saddr.sin_family = host->h_addrtype;
        !           428:        bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
        !           429:     } else {
        !           430: #ifdef INADDRX
        !           431: /* inet_addr() is of type struct in_addr */
        !           432:        struct in_addr ina;
        !           433:        unsigned long uu;
        !           434:        ina = inet_addr(namecopy);
        !           435:        uu = *(unsigned long *)&ina;
        !           436: #else
        !           437: /* inet_addr() is unsigned long */
        !           438:        unsigned long uu;
        !           439:        uu = inet_addr(namecopy);
        !           440: #endif /* INADDRX */
        !           441:        if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
        !           442:          saddr.sin_family = AF_INET;
        !           443:        else {
        !           444:          fprintf(stderr, "Can't get address for %s\n", namecopy);
        !           445: #ifdef MULTINET
        !           446:          debug(F101,"netopen can't get address","",socket_errno);
        !           447: #else
        !           448:          debug(F101,"netopen can't get address","",errno);
        !           449: #endif /* MULTINET */
        !           450:          errno = 0;                    /* rather than mislead */
        !           451:          return(-1);
        !           452:       }
        !           453:     }
        !           454: 
        !           455:     /* Get a file descriptor for the connection. */
        !           456: 
        !           457:     saddr.sin_port = service->s_port;
        !           458:     sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr));
        !           459:     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
        !           460:     
        !           461: #ifdef EXCELAN
        !           462:     send_socket.sin_family = AF_INET;
        !           463:     send_socket.sin_addr.s_addr = 0;
        !           464:     send_socket.sin_port = 0;
        !           465:     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
        !           466:                &send_socket, SO_REUSEADDR)) < 0)
        !           467: #else
        !           468:     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        !           469: #endif /* EXCELAN */
        !           470:       {
        !           471: #ifdef EXCELAN
        !           472:        experror("TCP socket error");
        !           473: #else
        !           474: #ifdef MULTINET
        !           475:        socket_perror("TCP socket error");
        !           476:        debug(F101,"netopen socket error","",socket_errno);
        !           477: #else
        !           478:        perror("TCP socket error");
        !           479:        debug(F101,"netopen socket error","",errno);
        !           480: #endif /* MULTINET */
        !           481: #endif /* EXCELAN */
        !           482:        return (-1);
        !           483:     }
        !           484:     errno = 0;
        !           485: 
        !           486:     /* Now connect to the socket on the other end. */
        !           487: 
        !           488: #ifdef EXCELAN
        !           489:     if (connect(ttyfd, &saddr) < 0)
        !           490: #else
        !           491:     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
        !           492: #endif /* EXCELAN */
        !           493:       {
        !           494:        i = errno;                      /* save error code */
        !           495:        close(ttyfd);
        !           496:        ttyfd = -1;
        !           497:        errno = i;                      /* and report this error */
        !           498: #ifdef EXCELAN
        !           499:        if (errno) experror("netopen connect");
        !           500: #else
        !           501: #ifdef MULTINET
        !           502:        debug(F101,"netopen connect error","",socket_errno);
        !           503:        if (errno) socket_perror("netopen connect");
        !           504: #else
        !           505:        debug(F101,"netopen connect errno","",errno);
        !           506: #endif /* MULTINET */
        !           507: #endif /* EXCELAN */
        !           508:        return(-1);
        !           509:     }
        !           510: #ifdef SO_OOBINLINE
        !           511:     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); /* (void) */
        !           512:     /* the symbol SO_OOBINLINE is not known to Ultrix 2.0 */
        !           513:     /* it means "leave out of band data inline" */
        !           514:     /* normal value is 0x0100 */
        !           515:     /* better not to try this on systems where the symbol is undefined. */
        !           516: #endif /* SO_OOBINLINE */
        !           517: 
        !           518:     /* See if the service is TELNET. */
        !           519:     if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT)
        !           520:       ttnproto = NP_TELNET;            /* Yes, set global flag. */
        !           521:     debug(F101,"netopen service","",x);
        !           522:     ttnet = nett;                      /* TCP/IP (sockets) network */
        !           523:     tn_init = 0;                       /* Telnet protocol not init'd yet */
        !           524:     if (*lcl < 0) *lcl = 1;            /* Local mode. */
        !           525:     return(0);                         /* Done. */
        !           526: }
        !           527: 
        !           528: /*  N E T C L O S  --  Close current network connection.  */
        !           529: 
        !           530: int
        !           531: netclos() {
        !           532:     int x = 0;
        !           533:     if (ttyfd < 0)                     /* Was open? */
        !           534:       return(0);                       /* Wasn't. */
        !           535:     if (ttyfd > -1)                    /* Was. */
        !           536: #ifdef MULTINET
        !           537:       x = socket_close(ttyfd);         /* Close it. */
        !           538: #else
        !           539:       x = close(ttyfd);
        !           540: #endif /* MULTINET */
        !           541:     ttyfd = -1;                                /* Mark it as closed. */
        !           542:     tn_init = 0;                       /* Remember about telnet protocol... */
        !           543:     *ipaddr = '\0';                    /* Zero the IP address string */
        !           544:     return(x);
        !           545: }
        !           546: 
        !           547: /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
        !           548: /*
        !           549:   Returns number of bytes waiting, or -1 if connection has been dropped.
        !           550: */
        !           551: int                                    /* Check how many bytes are ready */
        !           552: nettchk() {                            /* for reading from network */
        !           553: #ifdef MULTINET
        !           554:     unsigned int count;
        !           555:     int x, y;
        !           556:     char c;
        !           557: 
        !           558:     socket_errno = 0;
        !           559: /*
        !           560:   Note: this socket_ioctl() call does NOT return an error if the
        !           561:   connection has been broken.
        !           562: */
        !           563:     if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) {
        !           564:        debug(F101,"nettchk socket_ioctl error","",socket_errno);
        !           565:        if (ttibn < 1) return(-1);
        !           566:        else return(ttibn);
        !           567:     } else {
        !           568:        if (count == 0) {
        !           569: /*
        !           570:   Here we need to tell the difference between a 0 count on an active
        !           571:   connection, and a 0 count because the remote end of the socket broke
        !           572:   the connection.  There is no mechanism in TGV MultiNet to query the
        !           573:   status of the connection, so we have to do a read.  -1 means there was
        !           574:   no data available (socket_errno == EWOULDBLOCK), 0 means the connection
        !           575:   is down.  But if, by chance, we actually get a character, we have to
        !           576:   put it where it won't be lost.
        !           577: */
        !           578:            y = 1;                      /* Turn on nonblocking reads */
        !           579:            socket_ioctl(ttyfd,FIONBIO,&y);
        !           580:            x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
        !           581:            y = 0;                      /* Turn them back off */
        !           582:            socket_ioctl(ttyfd,FIONBIO,&y);
        !           583:            if (x == 0) return(-1);     /* Connection is broken. */
        !           584:            if (x == 1) {               /* Oops, actually got a byte? */
        !           585:                ttibuf[ttibp+ttibn] = c;
        !           586:                ttibn++;                /* Add it to the buffer. */
        !           587:            }
        !           588:        }
        !           589:        debug(F101,"nettchk count","",count);
        !           590:        return(count + ttibn);
        !           591:     }  
        !           592: #else
        !           593: /*
        !           594:   Note, for regular UNIX TCP/IP connections, might be able to use the
        !           595:   same technique as for MultiNet.  But as yet there is no need for it.
        !           596: */
        !           597:     return(0);
        !           598: #endif /* MULTINET */
        !           599: }
        !           600: 
        !           601: /*  N E T T I N C --  Input character from network */
        !           602: 
        !           603: int                    
        !           604: netinc(timo) int timo; {
        !           605: #ifdef MULTINET
        !           606:     int x; unsigned char c;            /* The locals. */
        !           607: 
        !           608:     if (ttibn > 0) {                   /* Something in internal buffer? */
        !           609:        debug(F100,"netinc char in buf","",0); /* Yes. */
        !           610:        x = 0;                          /* Success. */
        !           611:     } else {                           /* Else must read from network. */
        !           612:        x = -1;                         /* Assume failure. */
        !           613:        debug(F101,"netinc goes to net, timo","",timo);
        !           614:        if (timo <= 0) {                /* Untimed case. */
        !           615:            while (1) {                 /* Wait forever if necessary. */
        !           616:                if (ttbufr() < 0)       /* Refill buffer. */
        !           617:                  break;                /* Error, fail. */
        !           618:                if (ttibn > 0) {        /* Success. */
        !           619:                    x = 0;
        !           620:                    break;
        !           621:                }
        !           622:            }
        !           623:        } else {                        /* Timed case... */
        !           624:            saval = signal(SIGALRM,ttimoff); /* Enable timer interrupt */
        !           625:            alarm(timo);                /* for requested interval. */
        !           626:            if (setjmp(njbuf)) {        /* Timer went off? */
        !           627:                x = -1;                 /* Yes, fail. */
        !           628:            } else {
        !           629:                while (1) {
        !           630:                    if (ttbufr() < 0)   /* Keep trying to refill it. */
        !           631:                      break;            /* Till we get an error. */
        !           632:                    if (ttibn > 0) {    /* Or we get a character. */
        !           633:                        x = 0;
        !           634:                        break;
        !           635:                    }
        !           636:                }
        !           637:            }
        !           638:            ttimoff();                  /* Timer off. */
        !           639:        }
        !           640:     }
        !           641:     if (x < 0) {                       /* Return -1 if we failed. */
        !           642:        debug(F100,"netinc timed out","",0);
        !           643:        return(-1);
        !           644:     } else {                           /* Otherwise */
        !           645:        ttibn--;                        /* Return what we got. */
        !           646:        c = ttibuf[ttibp++];
        !           647:        debug(F101,"netinc returning","",c);
        !           648:        return((c & 0xff));
        !           649:     }
        !           650: #else /* Not MULTINET */
        !           651:     return(-1);
        !           652: #endif /* MULTINET */
        !           653: }
        !           654: 
        !           655: /*  N E T T O L  --  Output a string of bytes to the network  */
        !           656: /*
        !           657:   Call with s = pointer to string, n = length.
        !           658:   Returns number of bytes actuall written on success, or
        !           659:   -1 on i/o error, -2 if called improperly.
        !           660: */
        !           661: int
        !           662: nettol(s,n) char *s; int n; {
        !           663: #ifdef MULTINET
        !           664:     int count;
        !           665:     if (ttnet == NET_TCPB) {
        !           666:        if ((count = socket_write(ttyfd,s,n)) < 1) {
        !           667:            debug(F101,"nettol socket_write error","",socket_errno);
        !           668:            return(-1);
        !           669:        }
        !           670:        debug(F111,"nettol socket_write",s,count);
        !           671:        return(count);
        !           672:     } else return(-2);
        !           673: #else
        !           674:     return(-2);
        !           675: #endif /* MULTINET */
        !           676: }
        !           677: 
        !           678: /*  N E T T O C  --   Output character to network */
        !           679: /*
        !           680:   Call with character to be transmitted.
        !           681:   Returns 0 if transmission was successful, or
        !           682:   -1 upon i/o error, or -2 if called improperly.
        !           683: */
        !           684: int                    
        !           685: #ifdef CK_ANSIC
        !           686: nettoc(char c)
        !           687: #else
        !           688: nettoc(c) char c;
        !           689: #endif /* CK_ANSIC */
        !           690: /* nettoc */ {
        !           691: #ifdef MULTINET
        !           692:     unsigned char cc;
        !           693:     cc = c;
        !           694:     if (ttnet == NET_TCPB) {
        !           695:        debug(F101,"nettoc cc","",cc);
        !           696:        if (socket_write(ttyfd,&cc,1) < 1) {
        !           697:            debug(F101,"nettoc socket_write error","",socket_errno);
        !           698:            return(-1);
        !           699:        }
        !           700:        debug(F101,"nettoc socket_write","", cc);
        !           701:        return(0);
        !           702:     } else return(-2);
        !           703: #else
        !           704:     return(-2);
        !           705: #endif /* MULTINET */
        !           706: }
        !           707: 
        !           708: /*  N E T F L U I  --  Flush network input buffer  */
        !           709: 
        !           710: int
        !           711: netflui() {
        !           712:     int n;
        !           713:     if ((n = nettchk()) > 0) {
        !           714: #ifdef MULTINET
        !           715:        char c;
        !           716:        if (ttnet == NET_TCPB)
        !           717:          while ((n--) && socket_read(ttyfd,&c,1) > 1) ;
        !           718: #endif /* MULTINET */
        !           719:     }
        !           720: #ifdef MULTINET
        !           721:     ttibn = ttibp = 0;                 /* Also flush internal buffer. */
        !           722: #endif /* MULTINET */
        !           723:     return(0);
        !           724: }
        !           725: 
        !           726: #ifdef TNCODE                          /* Compile in telnet support code */
        !           727: 
        !           728: /* TCP/IP Telnet negotiation support code */
        !           729: 
        !           730: static int sgaflg = 0;                 /* telnet SGA flag */
        !           731: static int wttflg = 0;                 /* telnet terminal type flag */
        !           732: 
        !           733: #ifndef TELCMDS
        !           734: char *telcmds[] = {
        !           735:     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
        !           736:     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC",
        !           737: };
        !           738: #endif /* TELCMDS */
        !           739: 
        !           740: #ifndef TELOPTS
        !           741: char *telopts[] = {
        !           742:        "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
        !           743:        "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
        !           744:        "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
        !           745:        "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
        !           746:        "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
        !           747:        "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD"
        !           748: #ifdef TELOPT_TUID
        !           749:        ,"TACACS UID"
        !           750: #ifdef TELOPT_OUTMRK
        !           751:        ,"OUTPUT MARKING"
        !           752: #ifdef TELOPT_TTYLOC
        !           753:        ,"TTYLOC"
        !           754: #ifdef TELOPT_3270REGIME
        !           755:        ,"3270 REGIME"
        !           756: #ifdef TELOPT_X3PAD
        !           757:        ,"X.3 PAD"
        !           758: #ifdef TELOPT_NAWS
        !           759:        ,"NAWS"
        !           760: #ifdef TELOPT_TSPEED
        !           761:        ,"TSPEED"
        !           762: #ifdef TELOPT_LFLOW
        !           763:        ,"LFLOW"
        !           764: #ifdef TELOPT_LINEMODE
        !           765:        ,"LINEMODE"
        !           766: #endif
        !           767: #endif
        !           768: #endif
        !           769: #endif
        !           770: #endif
        !           771: #endif
        !           772: #endif
        !           773: #endif
        !           774: #endif
        !           775: };
        !           776: #endif /* TELOPTS */
        !           777: 
        !           778: int ntelopts = sizeof(telopts) / sizeof(char *);
        !           779: #endif /* TNCODE */
        !           780: 
        !           781: 
        !           782: /* Send network BREAK */
        !           783: /*
        !           784:   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
        !           785: */
        !           786: int
        !           787: netbreak() {
        !           788:     if (ttnet == NET_TCPB) {
        !           789:        if (ttnproto == NP_TELNET) {
        !           790: #ifdef TNCODE
        !           791:            if (ttoc(IAC) < 0) return(-1);
        !           792:            if (ttoc(BREAK) < 0) return(-1);
        !           793:            debug(F101,"telnet BREAK ok","",BREAK);    
        !           794:            return(1);
        !           795: #else
        !           796:            debug(F100,"netbreak no TNCODE","",0);
        !           797:            return(0);
        !           798: #endif /* TNCODE */
        !           799:        }
        !           800:        /* Insert other TCP/IP protocols here */
        !           801:     }
        !           802:     /* Insert other networks here */
        !           803:     return(0);
        !           804: }
        !           805: 
        !           806: /* Send a telnet option, avoid loops. */
        !           807: /* Returns 1 if command was sent, 0 if not, -1 on error */
        !           808: 
        !           809: int
        !           810: tn_sopt(cmd,opt) int cmd, opt; {       /* TELNET SEND OPTION */
        !           811:     if (ttnet != NET_TCPB) return(0);  /* Must be TCP/IP */
        !           812:     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
        !           813: #ifdef TNCODE
        !           814:     if (ttoc(IAC) < 0)                 /* Send Interpret As Command (IAC) */
        !           815:       return(-1);
        !           816:     if (ttoc(cmd) < 0)                 /* Command (WILL, WONT, DO, DONT) */
        !           817:       return(-1);
        !           818:     if (ttoc(opt) < 0)                 /* Option */
        !           819:       return(-1);
        !           820:     debug(F111,"telnet cmd >",telcmds[cmd - SE],cmd);
        !           821:     debug(F111,"telnet opt >",
        !           822:          (opt < ntelopts) ? telopts[opt] : "UNKNOWN", opt );
        !           823:     if (debses && cmd != SB)
        !           824:       printf("[%s %s]",telcmds[cmd - SE],
        !           825:             (opt < ntelopts) ? telopts[opt] : "UNKNOWN");
        !           826:     return(1);
        !           827: #else
        !           828:     debug(F100,"tn_sopt no TNCODE","",0);
        !           829:     return(0);
        !           830: #endif /* TNCODE */
        !           831: }
        !           832: 
        !           833: /* Initialize a telnet connection. */
        !           834: /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
        !           835: 
        !           836: int
        !           837: tn_ini() {
        !           838: #ifndef TNCODE
        !           839:     debug(F100,"tn_ini no TNCODE","",0);
        !           840:     return(0);
        !           841: #else /* TELNET protocol support */
        !           842:     debug(F101,"tn_ini ttnproto","",ttnproto);
        !           843:     debug(F101,"tn_ini tn_init","",tn_init);
        !           844: 
        !           845:     if (ttnet != NET_TCPB)             /* Make sure connection is TCP/IP. */
        !           846:       return(0);
        !           847:     if (tn_init)                       /* Have we done this already? */
        !           848:       return(0);                       /* Don't do it again. */
        !           849:     duplex = 1;                                /* Assume local echo. */
        !           850:     sgaflg = 0;                                /* Assume Go-Ahead suppressed. */
        !           851:     wttflg = 0;                                /* Did not send WILL TERM TYPE yet. */
        !           852:     if (ttnproto == NP_NONE) {         /* If not talking to a telnet port, */
        !           853:        ttnproto = NP_TELNET;           /* pretend it's telnet anyway, */
        !           854:        tn_init = 1;                    /* but don't send initial options. */
        !           855:        debug(F100,"tn_ini skipping telnet negotiations","",0);
        !           856:        return(0);
        !           857:     }
        !           858:     /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */
        !           859: 
        !           860:     if (tn_sopt(WILL,TELOPT_TTYPE) < 0)        /* Will send terminal type. */
        !           861:       return(-1);
        !           862:     wttflg = 1;                                /* Remember I said I would. */
        !           863:     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
        !           864:       return(-1);
        !           865: #ifdef COMMENT
        !           866:     if (tn_sopt(DO,TELOPT_ECHO) < 0)   /* Ask the server to echo, since */
        !           867:       return(-1);                      /* I'm assuming it will. */
        !           868: #endif /* COMMENT */
        !           869:     tn_init = 1;                       /* Set telnet-initialized flag. */
        !           870: 
        !           871:     /* Don't send anthing else! */
        !           872: 
        !           873:     debug(F101,"tn_ini duplex","",duplex);
        !           874:     return(1);
        !           875: #endif /* TNCODE */
        !           876: }
        !           877: 
        !           878: /*
        !           879:   Process in-band Telnet negotiation characters from the remote host.
        !           880:   Call with the telnet IAC character and the current duplex setting
        !           881:   (0 = remote echo, 1 = local echo).
        !           882:   Returns:
        !           883:     3 if server has sent us a quoted IAC
        !           884:     2 if local echo must be changed to remote
        !           885:     1 if remote echo must be changed to local
        !           886:     0 if nothing happens or no action necessary
        !           887:    -1 on failure (= internal or i/o error)
        !           888: */
        !           889: 
        !           890: #define TSBUFSIZ 41
        !           891: char sb[TSBUFSIZ];                     /* Buffer for subnegotiations */
        !           892: 
        !           893: int
        !           894: #ifdef CK_ANSIC                                /* TELNET DO OPTION */
        !           895: tn_doop(CHAR z, int echo)
        !           896: #else
        !           897: tn_doop(z, echo) CHAR z; int echo;
        !           898: #endif /* CK_ANSIC */
        !           899: /* tn_doop */ {
        !           900:     int c, x, y, e, n, flag;
        !           901: 
        !           902: #ifndef TNCODE
        !           903:     debug(F100,"tn_doop no TNCODE","",0);
        !           904:     return(0);
        !           905: #else
        !           906:     if (z != IAC) {
        !           907:        debug(F101,"tn_doop bad call","",z);
        !           908:        return(-1);
        !           909:     }
        !           910:     if (ttnet != NET_TCPB) return(0);
        !           911:     if (ttnproto != NP_TELNET) return(0);      /* Check protocol */
        !           912: /*
        !           913:   This is a weakness.  Because this module uses ttinc(), it prevents any
        !           914:   code that uses this routine from using any kind of buffering strategy.
        !           915:   Also, there's no reason why this module should have to know anything about
        !           916:   the session log.  It would be better to pass a character input function as
        !           917:   an argument to this routine -- that function could worry about buffering,
        !           918:   logging, etc.
        !           919: */
        !           920: 
        !           921: /* Have IAC, read command character. */
        !           922: 
        !           923:     c = ttinc(0) & 0xff;               /* Read command character */
        !           924:     if (seslog) {                      /* Copy to session log, if any. */
        !           925:        if (zchout(ZSFILE,z) < 0) seslog = 0; /* Log the IAC. */
        !           926:        else if (zchout(ZSFILE,c) < 0) seslog = 0; /* Log the command. */
        !           927:     }
        !           928:     debug(F111,"telnet cmd <",telcmds[c - SE],c); /* Debug log. */
        !           929: 
        !           930:     if (c == IAC) return(3);           /* Quoted IAC */
        !           931:     if (c < SB) return(0);             /* Other command with no arguments. */
        !           932: 
        !           933: /* SB, WILL, WONT, DO, or DONT need more bytes... */
        !           934: 
        !           935:     if ((x = ttinc(0)) < 0) return(-1); /* Get the option. */
        !           936:     x &= 0xff;                         /* Trim to 8 bits. */
        !           937: 
        !           938:     debug(F111,"telnet opt <",
        !           939:          (x < ntelopts) ? telopts[x] : "UNKNOWN", x );
        !           940:     if (seslog)                                /* Session log */
        !           941:       if (zchout(ZSFILE,x) < 0) seslog = 0;
        !           942: 
        !           943:     /* Now handle the command */
        !           944: 
        !           945:     if (debses && c != SB)             /* Debug to screen. */
        !           946:       printf("<%s %s>",telcmds[c-SE],
        !           947:             (x < ntelopts) ? telopts[x] : "UNKNOWN" );
        !           948:     switch (x) {
        !           949:       case TELOPT_ECHO:                        /* ECHO negotiation. */
        !           950:        switch (c) {                    /* Command */
        !           951:          case WILL:                    /* Host says it will echo. */
        !           952:            if (echo)                   /* Only reply if change required. */
        !           953:              return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */
        !           954:            else return(0);             /* Otherwise no change. */
        !           955:          case WONT:                    /* Host says it won't echo. */
        !           956:            if (!echo)                  /* If I'm full duplex */
        !           957:              return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */
        !           958:            else return(0);             /* Otherwise, no change.  */
        !           959:          case DO:                      /* Host wants me to echo */
        !           960:            if (tn_sopt(WONT,x) < 0)    /* but the client never echoes */
        !           961:              return(-1);               /* back to the server. */
        !           962:          default:                      /* Don't reply to anything else */
        !           963:            return(0);
        !           964:        }
        !           965: 
        !           966:       case TELOPT_SGA:                 /* Suppress Go-Ahead */
        !           967:        switch (c) {                    /* Command... */
        !           968:          case WONT:                    /* Host says it won't. */
        !           969:            if (!sgaflg) {
        !           970:                sgaflg = 1;             /* Remember. */
        !           971:                if (tn_sopt(DONT,x) < 0) /* acknowledge, */
        !           972:                  return(-1);
        !           973:            }
        !           974:            return(echo ? 0 : 1);       /* Switch to half duplex */
        !           975:          case WILL:                    /* Server says it will SGA */
        !           976:            if (sgaflg) {               /* ACK only if necessary */
        !           977:                if (tn_sopt(DO,x) < 0)
        !           978:                  return(-1);
        !           979:                sgaflg = 0;             /* Remember new SGA state. */
        !           980:            }
        !           981:            return(0);                  /* But don't change echo state. */
        !           982:        }
        !           983: 
        !           984: #ifdef TELOPT_TTYPE
        !           985:       case TELOPT_TTYPE:               /* Terminal Type */
        !           986:        switch (c) {
        !           987:          case DO:                      /* DO terminal type. */
        !           988:            if (wttflg == 0) {          /* If I haven't said so before, */
        !           989:                if (tn_sopt(WILL,x) < 0) /* say I'll send it if asked. */
        !           990:                  return(-1);
        !           991:                wttflg++;
        !           992:            }
        !           993:            return(0);
        !           994:          case SB:
        !           995:            debug(F100,"telnet subnegotiation:","",0);
        !           996:            n = flag = 0;               /* Flag for when done reading SB */
        !           997:            while (n < TSBUFSIZ) {      /* Loop looking for IAC SE */
        !           998:                if ((y = ttinc(0)) < 0)
        !           999:                  return(-1);
        !          1000:                y &= 0xff;              /* Make sure it's just 8 bits. */
        !          1001:                sb[n++] = y;            /* Save what we got in buffer. */
        !          1002:                if (seslog)             /* Log it if logging. */
        !          1003:                  if (zchout(ZSFILE,y) < 0)
        !          1004:                    seslog = 0;
        !          1005:                if (y == IAC) {         /* If this is an IAC */
        !          1006:                    flag = 1;           /* set the flag. */
        !          1007:                } else {                /* Otherwise, */
        !          1008:                    if (flag && y == SE) /* if this is SE which immediately */
        !          1009:                      break;            /* follows IAC, we're done. */
        !          1010:                    else flag = 0;      /* Otherwise turn off flag. */
        !          1011:                }
        !          1012:                debug(F111,"telnet subopt <","",y);
        !          1013:                }
        !          1014:            if (!flag) return(-1);      /* Make sure we got a valid SB */
        !          1015:            if (debses) {               /* Debug to screen. */
        !          1016:                int i;
        !          1017:                printf("<SB %s ",telopts[TELOPT_TTYPE]);
        !          1018:                for (i = 0; i < n-2; i++) printf("%02x",sb[i]);
        !          1019:                printf(" IAC SE>");
        !          1020:            }       
        !          1021:            debug(F101,"telnet suboption","",sb[0]);
        !          1022:            if (sb[0] == 1) {           /* SEND terminal type? */
        !          1023:                if (tn_sttyp() < 0)     /* Yes, so send it. */
        !          1024:                  return(-1);
        !          1025:            }
        !          1026:          default:                      /* Others, ignore */
        !          1027:            return(0);
        !          1028:        }
        !          1029: #endif /* TELOPT_TTYPE */
        !          1030: 
        !          1031:       default:                         /* All others: refuse */
        !          1032:        switch(c) {
        !          1033:          case WILL:                    /* You will? */
        !          1034:            if (tn_sopt(DONT,x) < 0)    /* Please don't. */
        !          1035:              return(-1);
        !          1036:            break;
        !          1037:          case DO:                      /* You want me to? */
        !          1038:            if (tn_sopt(WONT,x) < 0)    /* I won't. */
        !          1039:              return(-1);
        !          1040:            break;
        !          1041:          case DONT:                    /* You don't want me to? */
        !          1042:            if (tn_sopt(WONT,x) < 0)    /* I won't. */
        !          1043:              return(-1);
        !          1044:          case WONT:                    /* You won't? */
        !          1045:            break;                      /* Good. */
        !          1046:          }
        !          1047:        return(0);
        !          1048:     }
        !          1049: #endif /* TNCODE */
        !          1050: }
        !          1051: 
        !          1052: /* Telnet send terminal type */
        !          1053: /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
        !          1054: 
        !          1055: int
        !          1056: tn_sttyp() {                           /* Send telnet terminal type. */
        !          1057: #ifndef TNCODE
        !          1058:     debug(F100,"tn_sttyp no TNCODE","",0);
        !          1059:     return(0);
        !          1060: #else
        !          1061:     char *ttn; int ttl;                        /* Name & length of terminal type. */
        !          1062: 
        !          1063:     if (ttnet != NET_TCPB) return(0);
        !          1064:     if (ttnproto != NP_TELNET) return(0);
        !          1065:     ttn = getenv("TERM");              /* Get it from the environment. */
        !          1066:     if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) {
        !          1067:        ttn = "UNKNOWN";
        !          1068:        ttl = 7;
        !          1069:     }
        !          1070:     strcpy(sb,ttn);                    /* Copy to subnegotiation buffer */
        !          1071:     ttn = sb;                          /* Point back to beginning */
        !          1072:     if (tn_sopt(SB,TELOPT_TTYPE) < 0)  /* Send: Terminal Type */
        !          1073:       return(-1);
        !          1074:     if (ttoc((char) 0))                        /* IS... */
        !          1075:       return(-1);
        !          1076:     while (*ttn) {                     /* name of terminal */
        !          1077:        if (islower(*ttn)) *ttn = toupper(*ttn); /* converted to uppercase. */
        !          1078:        ttoc(*ttn++);
        !          1079:     }
        !          1080:     if (ttoc(IAC) < 0)                 /* Terminate the subnegotiation. */
        !          1081:       return(-1);
        !          1082:     if (ttoc(SE) < 0)
        !          1083:       return(-1);
        !          1084:     debug(F111,"telnet SB sent ttype",sb,ttl);
        !          1085:     if (debses)                                /* Debug to screen. */
        !          1086:       printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb);
        !          1087:     return(1);
        !          1088: #endif /* TNCODE */
        !          1089: }
        !          1090: 
        !          1091: #ifdef SUNX25
        !          1092: /*
        !          1093:   SunLink X.25 support by Marcello Frutig, Catholic University,
        !          1094:   Rio de Janeiro, Brazil, 1990.
        !          1095: */
        !          1096: 
        !          1097: /* PAD X.3, X.28 and X.29 support */
        !          1098: 
        !          1099: static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
        !          1100: 
        !          1101: 
        !          1102: /* Initialize PAD */
        !          1103: 
        !          1104: extern CHAR padparms[MAXPADPARMS+1];
        !          1105: 
        !          1106: VOID
        !          1107: initpad() {
        !          1108:   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
        !          1109:   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
        !          1110:   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
        !          1111:   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
        !          1112:   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
        !          1113:   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
        !          1114:   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
        !          1115:   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
        !          1116:   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
        !          1117:   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
        !          1118:   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
        !          1119:   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
        !          1120:   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
        !          1121:   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
        !          1122:   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
        !          1123:   padparms[PAD_EDITING]                = 1;  /* can edit */
        !          1124:   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
        !          1125:   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
        !          1126:   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
        !          1127: }
        !          1128: 
        !          1129: 
        !          1130: /* Set PAD parameters */
        !          1131: 
        !          1132: VOID
        !          1133: setpad(s,n) CHAR *s; int n; {
        !          1134:     int i;
        !          1135:     CHAR *ps = s;
        !          1136: 
        !          1137:     for (i = 0; i < n; i++) {
        !          1138:         if (*ps > MAXPADPARMS)
        !          1139:          x29err[i+2] = *ps;
        !          1140:         else
        !          1141:          padparms[*ps] = *(ps+1);
        !          1142:         ps += 2;
        !          1143:     }
        !          1144: }
        !          1145: 
        !          1146: /* Read PAD parameters */
        !          1147: 
        !          1148: VOID
        !          1149: readpad(s,n,r) CHAR *s; int n; CHAR *r; {
        !          1150:     int i;
        !          1151:     CHAR *ps = s;
        !          1152:     CHAR *pr = r;
        !          1153:     
        !          1154:     *pr++ = X29_PARAMETER_INDICATION;
        !          1155:     for (i = 0; i < n; i++, ps++) {
        !          1156:          if (*ps > MAXPADPARMS) {
        !          1157:              x29err[i+2] = *ps++;
        !          1158:          } else {
        !          1159:              *pr++ = *ps;
        !          1160:              *pr++ = padparms[*ps++];
        !          1161:          }
        !          1162:     }
        !          1163: }
        !          1164: 
        !          1165: int
        !          1166: qbitpkt(s,n) CHAR *s; int n; {
        !          1167:     CHAR *ps = s;
        !          1168:     int x29cmd = *ps;
        !          1169:     CHAR *psa = s+1; 
        !          1170:     CHAR x29resp[(MAXPADPARMS*2)+1];
        !          1171: 
        !          1172:     switch (x29cmd) {
        !          1173: 
        !          1174:         case X29_SET_PARMS:
        !          1175:             setpad (ps+1,n/2);
        !          1176:             if ((int)strlen(x29err) > 2) {
        !          1177:                 ttol (x29err,(int)strlen(x29err));
        !          1178:                 x29err[2] = '\0';
        !          1179:             } 
        !          1180:             return (-2);
        !          1181:         case X29_READ_PARMS:
        !          1182:             readpad (ps+1,n/2,x29resp);
        !          1183:             setqbit ();
        !          1184:             ttol (x29resp,n+1);
        !          1185:             if ((int)strlen(x29err) > 2) {
        !          1186:                 ttol (x29err,(int)strlen(x29err));
        !          1187:                 x29err[2] = '\0';
        !          1188:             } 
        !          1189:             resetqbit();
        !          1190:             break;
        !          1191:         case X29_SET_AND_READ_PARMS:
        !          1192:             setpad (ps+1,n/2);
        !          1193:             readpad (ps+1,n/2,x29resp);
        !          1194:             setqbit();
        !          1195:             ttol (x29resp,n+1);
        !          1196:             if ((int)strlen(x29err) > 2) {
        !          1197:                 ttol (x29err,(int)strlen(x29err));
        !          1198:                 x29err [2] = '\0';
        !          1199:             }
        !          1200:             resetqbit();
        !          1201:             return (-2);
        !          1202:         case X29_INVITATION_TO_CLEAR:
        !          1203:             (VOID) x25clear();
        !          1204:             return (-1) ;
        !          1205:         case X29_INDICATION_OF_BREAK:
        !          1206:            break;
        !          1207:     }
        !          1208:     return (0);
        !          1209: }
        !          1210: 
        !          1211: /* PAD break action processor */
        !          1212: 
        !          1213: VOID
        !          1214: breakact() {
        !          1215:     extern char x25obuf[MAXOX25];
        !          1216:     extern int obufl;
        !          1217:     extern int active;
        !          1218:     extern unsigned char tosend;
        !          1219:     static CHAR indbrk[3] = {
        !          1220:        X29_INDICATION_OF_BREAK,
        !          1221:        PAD_SUPPRESSION_OF_DATA,
        !          1222:        1
        !          1223:     };
        !          1224:     CHAR intudat, cause, diag;
        !          1225: 
        !          1226:     if (x25stat() < 0) return(0);   /* Ignore if no virtual call established */
        !          1227: 
        !          1228:     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
        !          1229:         if (ttol(x25obuf,obufl) < 0) {
        !          1230:             perror ("\r\nCan't send characters");
        !          1231:             active = 0;
        !          1232:         } else {
        !          1233:             bzero (x25obuf,sizeof(x25obuf));
        !          1234:             obufl = 0;
        !          1235:             tosend = 0;
        !          1236:         };
        !          1237: 
        !          1238:     switch (padparms[PAD_BREAK_ACTION]) {
        !          1239: 
        !          1240:        case 0 : break;                 /* do nothing */
        !          1241:        case 1 : /* send interrupt packet with interrupt user data field = 1 */
        !          1242:                intudat = 1;
        !          1243:                 x25intr (intudat);
        !          1244:                 break;
        !          1245:        case 2 : /* send reset packet with cause and diag = 0 */
        !          1246:                cause = diag = 0;
        !          1247:                 x25reset (cause,diag); 
        !          1248:                 break;
        !          1249:        case 5 : /* send interrupt packet with interrupt user data field = 0 */
        !          1250:                intudat = 0;
        !          1251:                 x25intr (intudat) ;
        !          1252:                 setqbit ();
        !          1253:                /* send indication of break without a parameter field */
        !          1254:                 ttoc(X29_INDICATION_OF_BREAK);
        !          1255:                 resetqbit ();
        !          1256:                 break;
        !          1257:        case 8 : active = 0;            /* leave data transfer */
        !          1258:                 conol ("\r\n");
        !          1259:                 break;
        !          1260:        case 21: /* send interrupt packet with interrupt user data field = 0 */
        !          1261:                intudat = 0;
        !          1262:                 x25intr (intudat);
        !          1263:                 setpad (indbrk+1,2);   /* set pad to discard input */
        !          1264:                 setqbit ();
        !          1265:                /* send indication of break with parameter field */
        !          1266:                 ttol (indbrk,sizeof(indbrk)); 
        !          1267:                 resetqbit ();
        !          1268:                 break;
        !          1269:      }
        !          1270: }
        !          1271: 
        !          1272: /* X.25 support functions */
        !          1273: 
        !          1274: X25_CAUSE_DIAG diag;
        !          1275: 
        !          1276: /*
        !          1277:   Convert a null-terminated string representing an X.121 address
        !          1278:   to a packed BCD form.
        !          1279: */
        !          1280: 
        !          1281: int
        !          1282: pkx121(str,bcd) char *str; CHAR *bcd; {
        !          1283:     int i, j;
        !          1284:     u_char c;
        !          1285: 
        !          1286:     i = j = 0;
        !          1287:     while (str[i]) {
        !          1288:         if ( i >= 15 || str [i] < '0' || str [i] > '9' )
        !          1289:          return (-1);
        !          1290:         c = str [i] - '0';
        !          1291:         if ( i & 1 )
        !          1292:          bcd [j++] |= c;
        !          1293:         else
        !          1294:          bcd [j] = c << 4;  
        !          1295:         i++;
        !          1296:     }
        !          1297:     return (i);
        !          1298: }
        !          1299: 
        !          1300: /* Reads and prints X.25 diagnostic */
        !          1301: 
        !          1302: int
        !          1303: x25diag () {
        !          1304:     int i;
        !          1305: 
        !          1306:     bzero ((char *)&diag,sizeof(diag));
        !          1307:     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
        !          1308:         perror ("Reading X.25 diagnostic");
        !          1309:         return(-1); 
        !          1310:     }
        !          1311:     if (diag.datalen > 0) {
        !          1312:         printf ("X.25 Diagnostic :");
        !          1313:         for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]);
        !          1314:         printf ("\r\n");
        !          1315:     }
        !          1316:     return(0);
        !          1317: }
        !          1318: 
        !          1319: /* X.25 Out-of-Band Signal Handler */
        !          1320: 
        !          1321: VOID
        !          1322: x25oobh() {
        !          1323:     int oobtype;
        !          1324:     u_char oobdata;
        !          1325: 
        !          1326:     (VOID) signal(SIGURG,x25oobh);
        !          1327:     do {
        !          1328:         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
        !          1329:             perror ("Getting signal type");
        !          1330:             return;
        !          1331:         }
        !          1332:         switch (oobtype) {
        !          1333:          case INT_DATA:
        !          1334:            if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) {
        !          1335:                perror ("Receiving X.25 interrupt data");
        !          1336:                return;
        !          1337:            }
        !          1338:            printf ("\r\nInterrupt received, data = %d\r\n", oobdata);
        !          1339:            break;
        !          1340:          case VC_RESET:
        !          1341:            printf ("\r\nVirtual circuit reset\r\n");
        !          1342:            x25diag ();
        !          1343:            break;
        !          1344:          case N_RESETS:
        !          1345:            printf ("\r\nReset timeout\r\n");
        !          1346:            break;
        !          1347:          case N_CLEARS:
        !          1348:            printf ("\r\nClear timeout\r\n");
        !          1349:            break;
        !          1350:          case MSG_TOO_LONG:
        !          1351:            printf ("\r\nMessage discarded, too long\r\n");
        !          1352:            break;
        !          1353:          default:
        !          1354:            if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
        !          1355:            break;
        !          1356:        }
        !          1357:     } while (oobtype);
        !          1358: }
        !          1359: 
        !          1360: /* Send a X.25 interrupt packet */
        !          1361: 
        !          1362: int
        !          1363: #ifdef CK_ANSIC
        !          1364: x25intr(char intr)
        !          1365: #else
        !          1366: x25intr(intr) char intr;
        !          1367: #endif /* CK_ANSIC */
        !          1368: /* x25intr */ {
        !          1369:     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
        !          1370:     debug(F100,"X.25 intr","",0);
        !          1371:     return(0);
        !          1372: }
        !          1373: 
        !          1374: /* Reset X.25 virtual circuit */
        !          1375: int
        !          1376: #ifdef CK_ANSIC
        !          1377: x25reset(char cause, char diagn)
        !          1378: #else
        !          1379: x25reset(cause, diagn) char cause; char diagn;
        !          1380: #endif /* CK_ANSIC */
        !          1381: /* x25reset */ {
        !          1382:     bzero ((char *)&diag,sizeof(diag));
        !          1383:     diag.flags   = 0;
        !          1384:     diag.datalen = 2;
        !          1385:     diag.data[0] = cause;
        !          1386:     diag.data[1] = diagn;
        !          1387:     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
        !          1388:       return(-1);
        !          1389:     debug(F100,"X.25 reset","",0);
        !          1390:     return(0);
        !          1391: }
        !          1392: 
        !          1393: /* Clear X.25 virtual circuit */
        !          1394: int
        !          1395: x25clear() {
        !          1396:     int i;
        !          1397:     debug(F100,"X.25 clear","",0);
        !          1398:     bzero ((char *)&diag,sizeof(diag));
        !          1399:     diag.flags = (1 << DIAG_TYPE);
        !          1400:     diag.datalen = 2;
        !          1401:     diag.data[0] = 0;
        !          1402:     diag.data[1] = 0;
        !          1403:     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
        !          1404:     return(ttclos(0));                 /* Close socket */
        !          1405: }
        !          1406: 
        !          1407: /* X.25 status */
        !          1408: int
        !          1409: x25stat() {
        !          1410:     if (ttyfd < 0) return (-1);
        !          1411:     return(0);
        !          1412: }
        !          1413: 
        !          1414: /* Set Q_BIT on */
        !          1415: VOID
        !          1416: setqbit() {
        !          1417:     static int qbiton = 1 << Q_BIT;
        !          1418:     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
        !          1419: }
        !          1420: 
        !          1421: /* Set Q_BIT off */
        !          1422: VOID
        !          1423: resetqbit() {
        !          1424:     static int qbitoff = 0;
        !          1425:     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
        !          1426: }
        !          1427: 
        !          1428: /* Read n characters from X.25 circuit into buf */
        !          1429: 
        !          1430: int
        !          1431: x25xin(n,buf) int n; CHAR *buf; {
        !          1432:     register int x, c;
        !          1433:     int qpkt;
        !          1434: 
        !          1435:     do {
        !          1436:        x = read(ttyfd,buf,n);
        !          1437:        if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
        !          1438:            /* If return -1 : invitation to clear; -2 : PAD changes */
        !          1439:            if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
        !          1440:            qpkt = 1;
        !          1441:        } else qpkt = 0;
        !          1442:     } while (qpkt);
        !          1443:     if (x > 0) buf[x] = '\0';
        !          1444:     if (x < 0) x = -1;
        !          1445:     return(x);
        !          1446: }
        !          1447: 
        !          1448: /* X.25 read a line */
        !          1449: 
        !          1450: int
        !          1451: #ifdef PARSENSE
        !          1452: #ifdef CK_ANSIC
        !          1453: x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
        !          1454: #else
        !          1455: x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
        !          1456: #endif /* CK_ANSIC */
        !          1457: #else /* not PARSENSE */
        !          1458: #ifdef CK_ANSIC
        !          1459: x25inl(CHAR *dest, int max,int timo, CHAR eol)
        !          1460: #else
        !          1461: x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
        !          1462: #endif /* __SDTC__ */
        !          1463: #endif /* PARSENSE */
        !          1464: /* x25inl */ {
        !          1465:     CHAR *pdest;
        !          1466:     int pktype, goteol, rest, n;
        !          1467:     int i, flag = 0;
        !          1468:     extern int ttprty;
        !          1469:     int ttpmsk;
        !          1470:         
        !          1471:     ttpmsk = (ttprty) ? 0177 : 0377;   /* Set parity stripping mask */
        !          1472: 
        !          1473:     debug(F101,"x25inl max","",max);
        !          1474:     debug(F101,"x25inl eol","",eol);
        !          1475:     pdest  = dest;
        !          1476:     rest   = max;
        !          1477:     goteol = 0;
        !          1478:     do {
        !          1479:        n = read(ttyfd,pdest,rest); 
        !          1480:        n--;
        !          1481:        pktype = *pdest & 0x7f;
        !          1482:        switch (pktype) {
        !          1483:          case 1 << Q_BIT:
        !          1484:            if (qbitpkt(pdest+1,--n) < 0) return(-2);
        !          1485:            break;
        !          1486:          default:
        !          1487:            if (flag == 0) { /* if not in packet, search start */
        !          1488:                for (i = 1; (i < n) &&
        !          1489:                     !(flag = ((dest[i] & 0x7f) == start));
        !          1490:                     i++);
        !          1491:                if (flag == 0) { /* not found, discard junk */
        !          1492:                    debug(F101,"x25inl skipping","",n);
        !          1493:                    continue;
        !          1494:                } else {                /* found, discard junk before start */
        !          1495:                    int k;
        !          1496:                    n = n - i + 1;
        !          1497:                    for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
        !          1498:                }
        !          1499:            }
        !          1500:            for (i = 0; (i < n) && /* search for eol */
        !          1501:                 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
        !          1502:                 i++,pdest++);
        !          1503:            *pdest = '\0';
        !          1504:            rest -= n;
        !          1505:        }
        !          1506:     } while ( (rest > 0) && (!goteol) );
        !          1507: 
        !          1508:     if (goteol) {
        !          1509:        n = max - rest;
        !          1510:        debug (F111,"ttinl X.25 got",(char *) dest,n);
        !          1511:        if (timo) ttimoff();
        !          1512:        if (ttprty == 0) {
        !          1513:            if ((ttprty = parchk(dest,start,n)) > 0) {
        !          1514:                int j;
        !          1515:                debug(F101,"ttinl senses parity","",ttprty);
        !          1516:                debug(F110,"ttinl packet before",(char *)dest,0);
        !          1517:                ttpmsk = 0x7f;
        !          1518:                for (j = 0; j < n; j++)
        !          1519:                  dest[j] &= 0x7f; /* Strip parity from packet */
        !          1520:                debug(F110,"ttinl packet after ",dest,0);
        !          1521:            } else {
        !          1522:                debug(F101,"parchk","",ttprty);
        !          1523:                if (ttprty < 0) { ttprty = 0; n = -1; }
        !          1524:            }
        !          1525:        }
        !          1526:        ttimoff();
        !          1527:        return(n);
        !          1528:     }
        !          1529:     ttimoff();
        !          1530:     return(-1);
        !          1531: }
        !          1532: #endif /* SUNX25 */
        !          1533: 
        !          1534: #endif /* NETCONN */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.