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

  1. char *ckxv = "OS-9 Communications I/O, 7.1.019, 24 Jul 2000";
  2.  
  3. /*  C K 9 T I O  */
  4.  
  5. /* C-Kermit interrupt, terminal control & i/o functions for os9/68k systems */
  6.  
  7. /*
  8.  Author: Peter Scholz
  9.  Ruhr University Bochum, Department of analytical chemistry
  10.  Federal Republic of Germany, February 1987
  11.  
  12.  Bob Larson (Blarson@ecla.usc.edu)
  13.  Cleanup, fix timeouts, fix connect escape
  14.  Rewrite ttinl for less overhead
  15.  
  16.  Edition: 5A(01)
  17.  Chris Hemsing (Chris@lfm.rwth-aachen.de)
  18.  Cleaned up timed i/o using F$Alarm
  19.  Tmode/Xmode stuff
  20.  Send break stuff
  21.  All time related stuff new
  22.  
  23.  07/25/91 Chris  Hemsing        minor bug fixes, changes for gnu (ansi) C
  24.  
  25.  12/02/91 Bob Larson    Blarson@usc.edu
  26.         alarm() code was a nice idea, but doesn't work.  Fixed back to
  27.         code that will interupt i/o in progress. Minor cleanup.
  28.         Retrofited current unix myread() code to speed things back up.
  29.  
  30.  01/14/92 Chris  Hemsing        minor xmode bug fixes, sigmask <->longjump
  31.                                 OS-9 does interrupt i/o, but bad drivers don't
  32.                                 -> alarm code not reintroduced.
  33.  Edition: 5A(05)
  34.           Bob Larson            conchk bug fix
  35.  Edition: 5A(06)
  36.  03/04/92 Chris  Hemsing        ttopen: dup(0) fix, compare upper case
  37.  Edition: 5A(07)
  38.  09/28/92 Chris  Hemsing        cccbrk bug fix
  39.  Edition: 5A(08)
  40.  10/12/92 Chris  Hemsing        improved CTRL-E handling (catch)
  41.  Edition: 5A(09)
  42.  12/09/93 ?                     added TRANSFER CANCELLATION variables
  43.  Edition: 5A(10)
  44.  12/23/94 Ulli Schlueter        improved performance (system load is reduced
  45.                                 about 80% on my system (68020, 25MHz) with the
  46.                                 little sleep in myread():achieved an efficiency
  47.                                 of 96% in a system transfer loop (two kermits
  48.                                 running on the same system) with all characters
  49.                                 unprefixed and a packet size of 2K at 19200),
  50.                                 fixed xfrnum bug and brought ttinl() near to
  51.                                 the unix version, added support of CK_REDIR,
  52.                                 added O_GOODRIVER compilation flag for
  53.                                 carefully written drivers (add or remove it
  54.                                 in the makefile)
  55.  Edition: 5A(11)
  56.  01/26/95 Ulli Schlueter        network support
  57.  Edition: 5A(12)
  58.  03/20/95 Ulli Schlueter        ttopen() accepts `/nil'
  59.  Edition: 5A(13)
  60.  04/21/95 Ulli Schlueter        tthang() has called netclos() and so the
  61.                                 event was not deleted
  62.  Edition: 5A(14)
  63.  04/25/95 Ulli Schlueter        Changed network ttopen() (event creation).
  64.  Edition: 5A(15)
  65.  06/20/95 Ulli Schlueter        Added MORE_DYNAMIC (not enabled), removed
  66.                                 `dfttystr[]'.
  67.  Edition: 5A(16)
  68.  28 May 99 Martin Whitaker    Added ttgwsiz().
  69.  31 May 99 Martin Whitaker    Removed declaration of ttnproto for non-
  70.                 networked versions - this is in ckcnet.c.
  71.  22 Jan 2000 Steve Rance & Frank da Cruz: Adapt to Ultra C; fix warnings, etc.
  72.  24 Jul 2000 fdc                Get username in sysinit(), add whoami().
  73.  
  74.  Adapted from UNIX C-Kermit ckutio.c.
  75.  Author: Frank da Cruz <fdc@columbia.edu>
  76.  
  77.  Copyright (C) 1985, 2000,
  78.    Trustees of Columbia University in the City of New York.
  79.    All rights reserved.  See the C-Kermit COPYING.TXT file or the
  80.    copyright text in the ckcmai.c module for disclaimer and permissions.
  81. */
  82. #include <dir.h>            /* Directory */
  83. #ifdef NULL
  84. #undef NULL
  85. #endif /* NULL */
  86. #ifndef GREGORIAN
  87. #define GREGORIAN 0
  88. #define JULIAN 1
  89. #endif
  90. #include <signal.h>            /* Interrupts */
  91. #include <errno.h>
  92.  
  93. #ifndef EOS_DEVBSY
  94. #ifdef E_DEVBSY
  95. #define EOS_DEVBSY E_DEVBSY
  96. #endif /* E_DEVBSY */
  97. #endif /* EOS_DEVBSY */
  98.  
  99. #ifndef EOS_SHARE
  100. #ifdef E_SHARE
  101. #define EOS_SHARE E_SHARE
  102. #endif /* E_SHARE */
  103. #endif /* EOS_SHARE */
  104.  
  105. #ifndef EOS_READ
  106. #ifdef E_READ
  107. #define EOS_READ E_READ
  108. #endif /* E_READ */
  109. #endif /* EOS_READ */
  110.  
  111. #ifndef EOS_UNKSVC
  112. #ifdef E_UNKSVC
  113. #define EOS_UNKSVC E_UNKSVC
  114. #endif /* E_UNKSVC */
  115. #endif /* EOS_UNKSVC */
  116.  
  117. #include <sgstat.h>            /* Set/Get tty modes */
  118. #include <sg_codes.h>            /* setstat/getstat function codes */
  119. #include <setsys.h>
  120. #include <setjmp.h>
  121. #include <strings.h>
  122. #include <time.h>
  123. #include <modes.h>            /* osk i/o modes S_IREAD, etc */
  124. #include "ckcsym.h"
  125. #include "ckcdeb.h"            /* Typedefs, formats for debug() */
  126. #include "ckcnet.h"
  127.  
  128. /* Maximum length for the name of a tty device */
  129.  
  130. #ifndef DEVNAMLEN
  131. #define DEVNAMLEN MAXNAMLEN*4+2 /* leave room for / and terminating \0 */
  132. #endif                          /* not really an OS-9 restriction */
  133.                                 /* *4 is arbitrary */
  134.                                 /* nfm getstat call bug: SS_DevNm always
  135.                                    copies all 32 bytes, nfm does the first
  136.                                    part of the name => sum is more than
  137.                                    32 bytes
  138.                                    e.g "term": all fine
  139.                                    because 32 bytes incl. "term" are copied
  140.                                    "n0/node1/term":  "n0/node1/" done by nfm
  141.                                    "term" is done by remote's scf
  142.                                    (32 bytes) */
  143. char *ckxsys = " OS-9/68000";
  144.  
  145. #define MYREAD                  /* use improved input code */
  146.                                 /* Warning: untested without this defiend */
  147.  
  148. /*
  149.    For drivers that interrupt I/O when signal code is less than S_DEADLY
  150. */
  151. #ifndef O_GOODDRIVER
  152. /*#define O_GOODDRIVER let's do it in the command line */
  153. #endif /* !O_GOODDRIVER */
  154.  
  155. /*
  156.  Variables available to outside world:
  157.  
  158.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  159.    dfloc  -- 0 if dftty is console, 1 if external line.
  160.    dfprty -- Default parity
  161.    dfflow -- Default flow control
  162.    ckxech -- Flag for who echoes console typein:
  163.      1 - The program (system echo is turned off)
  164.      0 - The system (or front end, or terminal).
  165.    functions that want to do their own echoing should check this flag
  166.    before doing so.
  167.  
  168.  Functions for assigned communication line (either external or console tty):
  169.  
  170.    syscleanup()            -- System dependent shutdown
  171.    sysinit()               -- System dependent program initialization
  172.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  173.    ttclos()                -- Close & reset the tty.
  174.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  175.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  176.     or in DIALING or CONNECTED modem control state.
  177.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  178.    ttinc(timo)             -- Timed read character from tty.
  179.    myread()                -- Raw mode bulk buffer read, gives subsequent
  180.                                 chars one at a time and simulates FIONREAD.
  181.    myunrd(c)               -- Places c back in buffer to be read (one only)
  182.    ttchk()                 -- See how many characters in tty input buffer.
  183.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  184.    ttol(string,length)     -- Write a string to the tty.
  185.    ttoc(c)                 -- Write a character to the tty.
  186.    ttflui()                -- Flush tty input buffer.
  187.  */
  188.  
  189. /*
  190. Functions for console terminal:
  191.  
  192.    congm()   -- Get console terminal modes.
  193.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  194.    conbin(esc) -- Put the console in binary (raw) mode.
  195.    conres()  -- Restore the console to mode obtained by congm().
  196.    conoc(c)  -- Unbuffered output, one character to console.
  197.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  198.    conola(s) -- Unbuffered output, array of strings to the console.
  199.    conxo(n,s) -- Unbuffered output, n characters to the console.
  200.    conchk()  -- Check if characters available at console (bsd 4.2).
  201.   Check if escape char (^\) typed at console (System III/V).
  202.    coninc(timo)  -- Timed get a character from the console.
  203.    conint()  -- Enable terminal interrupts on the console if not background.
  204.    connoi()  -- Disable terminal interrupts on the console if not background.
  205.  
  206. Time functions
  207.  
  208.    msleep(m) -- Millisecond sleep
  209.    ztime(s) -- Return date/time string
  210.    rtimer() --  Reset timer
  211.    gtimer()  -- Get elapsed time since last call to rtimer()
  212. */
  213.  
  214. /* Declarations */
  215.  
  216. int myfillbuf();
  217.  
  218. extern int errno;            /* System call error return */
  219. extern char uidbuf[];
  220.  
  221. /* dftty is the device name of the default device for file transfer */
  222. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  223.  
  224.     char *dftty;        /* Remote by default, use normal */
  225.     int dfloc = 0;      /* controlling terminal name. */
  226.  
  227.     int dfprty = 0;     /* Parity (0 = none) */
  228.     int ttprty = 0;     /* current parity */
  229.     int ttpflg = 0;     /* Parity not sensed yet */
  230.     static int ttpmsk = 0377;           /* Parity stripping mask. */
  231.     int ttmdm = 0;      /* Modem in use */
  232.     int dfflow = 1;     /* Xon/Xoff flow control */
  233.     int backgrd = 0;    /* Assume in foreground (no '&' ) */
  234.  
  235.     int ckxech = 0;     /* 0 if system normally echoes console characters, else
  236.  1 */
  237.  
  238.     int ttyfd = -1;    /* TTY path number, also used in ck9con.c */
  239.  
  240.     int ttcarr = CAR_AUT;               /* Carrier handling mode. */
  241.  
  242. #ifdef NETCONN
  243. extern int ttnproto;                    /* Defined in ckcnet.c */
  244. extern int ttnet;                       /* Defined in ckcnet.c */
  245. #endif /* NETCONN */
  246. extern int xfrcan, xfrchr, xfrnum;      /* Defined in ckcmai.c */
  247.  
  248. int csigflg, tsigflg; /* console/tty signal flags (incremented by catch()) */
  249.  
  250. /* Declarations of variables global within this module */
  251.  
  252. static char ttnmsv[DEVNAMLEN];   /* always name of ttyfd device */
  253. char myttystr[DEVNAMLEN];
  254. static int
  255.     xlocal = 0;    /* Flag for tty local or remote */
  256.  
  257. #ifdef NETCONN
  258. static int netconn = 0;  /* 1 if network connection active */
  259. static char ttevnm[12];
  260. int ttevid;
  261. #endif /* NETCONN */
  262.  
  263. static struct sgbuf      /* sgtty info... */
  264. #ifndef MORE_DYNAMIC
  265.   ttold, ttraw, tttvt,   /* for communication line */
  266.   ccold, ccraw, cccbrk;  /* and for console */
  267. #else /* MORE_DYNAMIC */
  268.   *ttold_, *ttraw_, *tttvt_,   /* for communication line */
  269.   *ccold_, *ccraw_, *cccbrk_;  /* and for console */
  270. #define ttold (*ttold_)
  271. #define ttraw (*ttraw_)
  272. #define tttvt (*tttvt_)
  273. #define ccold (*ccold_)
  274. #define ccraw (*ccraw_)
  275. #define cccbrk (*cccbrk_)
  276. #endif /* MORE_DYNAMIC */
  277.  
  278. static time_t   tcount;   /* Elapsed time counter */
  279. static time_t   timowhen; /* timeout time */
  280.  
  281. static SIGTYP (*saval)() = NULL;                /* For saving alarm handler */
  282. static jmp_buf sjbuf;                   /* Longjump buffers */
  283. static SIGTYP timerh();
  284.  
  285. #define B50     0
  286. #define B75     1
  287. #define B110    2
  288. #define B134    3
  289. #define B150    4
  290. #define B300    5
  291. #define B600    6
  292. #define B1200   7
  293. #define B1800   8
  294. #define B2000   9
  295. #define B2400  10
  296. #define B3600  11
  297. #define B4800  12
  298. #define B7200  13
  299. #define B9600  14
  300. #define B19200 15
  301. #define B38400 16
  302.  
  303. static unsigned short bdrts[] = {
  304.         50, 75, 110, 134, 150, 300, 600, 1200,
  305.         1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200, 38400
  306. };
  307.  
  308. /* for unix signal emulation */
  309.  
  310. #define MAXSIG 4
  311. typedef VOID (*fptr)();
  312. fptr sigtbl[MAXSIG+1];
  313. fptr signal();
  314.  
  315. syscleanup() {
  316.     return 0;                   /* none needed */
  317. }
  318.  
  319. /*  S Y S I N I T  --  System-dependent program initialization.  */
  320.  
  321. sysinit() {
  322. /* initialize unix signal emulation */
  323.     register int i;
  324.     register char *cp;
  325.     VOID catch();
  326.     char *getenv(), *s;
  327.  
  328.     for(i = 0; i <= MAXSIG; i++)
  329.       sigtbl[i] = SIG_DFL;
  330.     intercept(catch);
  331.     if(isatty(0)) {             /* must disable buffering before io */
  332.         setbuf(stdin,(char *)NULL);
  333.         setbuf(stdout,(char *)NULL);
  334.     }
  335.     /* get terminal name from enviornment variable PORT,
  336.      * use device of stderr as a backup
  337.      */
  338.     myttystr[0] = '/';
  339.     if((cp = getenv("PORT")) == NULL) {
  340.         if(_gs_devn(2, myttystr+1) < 0) return -1;
  341.     } else
  342.       strncpy(myttystr, cp, DEVNAMLEN);
  343.     dftty = &myttystr[0];
  344.     backgrd = (isatty(0) && isatty(1)) ? 0 : 1;
  345. #ifdef MORE_DYNAMIC
  346.     if ((cp = malloc(sizeof ttold + sizeof ttraw + sizeof tttvt
  347.              + sizeof ccold + sizeof ccraw + sizeof cccbrk)
  348.      ) == NULL)
  349.       return -1;
  350.     ttold_ = (void *)cp;
  351.     ttraw_ = ttold_ + 1;
  352.     tttvt_ = ttraw_ + 1;
  353.     ccold_ = tttvt_ + 1;
  354.     ccraw_ = ccold_ + 1;
  355.     cccbrk_ = ccraw_ + 1;
  356. #endif /* MORE_DYNAMIC */
  357.  
  358.     s = getenv("USER");
  359.     if (!s) s = getenv("LOGNAME");
  360.     if (s)
  361.       strncpy(uidbuf,s,UIDBUFLEN);
  362.     else
  363.       uidbuf[0] = '\0';
  364.  
  365.     congm();
  366.     return 0;
  367. }
  368.  
  369. char *
  370. whoami() {
  371.     return((char *)uidbuf);
  372. }
  373.  
  374.  
  375. /*  T T O P E N  --  Open a tty for exclusive access.  */
  376.  
  377. /*
  378.   Call with:
  379.     ttname: character string - device name or network host name.
  380.     lcl:
  381.   If called with lcl < 0, sets value of lcl as follows:
  382.   0: the terminal named by ttname is the job's controlling terminal.
  383.   1: the terminal named by ttname is not the job's controlling terminal.
  384.   But watch out: if a line is already open, or if requested line can't
  385.   be opened, then lcl remains (and is returned as) -1.
  386.     modem:
  387.   Less than zero: ttname is a network host name.
  388.   Zero or greater: ttname is a terminal device name.
  389.   Zero means a local connection (don't use modem signals).
  390.   Positive means use modem signals.
  391.    timo:
  392.   0 = no timer.
  393.   nonzero = number of seconds to wait for open() to return before timing out.
  394.  
  395.   Returns:
  396.     0 on success
  397.    -5 if device is in use
  398.    -4 if access to device is denied
  399.    -3 if access to lock directory denied
  400.    -2 upon timeout waiting for device to open
  401.    -1 on other error
  402. */
  403.  
  404. int
  405. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  406.  
  407. char dev_buffer[DEVNAMLEN];
  408.     debug(F111,"ttopen entry modem",ttname,modem);
  409.     debug(F101," ttyfd","",ttyfd);
  410.     debug(F101," lcl","",*lcl);
  411.  
  412.     if (ttyfd > -1)             /* if device already opened */
  413.     {
  414.         if (ustrncmp(ttname,ttnmsv,DEVNAMLEN))/* are new & old names equal? */
  415.                                               /* compare ignoring case */
  416.           ttclos(0);                    /* no, close old ttname, open new */
  417.         else                            /* else same, ignore this call, */
  418.           return(0);                    /* and return. */
  419.     }
  420.  
  421. #ifdef  NETCONN
  422.     if (modem < 0) {                    /* modem < 0 = special code for net */
  423.         int x;
  424.         ttmdm = modem;
  425.         modem = -modem;                 /* Positive network type number */
  426.         /*fdflag = 0;*/                     /* Stdio not redirected. */
  427.         netconn = 1;                    /* And it's a network connection */
  428.         debug(F111,"ttopen net",ttname,modem);
  429.         x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
  430.         if (x >= 0) {
  431.             strncpy(ttnmsv,ttname,DEVNAMLEN);
  432.             sprintf(ttevnm, "cktn%d", getpid());
  433.             if ((x = _ev_creat(0, -1, -1, ttevnm)) == -1) {
  434.                 debug(F101, "ttopen ev_creat errno", "", errno);
  435.             }
  436.             else if ((x = _ss_sevent(ttyfd, ttevid = x)) == -1) {
  437.                 debug(F101, "ttopen sevent errno", "", errno);
  438.             }
  439. #if 0
  440.             else if (_gs_opt(ttyfd, &ttold) != -1) {
  441.                 if (ttold.sg_class == DT_SOCK) {
  442.                     ttold.sg_noblock = 0;
  443.                     if (_ss_opt(ttyfd, &ttold) != -1)
  444.                       debug(F100, "ttopen sockio blocking", "", 0);
  445.                 }
  446.             }
  447. #endif /* 0 */
  448.             if (x == -1) ttclos(0); /* Let ttclos do the clean up */
  449.         } else {
  450.             netconn = 0;
  451.         }
  452.  
  453.  
  454.         xlocal = *lcl = 1;              /* Network connections are local. */
  455.         debug(F101,"ttopen net x","",x);
  456.         return(x);
  457.     }
  458. #endif /* NETCONN */
  459.  
  460.     if (timo < 0) timo = 0;             /* Safety */
  461.     if (setjmp(sjbuf))                  /* Timer went off? */
  462.     {
  463.         debug(F100,"ttopen timout","",0); /*    Get here on timeout. */
  464.         return(-2);                     /* and return error code. */
  465.     }
  466.     else
  467.     {
  468.         if (timo)
  469.         {                           /* Don't time out if timo == 0 */
  470.             /* This won't work, since alarm() will not interupt i/o. */
  471.             /* Unfortunatatly, there is no non-blocking open to replace */
  472.             /* it with.   blarson@usc.edu */
  473.             /* Alarm will interrupt i/o when using a proper driver that */
  474.             /* checks for pending signals smaller than deadly */
  475.             /* chris@lfm.rwth-aachen.de */
  476.             saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
  477.             alarm((unsigned int)timo);                      /* Set it. */
  478.         }
  479.         strncpy(ttnmsv,ttname,DEVNAMLEN); /* keep ttnmsv corresp. to ttyfd */
  480.         dev_buffer[0] = '/';
  481.         _gs_devn(0,&dev_buffer[1]);         /* get name of stdin */
  482.         if (*ttname == '\0' || ustrncmp(ttname,dev_buffer,DEVNAMLEN) == 0
  483.           || strcmp(ttname, "/nil") == 0)
  484.           ttyfd = open(ttname,S_IREAD|S_IWRITE);
  485.           /* Try open for read/write; we cannot open own stdin non-share*/
  486.           /* Don't simply dup(0) or dup(1); they might only be open
  487.              for mere read (0) or mere write (1) */
  488.         else
  489.           ttyfd = open(ttname,S_IREAD|S_IWRITE|S_ISHARE); /* Try to open for
  490.           read/write nonshare*/
  491.         if (timo)
  492.             ttimoff();                  /* Turn off timer */
  493.         if (ttyfd < 0)      /* If couldn't open, fail. */
  494.         {
  495.             perror(ttname);
  496.             if ((errno == EOS_DEVBSY) ||
  497.                 (errno == EOS_SHARE )) return(-5);
  498.             return(-1);
  499.         }
  500.     }
  501.     debug(F111,"ttopen ok",ttname,*lcl);
  502.  
  503.  
  504. /* Caller wants us to figure out if line is controlling tty */
  505.  
  506.     if (*lcl == -1)
  507.     {
  508.         if (isatty(0))
  509.         {               /* if stdin not redirected */
  510.             dev_buffer[0] = '/';
  511.             _gs_devn(0,&dev_buffer[1]); /* ...with real name of stdin   */
  512.             xlocal = (ustrncmp(ttname,dev_buffer,DEVNAMLEN) != 0);
  513.             debug(F111," ttyname",dev_buffer,xlocal);
  514.         }
  515.         else   /* Else, if stdin redirected... */
  516.         {
  517.         /* Just assume local, so "set speed" and similar commands will work */
  518.         /* If not really local, how could it work anyway?... */
  519.             xlocal = 1;
  520.             debug(F101," redirected stdin","",xlocal);
  521.         }
  522.     }
  523.  
  524. /* line locking not needed -- os9 has exclusive access flag on open */
  525.  
  526. /* Got the line, now set the desired value for local. */
  527.  
  528.     if (*lcl < 0) *lcl = xlocal;
  529.  
  530. /* Get tty device settings */
  531.  
  532.     _gs_opt(ttyfd,&ttold);   /* Get sgtty info */
  533.     _gs_opt(ttyfd,&ttraw);   /* And a copy of it for packets*/
  534.     _gs_opt(ttyfd,&tttvt);   /* And one for virtual tty service */
  535.     debug(F101,"ttopen, ttyfd","",ttyfd);
  536.     debug(F101," lcl","",*lcl);
  537.     return(0);
  538. }
  539.  
  540. /*  T T C L O S  --  Close the TTY */
  541.  
  542. ttclos(foo) int foo; {
  543.     if (ttyfd < 0) return(0);  /* Wasn't open. */
  544.  
  545. #ifdef  NETCONN
  546.     if (netconn) {                      /* If it's a network connection. */
  547.         debug(F100,"ttclos closing net","",0);
  548.         _ss_sevent(ttyfd, 0);
  549.         netclos();                      /* Let the network module close it. */
  550.         netconn = 0;                    /* No more network connection. */
  551.         if (ttevid != 0) {
  552.             _ev_unlink(ttevid);
  553.             _ev_delete(ttevnm);
  554.             ttevid = 0;
  555.         }
  556.         return(0);
  557.     }
  558. #endif /* NETCONN */
  559.  
  560.     if (xlocal) {
  561.         if (tthang())   /* Hang up phone line */
  562.             fprintf(stderr,"Warning, problem hanging up the phone\n");
  563.     }
  564.     ttres();    /* Reset modes. */
  565. /* Relinquish exclusive access if we might have had it... */
  566.     close(ttyfd);   /* Close it. */
  567.     debug (F101,"closed connection, ttyfd","",ttyfd);
  568.     ttyfd = -1;    /* Mark it as closed. */
  569.     return(0);
  570. }
  571.  
  572. #ifdef MYREAD
  573.  
  574. /* Private buffer for myread() and its companions.  Not for use by anything
  575.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  576.  * allowed to read my_count.
  577.  *
  578.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  579.  *
  580.  * A global parity mask variable could be useful too.  We could use it to
  581.  * let myread() strip the parity on its own, instead of stripping sign
  582.  * bits as it does now.
  583.  */
  584.  
  585. #define MYBUFLEN 256
  586. static CHAR mybuf[MYBUFLEN];            /* Buffer, including push back */
  587. static int my_count = 0;                /* Number of chars still in mybuf */
  588. static int my_item = -1;                /* Last index read from mybuf[] */
  589.  
  590. /* myread() -- Efficient read of one character from communications line.
  591.  *
  592.  * Uses a private buffer to minimize the number of expensive read() system
  593.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  594.  * is then returned.  By reading all available input from the system buffers
  595.  * to the private buffer in one chunk, and then working from this buffer, the
  596.  * number of system calls is reduced in any case where more than one character
  597.  * arrives during the processing of the previous chunk, for instance high
  598.  * baud rates or network type connections where input arrives in packets.
  599.  * If the time needed for a read() system call approaches the time for more
  600.  * than one character to arrive, then this mechanism automatically compensates
  601.  * for that by performing bigger read()s less frequently.  If the system load
  602.  * is high, the same mechanism compensates for that too.
  603.  *
  604.  * myread() is a macro that returns the next character from the buffer.  If the
  605.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  606.  * returns.
  607.  *
  608.  * This should be efficient enough for any one-character-at-a-time loops.
  609.  * For even better efficiency you might use memcpy()/bcopy() or such between
  610.  * buffers (since they are often better optimized for copying), but it may not
  611.  * be worth it if you have to take an extra pass over the buffer to strip
  612.  * parity and check for CTRL-C anyway.
  613.  *
  614.  * Note that if you have been using myread() from another program module, you
  615.  * may have some trouble accessing this macro version and the private variables
  616.  * it uses.  In that case, just add a function in this module, that invokes the
  617.  * macro.
  618.  */
  619. #define myread()  (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
  620.  
  621. /* Specification: Push back up to one character onto myread()'s queue.
  622.  *
  623.  * This implementation: Push back characters into mybuf. At least one character
  624.  * must have been read through myread() before myunrd() may be used.  After
  625.  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
  626.  * one character can be pushed back, but only one character is guaranteed.
  627.  * Since a previous myread() must have read its character out of mybuf[],
  628.  * that guarantees that there is space for at least one character.  If push
  629.  * back was really needed after EOF, a small addition could provide that.
  630.  *
  631.  * myunrd() is currently not called from anywhere inside kermit...
  632.  */
  633. #ifdef NOTUSED
  634. myunrd(ch) CHAR ch; {
  635.     if (my_item >= 0) {
  636.         mybuf[my_item--] = ch;
  637.         ++my_count;
  638.     }
  639. }
  640. #endif
  641.  
  642. /* mygetbuf() -- Fill buffer for myread() and return first character.
  643.  *
  644.  * This function is what myread() uses when it can't get the next character
  645.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  646.  * to read at least one new character into the buffer, and then it returns
  647.  * the first character just as myread() would have done.  This function also
  648.  * is responsible for all error conditions that myread() can indicate.
  649.  *
  650.  * Returns: When OK     => a positive character, 0 or greater.
  651.  *          When EOF    => -2.
  652.  *          When error  => -3, error code in errno.
  653.  *
  654.  * Older myread()s additionally returned -1 to indicate that there was nothing
  655.  * to read, upon which the caller would call myread() again until it got
  656.  * something.  The new myread()/mygetbuf() always gets something.  If it
  657.  * doesn't, then make it do so!  Any program that actually depends on the old
  658.  * behaviour will break.
  659.  *
  660.  * The older version also used to return -2 both for EOF and other errors,
  661.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  662.  * other errors now return different results, although Kermit currently never
  663.  * checks to see which it was.  It just disconnects in both cases.
  664.  *
  665.  * Kermit lets the user use the quit key to perform some special commands
  666.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  667.  * finish without reading anything and return the EINTR error.  This should
  668.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  669.  * but if there is nothing to read, this could delay Kermit's reaction to
  670.  * the command, and make Kermit appear unresponsive.
  671.  *
  672.  * The debug() call should be removed for optimum performance.
  673.  */
  674. int
  675. mygetbuf() {
  676.     my_count = myfillbuf();
  677.     /* debug(F101, "myfillbuf read", "", my_count); */
  678.     if (my_count <= 0)
  679.       return(my_count < 0 ? -3 : -2);
  680.     --my_count;
  681.     return(255 & (int)mybuf[my_item = 0]);
  682. }
  683.  
  684. /* myfillbuf():
  685.  * System-dependent read() into mybuf[], as many characters as possible.
  686.  *
  687.  * Returns: OK => number of characters read, always more than zero.
  688.  *          EOF => 0
  689.  *          Error => -1, error code in errno.
  690.  *
  691.  * If there is input available in the system's buffers, all of it should be
  692.  * read into mybuf[] and the function return immediately.  If no input is
  693.  * available, it should wait for a character to arrive, and return with that
  694.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  695.  * character, but be aware that any such delay lengthens the packet turnaround
  696.  * time during kermit file transfers.  Should never return with zero characters
  697.  * unless EOF or irrecoverable read error.
  698.  *
  699.  * Correct functioning depends on the correct tty parameters being used.
  700.  * Better control of current parameters is required than may have been the
  701.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
  702.  * no longer be sometimes off and sometimes on like it used to, unless a
  703.  * special myfillbuf() is written to handle that.  Otherwise the ordinary
  704.  * myfillbuf()s may think they have come to EOF.
  705.  *
  706.  * If your system has a facility to directly perform the functioning of
  707.  * myfillbuf(), then use it.  If the system can tell you how many characters
  708.  * are available in its buffers, then read that amount (but not less than 1).
  709.  * If the system can return a special indication when you try to read without
  710.  * anything to read, while allowing you to read all there is when there is
  711.  * something, you may loop until there is something to read, but probably that
  712.  * is not good for the system load.
  713.  */
  714.  
  715.         /* This is for OSK.  _gs_rdy returns the number
  716.          * of characters available for reading. If none are available, wait
  717.          * until something arrives, otherwise return all there is.
  718.          * The OSK version needs to handle timeouts explicitly since
  719.          * OSK alarm() does not interupt I/O.  (Only done when filling buffer
  720.          * to reduce overhead.)
  721.          */
  722. int
  723. myfillbuf() {
  724.     register int avail;
  725.     register int x;
  726.  
  727. #ifdef O_GOODDRIVER
  728. /*
  729.   Drivers that conform with the Technical I/O Manual interrupt I/O when
  730.   the signal code is less than S_DEADLY.
  731. */
  732.     while (1) {
  733.         if ((avail = _gs_rdy(ttyfd)) <= 0)
  734.             avail = 1;
  735.         else if (avail > MYBUFLEN)
  736.             avail = MYBUFLEN;
  737.         if ((x = read(ttyfd, (char *)mybuf, (int)avail)) < 0) {
  738.             if ((errno & 0xff) == EOS_READ)
  739.                 /* Ingore framing, parity and break errors (like unix) */
  740.                 continue;
  741.         }
  742. /* Wait some arbitrary time for buffer fill to reduce system load. */
  743.         if (avail < 10) tsleep(2);
  744.         break;
  745.     }
  746.     return x;
  747. #else /* O_GOODDRIVER */
  748.     (void) remove_alarm();      /* let's fake it instead */
  749.     for(;;) {
  750.         if (timowhen && time((time_t *)0) >= timowhen) { /*check for timeout*/
  751.             timowhen = 0;
  752.             if (sigtbl[MAXSIG] != SIG_DFL) (*sigtbl[MAXSIG])(SIGALRM);
  753.             return -1;
  754.         }
  755.         if ((avail = _gs_rdy(ttyfd)) > 0) break;
  756.         sigmask(1);
  757.         _ss_ssig(ttyfd, SIGARB);
  758.         sleep(1);               /* interupted by signal if incoming char */
  759.         _ss_rel(ttyfd, SIGARB);
  760.     }
  761.  
  762.     if (avail > MYBUFLEN)
  763.       avail = MYBUFLEN;
  764.  
  765.     x = read(ttyfd, mybuf, (int) avail);
  766. /* Wait some arbitrary time for buffer fill to reduce system load. */
  767.     if (avail < 10) tsleep(2);
  768.     return(x);
  769. #endif /* !O_GOODDRIVER */
  770. }
  771.  
  772. #endif /* MYREAD */
  773. /*  T T H A N G -- Hangup phone line */
  774.  
  775. tthang() {
  776.     if (ttyfd < 0) return(0);        /* Not open. */
  777.  
  778. #ifdef NETCONN
  779.     if (netconn)                        /* Network connection. */
  780.       return((ttclos(0) < 0) ? -1 : 1); /* Just close it. */
  781. #endif /* NETCONN */
  782.  
  783.     return 0;                /* not implemented */
  784. }
  785.  
  786.  
  787. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  788.  
  789. ttres() {    /* Restore the tty to normal. */
  790.     if (ttyfd < 0) return(-1);  /* Not open. */
  791.  
  792. #ifdef  NETCONN
  793.     if (netconn) return (0);            /* Network connection, do nothing */
  794. #endif  /* NETCONN */
  795.  
  796. #ifdef XMODE
  797.     if (xmode(ttold.sg_baud) < 0) return(-1);
  798. #endif
  799.     tsleep(2);    /* Wait for pending i/o to finish. */
  800.     if (_ss_opt(ttyfd,&ttold) < 0) return(-1); /* Restore sgtty stuff */
  801.     return(0);
  802. }
  803.  
  804. /*  T T P K T  --  Condition the communication line for packets. */
  805. /*  or for modem dialing */
  806.  
  807. /*  If called with speed > -1, also set the speed.  */
  808.  
  809. /*  Returns 0 on success, -1 on failure.  */
  810.  
  811. ttpkt(speed,flow,parity) long speed; int flow, parity; {
  812.     int s = 0;
  813.     if (ttyfd < 0) return(-1);        /* Not open. */
  814.  
  815. #ifdef NETCONN                          /* Nothing to do for telnet */
  816.     if (netconn) return (0);
  817. #endif /* NETCONN */
  818.  
  819.     if (speed >-1)
  820.         if ((s=ttsspd(speed/10)) <0) return(-1); /* Check the speed */
  821.  
  822.     ttprty = parity;          /* Let other functions see these. */
  823.     ttpflg = 0;               /* Parity not sensed yet */
  824.     ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */
  825.  
  826.     ttraw.sg_case =
  827.     ttraw.sg_backsp =
  828.     ttraw.sg_delete =
  829.     ttraw.sg_echo =
  830.     ttraw.sg_alf =
  831.     ttraw.sg_nulls =
  832.     ttraw.sg_pause =
  833.     ttraw.sg_bspch =
  834.     ttraw.sg_dlnch =
  835.     ttraw.sg_eorch =
  836.     ttraw.sg_eofch =
  837.     ttraw.sg_rlnch =
  838.     ttraw.sg_dulnch =
  839.     ttraw.sg_psch =
  840.     ttraw.sg_kbich =
  841.     ttraw.sg_kbach =
  842.     ttraw.sg_bsech =
  843.     ttraw.sg_tabcr = 0;
  844.     if (speed >-1)
  845.         ttraw.sg_baud = (char)s;
  846.     if (flow==1) {
  847.         ttraw.sg_xon  = 0x11;
  848.         ttraw.sg_xoff = 0x13;
  849.     } else ttraw.sg_xon = ttraw.sg_xoff = 0;
  850.     if(_ss_opt(ttyfd,&ttraw) < 0) return(-1);    /* set new modes . */
  851.     ttflui();    /* Flush any pending input */
  852.     return(0);
  853. }
  854.  
  855. /*  T T V T -- Condition communication line for use as virtual terminal  */
  856.  
  857. ttvt(speed,flow) long speed; int flow; {
  858.  
  859. int s;
  860.     if (ttyfd < 0) return(-1);  /* Not open. */
  861.  
  862. #ifdef NETCONN
  863.     if (netconn) {
  864.         /*tvtflg = 1;*/                     /* Network connections */
  865.         debug(F100,"ttvt network connection, skipping...","",0);
  866.         return(0);                      /* require no special setup */
  867.     }
  868. #endif /* NETCONN */
  869.  
  870.     if ((s=ttsspd(speed/10)) <0) return(-1); /* This speed not supported */
  871.  
  872.     tttvt.sg_case =
  873.     tttvt.sg_backsp =
  874.     tttvt.sg_delete =
  875.     tttvt.sg_echo =
  876.     tttvt.sg_alf =
  877.     tttvt.sg_nulls =
  878.     tttvt.sg_pause =
  879.     tttvt.sg_bspch =
  880.     tttvt.sg_dlnch =
  881.     tttvt.sg_eorch =
  882.     tttvt.sg_eofch =
  883.     tttvt.sg_rlnch =
  884.     tttvt.sg_dulnch =
  885.     tttvt.sg_psch =
  886.     tttvt.sg_kbich =
  887.     tttvt.sg_kbach =
  888.     tttvt.sg_bsech =
  889.     tttvt.sg_tabcr = 0;
  890.     tttvt.sg_baud = (char)s;
  891.     if (flow==1) {
  892.         tttvt.sg_xon  = 0x11;
  893.         tttvt.sg_xoff = 0x13;
  894.     } else tttvt.sg_xon = tttvt.sg_xoff = 0;
  895.     s = _ss_opt(ttyfd,&tttvt);   /* set new modes . */
  896.     debug (F101,"ss_opt on tty was :","",s);
  897.     return(0);
  898. }
  899.  
  900. /*  T T F L U I  --  Flush tty input buffer */
  901.  
  902. ttflui() {
  903.     int n;
  904.     char flushbuf[256];
  905.  
  906.     if (ttyfd < 0) return(-1);  /* Not open. */
  907. #ifdef MYREAD
  908.     my_count = 0;                       /* initialize myread() stuff */
  909.     my_item = -1;
  910. #endif /* MYREAD */
  911.  
  912. #ifdef NETCONN
  913. /*
  914.   Network flush is done specially, in the network support module.
  915. */
  916.     debug(F100,"ttflui netflui","",0);
  917.     if (netconn) return(netflui());
  918. #endif /* NETCONN */
  919.  
  920.     while((n=_gs_rdy(ttyfd))>0)
  921.         read(ttyfd, flushbuf, n>256 ? 256 : (unsigned int)n);
  922.     return 0;
  923. }
  924.  
  925. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  926. ttchk() {
  927.     register int n;
  928.  
  929.     n = _gs_rdy(ttyfd);
  930.     if (n < 0) n = 0;
  931. #ifdef MYREAD
  932.     if (my_count > 0) n += my_count;
  933. #endif /* MYREAD */
  934.     return n;
  935. }
  936.  
  937. /*  T T X I N  --  Get n characters from tty input buffer  */
  938. /*  Returns number of characters actually gotten, or -1 on failure  */
  939. /*  Intended for use only when it is known that n characters are actually */
  940. /*  Available in the input buffer.  */
  941.  
  942. ttxin(n,buf) int n; CHAR *buf; {
  943.     register int c = 0;
  944. #ifdef MYREAD
  945.     register CHAR *bp, *bpe;
  946. #else
  947.     register int x;
  948. #endif /* MYREAD */
  949.  
  950.     ttpmsk = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  951.     debug(F101,"ttxin n","",n);
  952. #ifdef MYREAD
  953.     for( bpe = (bp = buf) + n; (bp != bpe) && (c = myread()) >= 0; )
  954.         *bp++ = c & ttpmsk;
  955.     if (c < 0) return -1;
  956.     *bp = '\0';
  957.     return n;
  958. #else
  959.     x = read(ttyfd,(char *)buf,(unsigned int)n);
  960.     if (ttprty) {
  961.         for (c = 0; c < n; c++) buf[c] &= 0177;
  962.     }
  963.     if (x > 0) buf[x] = '\0';
  964.     if (x < 0) x = -1;
  965.     return(x);
  966. #endif /* MYREAD */
  967. }
  968.  
  969. /*  C O N I N T  --  Console Interrupt setter  */
  970. VOID
  971. conint(f,s) SIGTYP (*f)(), (*s)();
  972. {
  973.     if (backgrd) return;  /* must ignore signals in bkgrd */
  974.     signal(SIGINT,f);  /* console escape in pkt modes */
  975. }
  976.  
  977.  
  978. /*  C O N N O I  --  Reset console terminal interrupts */
  979. VOID
  980. connoi() {    /* Console-no-interrupts */
  981.     signal(SIGQUIT,(fptr)SIG_IGN);
  982.     signal(SIGINT,(fptr)SIG_IGN);
  983. }
  984.  
  985.  
  986.  
  987. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  988.  
  989. ttol(s,n) int n; CHAR *s; {
  990.     int x;
  991.     if (ttyfd < 0) {
  992.         debug(F101,"ttol: ttyfd",NULL,ttyfd);
  993.         return(-1);  /* Not open. */
  994.     }
  995.     x = write(ttyfd,(char *)s,(unsigned int)n);
  996.     debug(F111,"ttol",s,n); /* `s' schould be null terminated !? */
  997.     if (x < 0) {
  998.         debug(F101,"ttol failed errno",NULL,errno);
  999. #ifdef TCPSOCKET
  1000.         if (netconn && ttnet == NET_TCPB) {
  1001.             if (errno) perror("TCP/IP"); /* Say why */
  1002.             ttclos(0);              /* Close the connection. */
  1003.         }
  1004. #endif /* TCPSOCKET */
  1005.     }
  1006.     return(x);
  1007. }
  1008.  
  1009.  
  1010. /*  T T O C  --  Output a character to the communication line  */
  1011.  
  1012. int
  1013. #ifdef CK_ANSIC
  1014. ttoc(char c)
  1015. #else
  1016. ttoc(c) char c;
  1017. #endif /* CK_ANSIC */
  1018. /* ttoc */{
  1019.     if (ttyfd < 0) return(-1);  /* Not open. */
  1020.     return(write(ttyfd,&c,1));
  1021. }
  1022.  
  1023.  
  1024. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1025. /*
  1026.   Reads up to "max" characters from the communication line, terminating on:
  1027.  
  1028.     (a) the packet length field if the "turn" argument is zero, or
  1029.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  1030.     (c) two Ctrl-C's in a row
  1031.  
  1032.   and returns the number of characters read upon success, or if "max" was
  1033.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  1034.  
  1035.   The characters that were input are copied into "dest" with their parity bits
  1036.   stripped if parity was selected.  Returns the number of characters read.
  1037.   Characters after the eol are available upon the next call to this function.
  1038.  
  1039.   The idea is to minimize the number of system calls per packet, and also to
  1040.   minimize timeouts.  This function is the inner loop of the program and must
  1041.   be as efficient as possible.  The current strategy is to use myread().
  1042.  
  1043.   WARNING: this function calls parchk(), which is defined in another module.
  1044.   Normally, ckutio.c does not depend on code from any other module, but there
  1045.   is an exception in this case because all the other ck?tio.c modules also
  1046.   need to call parchk(), so it's better to have it defined in a common place.
  1047.  
  1048.   Since this function has grown to have its fingers so deeply into the 
  1049.   protocol, it is slated for removal: rpack() will take care of everything.
  1050. */
  1051. #ifdef CTRLC
  1052. #undef CTRLC
  1053. #endif /* CTRLC */
  1054. #define CTRLC '\03'
  1055. /*
  1056.   We have four different declarations here because:
  1057.   (a) to allow Kermit to be built without the automatic parity sensing feature
  1058.   (b) one of each type for ANSI C, one for non-ANSI.
  1059. */
  1060. int
  1061. #ifdef PARSENSE
  1062. #ifdef CK_ANSIC
  1063. ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
  1064. #else
  1065. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
  1066. #endif /* CK_ANSIC */
  1067. #else /* not PARSENSE */
  1068. #ifdef CK_ANSIC
  1069. ttinl(CHAR *dest, int max,int timo, CHAR eol)
  1070. #else
  1071. ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  1072. #endif /* __SDTC__ */
  1073. #endif /* PARSENSE */
  1074. /* ttinl */ {
  1075.  
  1076.     if (ttyfd < 0) return(-1);          /* Not open. */
  1077.  
  1078.     debug(F101,"ttinl max","",max);
  1079.     debug(F101,"ttinl timo","",timo);
  1080.  
  1081.     *dest = '\0';                       /* Clear destination buffer */
  1082.     if (timo < 0) timo = 0;             /* Safety */
  1083.     if (
  1084. #ifdef CK_POSIX_SIG
  1085.         sigsetjmp(sjbuf,1)
  1086. #else
  1087.         setjmp(sjbuf)
  1088. #endif /* CK_POSIX_SIG */
  1089.         ) {                /* Timer went off? */
  1090.         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
  1091.         /* debug(F110," with",(char *) dest,0); */
  1092. #ifndef OSK
  1093.         ttimoff();                      /* Turn off timer */
  1094. #endif /* !OSK */
  1095.         return(-1);                     /* and return error code. */
  1096.     } else {
  1097. #ifndef MYREAD
  1098.         CHAR ch;
  1099. #endif /* MYREAD */
  1100.         register int i, n;              /* local variables */
  1101.         int ccn = 0;
  1102. #ifdef PARSENSE
  1103.         int pktlen = -1;
  1104.         int lplen = 0;
  1105.         int havelen = 0;
  1106.         int flag = 0;
  1107.         debug(F000,"ttinl start","",start);
  1108. #endif /* PARSENSE */
  1109.  
  1110.         if (timo) {                     /* Don't time out if timo == 0 */
  1111.             int xx;
  1112.             saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
  1113.             xx = alarm(timo);           /* Set it. */
  1114.             debug(F101,"ttinl alarm","",xx);
  1115.         }
  1116.         ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */
  1117.  
  1118. #ifdef COMMENT
  1119. /*
  1120.   No longer needed.
  1121. */
  1122. #ifdef SUNX25
  1123.         if (netconn && (ttnet == NET_SX25))
  1124. #ifdef PARSENSE
  1125.           return(x25inl(dest,max,timo,eol,start));
  1126. #else
  1127.           return(x25inl(dest,max,timo,eol));
  1128. #endif /* PARSENSE */
  1129. #endif /* SUNX25 */
  1130. #endif /* COMMENT */
  1131.  
  1132. /* Now read into destination, stripping parity and looking for the */
  1133. /* the packet terminator, and also for two Ctrl-C's typed in a row. */
  1134.  
  1135.         i = 0;                          /* Destination index */
  1136.         debug(F101,"ttinl eol","",eol);
  1137.  
  1138. #ifdef MYREAD
  1139.         while (i < max-1) {
  1140.             /* debug(F101,"ttinl i","",i); */
  1141.             if ((n = myread()) < 0) {
  1142.                 debug(F101,"ttinl myread failure, n","",n);
  1143.                 debug(F101,"ttinl myread errno","",errno);
  1144. #ifndef OSK
  1145.                 /* Don't let EINTR break packets. */
  1146.                 if (n == -3 && errno == EINTR && i > 0) {
  1147.                     debug(F101,"ttinl myread i","",i);
  1148.                     continue;
  1149.                 }
  1150. #endif /* !OSK */
  1151.                 break;
  1152.             }
  1153. #else
  1154.         while ((i < max-1)  &&  (n = read(ttyfd, &ch, 1)) > 0) {
  1155.             n = ch;
  1156. #endif /* MYREAD */
  1157.  
  1158.             /* debug(F101,"ttinl char","", (n & ttpmsk)); */
  1159.  
  1160. #ifdef PARSENSE
  1161. /*
  1162.   Figure out what the length is supposed to be in case the packet
  1163.   has no terminator (as with Honeywell GCOS-8 Kermit).
  1164. */
  1165. #ifndef xunchar
  1166. #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
  1167. #endif /* xunchar */
  1168.             if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
  1169.             if (flag) dest[i++] = n & ttpmsk;
  1170. /*
  1171.   If we have not been instructed to wait for a turnaround character, we
  1172.   can go by the packet length field.  If turn != 0, we must wait for the
  1173.   end of line (eol) character before returning.
  1174. */
  1175.             if (i == 2) {
  1176.                 pktlen = xunchar(dest[1] & 0x7f);
  1177.                 havelen = (pktlen > 1);
  1178.                 debug(F101,"ttinl length","",pktlen);
  1179.             } else if (i == 5 && pktlen == 0) {
  1180.                 lplen = xunchar(dest[4] & 0x7f);
  1181.             } else if (i == 6 && pktlen == 0) {
  1182.                 pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
  1183.                 havelen = 1;
  1184.                 debug(F101,"ttinl length","",pktlen);
  1185.             }
  1186. #else
  1187.             dest[i++] = n & ttpmsk;
  1188. #endif /* PARSENSE */
  1189. /*
  1190.   Use parity mask, rather than always stripping parity, to check for
  1191.   cancellation.  Otherwise, runs like \x03\x83\x03 in packet could cancel
  1192.   the transfer when parity is NONE.
  1193. */
  1194.             /* Check cancellation */
  1195.             if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
  1196.                 if (++ccn >= xfrnum) {  /* If xfrnum in a row, bail out. */
  1197.                     if (timo) {         /* Clear timer. */
  1198.                         ttimoff();
  1199.                     }
  1200. #ifdef OSK
  1201.                     fprintf(stderr,"^C...\r\012"); /* Echo Ctrl-C */
  1202. #else /* OSK */
  1203.                     fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  1204. #endif /* !OSK */
  1205.                     return(-2);
  1206.                 }
  1207.             } else ccn = 0;             /* No cancellation, reset counter, */
  1208.  
  1209. #ifdef PARSENSE
  1210.             if (flag == 0) {
  1211.                 debug(F101,"ttinl skipping","",n);
  1212.                 continue;
  1213.             }
  1214. #endif /* PARSENSE */
  1215.  
  1216.     /* Check for end of packet */
  1217.  
  1218.             if (
  1219. #ifdef PARSENSE
  1220. /*
  1221.   Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
  1222.   This allows packet terminators and handshake characters to appear
  1223.   literally inside a packet data field.
  1224. */
  1225.                 (havelen && (i > pktlen+1) &&
  1226.                  (!turn || (turn && (n & 0x7f) == eol)))
  1227. #ifdef COMMENT
  1228.                 (!turn && havelen && (i > pktlen+1)) ||
  1229.                 (turn && havelen && (i > pktlen+1) && (n & 0x7f) == eol)
  1230. #endif /* COMMENT */
  1231. #else /* !PARSENSE */
  1232. /*
  1233.   Built without PARSENSE, so just look for packet terminator.
  1234. */
  1235.                 ((n & 0x7f) == eol)
  1236. #endif /* PARSENSE */
  1237.                 ) {
  1238. #ifndef PARSENSE
  1239.                 debug(F101,"ttinl got eol","",eol);
  1240.                 dest[i] = '\0';         /* Yes, terminate the string, */
  1241.                 /* debug(F101,"ttinl i","",i); */
  1242. #else
  1243.                 if ((n & 0x7f) != eol) {
  1244.                     debug(F101,"ttinl EOP length","",pktlen);
  1245.                     debug(F101,"ttinl i","",i);
  1246.                 } else debug(F101,"ttinl got eol","",eol);
  1247.                 dest[i] = '\0';         /* Terminate the string, */
  1248.                 /* Parity checked yet? */
  1249.                 if (ttpflg++ == 0 && ttprty == 0) {
  1250.                     if ((ttprty = parchk(dest,start,i)) > 0) { /* No, check. */
  1251.                         int j;
  1252.                         debug(F101,"ttinl senses parity","",ttprty);
  1253.                         debug(F110,"ttinl packet before",dest,0);
  1254.                         ttpmsk = 0x7f;
  1255.                         for (j = 0; j < i; j++)
  1256.                           dest[j] &= 0x7f;      /* Strip parity from packet */
  1257.                         debug(F110,"ttinl packet after ",dest,0);
  1258.                     } else ttprty = 0;  /* restore if parchk error */
  1259.                 }
  1260. #endif /* PARSENSE */
  1261.                 if (timo) {                     /* Turn off timer. */
  1262.                     ttimoff();
  1263.                 }
  1264.                 debug(F111,"ttinl got", dest,i);
  1265.                 return(i);
  1266.             }
  1267.         }                               /* end of while() */
  1268. #ifdef OSK
  1269.         if (timo)
  1270. #endif /* OSK */
  1271.             ttimoff();
  1272.         return(-1);
  1273.     }
  1274. }
  1275.  
  1276. /*  T T I N C --  Read a character from the communication line  */
  1277. /*
  1278.  On success, returns the character that was read, >= 0.
  1279.  On failure, returns -3 on internal error, -2 on communication disconnect,
  1280.  -1 on timeout and other
  1281. */
  1282. int
  1283. ttinc(timo) int timo; {
  1284. #ifndef MYREAD
  1285.     CHAR ch = 0;
  1286. #endif /* MYREAD */
  1287.     int n = 0;
  1288.  
  1289.     if (ttyfd < 0) return(-1);          /* Not open. */
  1290.     if (timo <= 0                       /* Untimed. */
  1291. #ifdef MYREAD
  1292.         || my_count > 0                 /* Buffered char already waiting. */
  1293. #endif /* MYREAD */
  1294.     ) {
  1295.         /* not realy untimed, ckudia.c uses alarm() */
  1296. #ifdef MYREAD
  1297.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  1298.         n = myread();                   /* Wait for a character... */
  1299.         /* debug(F101,"ttinc n","",n); */
  1300. #else
  1301.         while ((n = read(ttyfd,&ch,1)) == 0) /* Wait for a character. */
  1302.         /* Shouldn't have to loop in ver 5A. */
  1303.           ;
  1304. /* debug(F000,"ttinc","",ch); */
  1305.         return( (n < 1) ? -3 : (ch & ttpmsk) );
  1306. #endif /* MYREAD */
  1307.     } else {
  1308.         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
  1309.         alarm((unsigned int)timo);
  1310.         if (setjmp(sjbuf)) {
  1311.             n = -1;
  1312.         } else {
  1313. #ifdef MYREAD
  1314.             n = myread();               /* If managing own buffer... */
  1315.             debug(F101,"ttinc myread","",n);
  1316. #else
  1317. #ifdef O_GOODDRIVER
  1318.             n = read(ttyfd,(char *)&ch,1);
  1319. #else /* O_GOODDRIVER */
  1320.             n = timoread(ttyfd,(char *)&ch,1);  /*Otherwise call the system.*/
  1321. #endif /* !O_GOODDRIVER */
  1322.             debug(F101,"ttinc read","",n);
  1323.             if (n > 0)
  1324.               n = ch & 255;
  1325.             else
  1326.               n = (n < 0) ? -3 : -2;    /* Special return codes */
  1327. #endif /* MYREAD */
  1328.         }
  1329.         ttimoff();                          /* Turn off timer */
  1330.     }
  1331.     return( (n < 0) ? n : (n & ttpmsk) ); /* Return masked char or neg. */
  1332. }
  1333.  
  1334. /*  T T S N D B  --  Send a BREAK signal  */
  1335.  
  1336. ttsndb()
  1337. {
  1338. struct sgbuf before;
  1339. int i;
  1340.     if (ttyfd < 0) return(-1);  /* Not open. */
  1341.  
  1342. #ifdef NETCONN
  1343.     if (netconn)                        /* Send network BREAK */
  1344.       return(netbreak());
  1345. #endif /* NETCONN */
  1346.  
  1347. #ifndef XMODE
  1348.     if (send_break(ttyfd) == 0) return(0); /* all fine done by driver */
  1349.     if (errno!=EOS_UNKSVC)  /*should have been unknown service call*/
  1350.       return(-1);
  1351.     if (_gs_opt(ttyfd,&before) < 0) return(-1); /* din't get old speed */
  1352.     for (i=B50; i<before.sg_baud; i++) /* try to switch to a lower speed */
  1353.     {
  1354.       if (ttsspd((int)bdrts[i]/10) != -1) break;
  1355.     }
  1356.     if (i == before.sg_baud) return(-1); /* no lower speed supported */
  1357. #else
  1358.     if (_gs_opt(ttyfd,&before) < 0) return(-1); /* din't get old speed */
  1359.     ttsspd((int)bdrts[B300]/10);/* xmode always return success, since it only
  1360.                                    patches device descriptor */
  1361. #endif
  1362.     write(ttyfd,"\0",1);
  1363.     write(ttyfd,"\0",1); /* send two zeroes */
  1364.     msleep(400);      /* wait chars to appear (50 baud == 400 milli seconds */
  1365.     ttsspd((int)bdrts[before.sg_baud]/10); /* restore old baud rate*/
  1366.     return(0);
  1367. }
  1368.  
  1369. VOID
  1370. rtimer() {
  1371.     tcount = time( (time_t *) 0 );
  1372. }
  1373.  
  1374.  
  1375. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1376.  
  1377. int
  1378. gtimer() {
  1379.     int x;
  1380.     x = (int) (time( (time_t *) 0 ) - tcount);
  1381.     return( (x < 0) ? 0 : x );
  1382. }
  1383.  
  1384. /*  Z T I M E  --  Return date/time string  */
  1385. VOID
  1386. ztime(s) char **s;
  1387. {
  1388. time_t t;
  1389.   t = time((time_t*)NULL);
  1390.   if (t != (time_t)-1)
  1391.     *s =ctime(&t);
  1392.   else
  1393.     *s = "Ddd Mmm 00 00:00:00 0000\n";  /* Return dummy in asctime() format */
  1394. }
  1395.  
  1396. /*  C O N G M  --  Get console terminal modes.  */
  1397.  
  1398. /*
  1399.  Saves current console mode, and establishes variables for switching between
  1400.  current (presumably normal) mode and other modes.
  1401. */
  1402.  
  1403. congm() {
  1404.     if (!isatty(0)) return(-1);  /* only for real ttys */
  1405.     _gs_opt(0,&ccold);   /* Structure for restoring */
  1406.     _gs_opt(0,&cccbrk);  /* For setting CBREAK mode */
  1407.     cccbrk.sg_echo  =
  1408.     cccbrk.sg_pause =
  1409.     cccbrk.sg_eofch =
  1410.     cccbrk.sg_psch = 0; /* kermit interpreter uses CTRL-W */
  1411.  
  1412.     _gs_opt(0,&ccraw);   /* For setting RAW mode */
  1413.     ccraw.sg_case =
  1414.     ccraw.sg_backsp =
  1415.     ccraw.sg_delete =
  1416.     ccraw.sg_echo =
  1417.     ccraw.sg_alf =
  1418.     ccraw.sg_nulls =
  1419.     ccraw.sg_pause =
  1420.     ccraw.sg_bspch =
  1421.     ccraw.sg_dlnch =
  1422.     ccraw.sg_eorch =
  1423.     ccraw.sg_eofch =
  1424.     ccraw.sg_rlnch =
  1425.     ccraw.sg_dulnch =
  1426.     ccraw.sg_psch =
  1427.     ccraw.sg_kbich =
  1428.     ccraw.sg_kbach =
  1429.     ccraw.sg_bsech =
  1430.     ccraw.sg_tabcr =
  1431.     ccraw.sg_xon =
  1432.     ccraw.sg_xoff = 0;
  1433.         return(0);
  1434. }
  1435.  
  1436.  
  1437. /*  C O N C B --  Put console in cbreak mode.  */
  1438. /* we can ignore esc since conchk() works on OS-9, no need for a special esc */
  1439. /*  Returns 0 if ok, -1 if not  */
  1440.  
  1441. int
  1442. #ifdef CK_ANSIC
  1443. concb(char esc)
  1444. #else
  1445. concb(esc) char esc;
  1446. #endif /* CK_ANSIC */
  1447. /* concb */ {
  1448.     int x;
  1449.     if (!isatty(0)) return(0);  /* only for real ttys */
  1450.     ckxech = 1;                 /* Program can echo characters */
  1451.     x = _ss_opt(0,&cccbrk) | _ss_opt(1,&cccbrk);
  1452.     debug(F101,"console set to cbreak mode","",esc);
  1453.     return(x);
  1454. }
  1455.  
  1456. /*  C O N B I N  --  Put console in binary mode  */
  1457.  
  1458. /* we can ignore esc since conchk() works on OS-9, no need for a special esc */
  1459. /*  Returns 0 if ok, -1 if not  */
  1460.  
  1461. int
  1462. #ifdef CK_ANSIC
  1463. conbin(char esc)
  1464. #else
  1465. conbin(esc) char esc;
  1466. #endif /* CK_ANSIC */
  1467. /* conbin */ {
  1468.     if (!isatty(0)) return(0);  /* only for real ttys */
  1469.     ckxech = 1;                 /* Program can echo characters */
  1470.     _ss_opt(0,&ccraw);
  1471.     _ss_opt(1,&ccraw);          /* set new modes . */
  1472.     debug(F101,"console switched to raw mode","",esc);
  1473.     return(0);
  1474. }
  1475.  
  1476.  
  1477. /*  C O N R E S  --  Restore the console terminal  */
  1478.  
  1479. conres() {
  1480.     if(!isatty(0)) return 0; /* only for real ttys with known modes*/
  1481.     tsleep(2);
  1482.     ckxech = 0;    /* OS-9 will echo chars */
  1483.     return(_ss_opt(0,&ccold)| _ss_opt(1,&ccold)); /* Restore controlling tty */
  1484. }
  1485.  
  1486. /*  C O N O C  --  Output a character to the console terminal  */
  1487. int
  1488. #ifdef CK_ANSIC
  1489. conoc(char c)
  1490. #else
  1491. conoc(c) char c;
  1492. #endif /* CK_ANSIC */
  1493. /* conoc */ {
  1494.     return((write(1,&c,1)>0) ? 1:0);
  1495. }
  1496.  
  1497. /*  C O N X O  --  Write x characters to the console terminal  */
  1498. /*VOID*/
  1499. int
  1500. conxo(x,s) char *s; int x; {
  1501.     return(write(1,s,(unsigned int)x));
  1502. }
  1503.  
  1504. /*  C O N O L  --  Write a line to the console terminal  */
  1505. /*VOID*/
  1506. int
  1507. conol(s) char *s; {
  1508.     int len;
  1509.     len = strlen(s);
  1510.     return(write(1,s,(unsigned int)len));
  1511. }
  1512.  
  1513. /*  C O N O L L L  --  Output a string followed by LF  */
  1514. static int
  1515. conolll(s) char *s; {
  1516.     conol(s);
  1517.     return(write(1,"\012",1));
  1518. }
  1519.  
  1520. /*  C O N O L A  --  Write an array of lines to the console terminal */
  1521. /*VOID */
  1522. int
  1523. conola(s) char *s[]; {
  1524.     int i;
  1525.     for (i=0 ; *s[i] ; i++) if (conolll(s[i]) < 0) return(-1);
  1526.     return(0);
  1527. }
  1528.  
  1529. /*  C O N O L L  --  Output a string followed by CRLF  */
  1530. /*VOID*/
  1531. int
  1532. conoll(s) char *s; {
  1533.     conol(s);
  1534.     return(write(1,"\r\012",2));
  1535. }
  1536.  
  1537. /*  C O N C H K  --  Return how many characters available at console  */
  1538. conchk()
  1539. {
  1540.     int x;
  1541.     x=_gs_rdy(0);
  1542.     if(x<0) x=0; /* always return 0 irrespective the type of error */
  1543.                  /* e.q. /nil would return E_UNKSVC and conchk is only */
  1544.                  /* checked on != 0 anyway, Bob Larson */
  1545.     debug (F101,"conchk","",x);
  1546.     return x;
  1547. }
  1548.  
  1549. /*  C O N I N C  --  Get a character from the console  */
  1550. int
  1551. coninc(timo) int timo; {
  1552.     int n = 0; CHAR ch;
  1553.  
  1554.     if (timo <= 0 ) {                   /* Untimed. */
  1555.         n = read(0, (char *)&ch, 1);            /* Read a character. */
  1556.         ch &= 0377;
  1557.         if (n > 0)                      /* Return the character if read ok */
  1558.           return(ch);
  1559.         else                            /* otherwise... */
  1560.         {
  1561.             debug(F101, "coninc(0) errno","",errno);
  1562.             return(-1);             /* Return -1 as error indication */
  1563.         }
  1564.     }
  1565.     if (setjmp(sjbuf)) n = -2;
  1566.     else {
  1567.         saval = signal(SIGALRM,timerh); /* Timed read, so set up timer */
  1568.         alarm((unsigned int)timo);
  1569. #ifdef O_GOODDRIVER
  1570.         n = read(0, (char *)&ch, 1);
  1571. #else /* O_GOODDRIVER */
  1572.         n = timoread(0, (char *)&ch, 1);
  1573. #endif /* !O_GOODDRIVER */
  1574.         ttimoff();                          /* Turn off timer */
  1575.         ch &= 0377;
  1576.     }
  1577.     if (n > 0) return(ch);
  1578.     else
  1579.         return(-1);
  1580. }
  1581.  
  1582. /* emulate unix signal functions */
  1583. fptr
  1584. signal(sig,func)
  1585. int sig;
  1586. fptr func;
  1587. {
  1588.     fptr temp;
  1589.     if (sig < MAXSIG) {
  1590.         temp = sigtbl[sig];
  1591.         sigtbl[sig] = func;
  1592.         return temp;
  1593.     }
  1594.     if (sig == SIGALRM) {
  1595.         temp = sigtbl[MAXSIG];
  1596.         sigtbl[MAXSIG] = func;
  1597.         return temp;
  1598.     }
  1599.     return (fptr)-1;
  1600. }
  1601.  
  1602. VOID
  1603. catch(sig) register int sig;{
  1604.     register fptr temp;
  1605.  
  1606.     if(sig == SIGARB) {
  1607.         csigflg += 1;
  1608.         return;
  1609.     }
  1610.     if (sig == SIGARB+1) {
  1611.         tsigflg += 1;
  1612.         return;
  1613.     }
  1614.     if(sig < MAXSIG) {
  1615.         if ((temp = sigtbl[sig]) == SIG_DFL) doexit(sig,-1);
  1616.         if(temp != (SIGTYP (*)())SIG_IGN)
  1617.           (*temp)(sig);
  1618.         else
  1619.         {
  1620.           if (sig == SIGQUIT) /* output ceises on CTRL-E typed, so notify */
  1621.             stdin->_flag |= _ERR;
  1622.         }
  1623.         return;
  1624.     }
  1625.     if(sig == SIGALRM) {
  1626.         if ((temp = sigtbl[MAXSIG]) == SIG_DFL) return;
  1627.         if (temp != (SIGTYP (*)())SIG_IGN) (*temp)(sig);
  1628.         return;
  1629.     }
  1630.     doexit(sig,-1);
  1631. }
  1632.  
  1633. int isatty(path)
  1634. int path;
  1635. {
  1636.     struct sgbuf buffer;
  1637.     return((_gs_opt(path,&buffer)<0) ? 0 : buffer.sg_class == 0);
  1638. }
  1639.  
  1640. /*********************************************************************/
  1641. int msleep(m_secs) /* sleeps at least !! (not exact) m_secs milli seconds */
  1642. register int m_secs;
  1643. {
  1644. register unsigned int i;
  1645. register int tick_rate;
  1646.   if ((tick_rate = _getsys(D_TckSec,2)) < 0) return(-1); /* clock   not on */
  1647.   i = (unsigned int)(((double)m_secs*(double)tick_rate)/1000.0);
  1648.   tsleep(i+2);  /* +1 for rounding and another
  1649.                    +1 because tsleep is accurate not more than +/-(!) 1 tick */
  1650.   return(0);
  1651. }
  1652. /**********************************************************************/
  1653. psuspend(foo) int foo;
  1654. {
  1655.   return(-1);
  1656. }
  1657.  
  1658. long ttgspd()                           /* Get current tty speed */
  1659. {
  1660. struct sgbuf buffer;
  1661.   if (ttyfd < 0) return(-1);
  1662.  
  1663. #ifdef NETCONN
  1664.     if (netconn) return(-1);            /* -1 if network connection */
  1665. #endif /* NETCONN */
  1666.  
  1667.   if(_gs_opt(ttyfd,&buffer) < 0) return(-1);
  1668.   return(bdrts[buffer.sg_baud]);
  1669. }
  1670.  
  1671.  
  1672. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  1673.  *
  1674.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  1675.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  1676.  *  2 = Auto: For "modem direct": The same as "Off".
  1677.  *            For real modem types: Heed carrier during connect, but ignore
  1678.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  1679.  *
  1680.  * As you can see, this setting does not affect dialing, which always ignores
  1681.  * carrier (unless there is some special exception for some modem type).  It
  1682.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  1683.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  1684.  * (or should be) always called before any communications is tried, which
  1685.  * means that, practically speaking, the effect is immediate.
  1686.  *
  1687.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  1688.  *
  1689.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  1690.  * environment (or any non-termio using environment).  Until that time, this
  1691.  * will simply be a no-op for BSD.
  1692.  *
  1693.  * Note that in previous versions, the carrier was most often left unchanged
  1694.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  1695.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  1696.  * modes.
  1697.  */
  1698. ttscarr(carrier) int carrier; {
  1699.     ttcarr = carrier;
  1700.     debug(F101, "ttscarr","",ttcarr);
  1701.     return(ttcarr);
  1702. }
  1703.  
  1704. /*  T T G M D M  --  Get modem signals  */
  1705. /*
  1706.  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  1707.  on in as its return value, in a bit mask as described for ttwmdm.  Returns:
  1708.  -3 Not implemented
  1709.  -2 if the line does not have modem control
  1710.  -1 on error.
  1711.  >= 0 on success, with a bit mask containing the modem signals that are on.
  1712. */
  1713. ttgmdm()
  1714. {
  1715. #ifdef NETCONN
  1716.     if (netconn)                        /* Network connection */
  1717.       return(-2);                       /* No modem signals */
  1718. #endif /* NETCONN */
  1719.   return(-3);
  1720. }
  1721.  
  1722. /*  T T S S P D  --  Set the transmission of tty to ten times the argument */
  1723.  
  1724. ttsspd(speed) int speed; {
  1725. int s;
  1726. struct sgbuf before;
  1727.     debug (F101,"ttsspd: speed(cps):","",speed);
  1728.     if (ttyfd < 0) return(-1);
  1729.  
  1730. #ifdef  NETCONN
  1731.     if (netconn)
  1732.       return(0);
  1733. #endif  /* NETCONN */
  1734.  
  1735.     switch (speed) {
  1736.         case 5:         s = B50;        break;
  1737.         case 7:         s = B75;        break;
  1738.         case 11:        s = B110;       break;
  1739.         case 13:        s = B134;       break;
  1740.         case 15:        s = B150;       break;
  1741.         case 30:        s = B300;       break;
  1742.         case 60:        s = B600;       break;
  1743.         case 120:       s = B1200;      break;
  1744.         case 180:       s = B1800;      break;
  1745.         case 200:       s = B2000;      break;
  1746.         case 240:       s = B2400;      break;
  1747.         case 360:       s = B3600;      break;
  1748.         case 480:       s = B4800;      break;
  1749.         case 720:       s = B7200;      break;
  1750.         case 960:       s = B9600;      break;
  1751.         case 1920:      s = B19200;     break;
  1752.         case 3840:      s = B38400;     break;
  1753.         case 888:       return(-1); /* no 75/1200 split speed */
  1754.         default:        return -1;
  1755.     }
  1756.     _gs_opt(ttyfd,&before);
  1757.     before.sg_baud = (char)s;
  1758. #ifdef XMODE
  1759.     xmode((char)s); /* xmode open and closes => new options
  1760.                        => restore as they were before */
  1761.     return(_ss_opt(ttyfd,&before) < 0 ? -1 : s);
  1762. #else
  1763.     return(_ss_opt(ttyfd,&before) < 0 ? -1 : s);
  1764. #endif /* !XMODE */
  1765. }
  1766.  
  1767. #ifdef XMODE
  1768. int     /* change the line tty speed via xmode, special hack for bad drivers*/
  1769. xmode(os9_speed) char os9_speed;
  1770. {
  1771. char command[DEVNAMLEN+17]; /* e.g. xmode baud=38400 = 17 chars */
  1772. char devicename[DEVNAMLEN];
  1773. long old_speed;
  1774.     if ((old_speed = ttgspd()) < 0) return(-1);
  1775.     devicename[0] = '/';
  1776.     _gs_devn(ttyfd,&devicename[1]);
  1777.     sprintf(command,"xmode %s baud=%d",devicename,bdrts[os9_speed]);
  1778.     debug (F110,"xmode command = ",command,0);
  1779.     debug (F101,"xmode baud","",os9_speed);
  1780.     zsyscmd(command);
  1781.     close(ttyfd);       /* hopefully not iniz'ed */
  1782.     if ((ttyfd=open(devicename,0x43)) < 0) /* no open with new speed anymore*/
  1783.     {
  1784.       sprintf(command,"xmode %s baud=%d",devicename,old_speed);
  1785.       zsyscmd(command); /* restore old speed */
  1786.       ttyfd=open(devicename,0x43); /* now it should work again */
  1787.       return (-1);
  1788.     }
  1789.     return(os9_speed);
  1790. }
  1791. #endif /* XMODE */
  1792.  
  1793. VOID
  1794. ttimoff() {                           /* Turn off any timer interrupts */
  1795.     alarm(0);
  1796.     if (saval)
  1797.       signal(SIGALRM,saval);
  1798.     else
  1799.       signal(SIGALRM,(fptr)SIG_DFL);
  1800.     saval = NULL;
  1801. }
  1802.  
  1803. int alarm(secs) unsigned int secs;
  1804. /* after secs seconds the signal SIGALRM will be sent */
  1805. /* 0 will clear the alarm */
  1806. {
  1807.     if (secs) {
  1808.         timowhen = time((time_t *)0) + secs;
  1809.         return(add_alarm(secs,SIGALRM));
  1810.     }
  1811.     timowhen = 0;
  1812.     return(remove_alarm());
  1813. }
  1814.  
  1815. #ifndef O_GOODDRIVER
  1816. /* read from serial device with working timeout */
  1817. int
  1818. timoread(ttyfd, cp, n)
  1819. int ttyfd;
  1820. char *cp;
  1821. int n;
  1822. {
  1823.     if (timowhen == 0) return read(ttyfd, cp, n);
  1824.     (void) remove_alarm();
  1825.     for(;;) {
  1826.         if (_gs_rdy(ttyfd) >= n) return read(ttyfd, cp, n);
  1827.         if (time((time_t *)0) >= timowhen) {
  1828.             timowhen = 0;
  1829.             if (sigtbl[MAXSIG] != SIG_DFL) (*sigtbl[MAXSIG])(SIGALRM);
  1830.             return -1;
  1831.         }
  1832.         _ss_ssig(ttyfd, SIGARB);
  1833.         sleep(1);       /* interupted by _ss_ssig if incoming char */
  1834.         _ss_rel(ttyfd, SIGARB);
  1835.     }
  1836. }
  1837. #endif /* !O_GOODDRIVER */
  1838.  
  1839. /* Timeout handler for communication line input functions */
  1840. static SIGTYP
  1841. timerh(sig) int sig;{
  1842.     ttimoff();
  1843.     sigmask(-1);        /*  we are in an intercept routine but do not perform
  1844.                             a F$RTE (done implicitly but rts). => we have to
  1845.                             decrement the sigmask as F$RTE does. Warning:
  1846.                             longjump only restores the cpu registers NOT the
  1847.                             fpu registers. So, don't use fpu at all or at
  1848.                             least don't use common fpu (double or float)
  1849.                             register variables */
  1850.     longjmp(sjbuf,1);
  1851. }
  1852. int ustrncmp(a2,a3,d4) /*string compare but ignore upper and lower case*/
  1853. register char *a2,*a3;
  1854. register int d4;
  1855. {
  1856.   while((--d4>=0)&&(_toupper(*a2)==_toupper(*a3)))
  1857.   {
  1858.     if (*a3++ == '\0') return 0;
  1859.     a2++;
  1860.   }
  1861.   return (d4 < 0) ? 0 : *a2-*a3;
  1862. }
  1863.  
  1864. /* Sorry...gotta avoid namespace pollution! */
  1865. #ifdef _UCC
  1866. #define environ _environ
  1867. #endif /* _UCC */
  1868.  
  1869. #ifdef CK_REDIR
  1870. int
  1871. ttruncmd(s) char *s; {
  1872.     int r = 0;                          /* Return code */
  1873.                                         /* 0 = failure, 1 = success */
  1874.     int x = 0, status;
  1875.     int pd[2];
  1876.     int pid;
  1877.     char *argb[3];
  1878.     extern char **environ;
  1879.     extern int os9forkc();
  1880.     extern char *getenv();
  1881.  
  1882.     if (ttyfd == -1) {
  1883.         printf("?Sorry, device is not open\n");
  1884.         return(0);
  1885.     }
  1886.     conres();                           /* Make console normal  */
  1887.     pd[0] = dup(0);
  1888.     pd[1] = dup(1);
  1889.     if (pd[0] != -1) close(0);
  1890.     if (pd[1] != -1) close(1);
  1891.     if (dup(ttyfd) == 0 && dup(ttyfd) == 1) {
  1892.         SIGTYP (*istat)(), (*qstat)();
  1893.         
  1894.         istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
  1895.         qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
  1896.         if ((argb[0] = getenv("SHELL")) == (char *)0)
  1897.             argb[0] = "shell";
  1898.         argb[1] = s;
  1899.         argb[2] = (char *)0;
  1900.         if ((pid = os9exec(os9forkc, argb[0], argb, environ, 0, 0, 3)) > 0) {
  1901.             while ((x = wait(&status)) != pid && x != -1) {}
  1902.             r = 1;
  1903.         }
  1904.         signal(SIGINT,istat);           /* Restore interrupts */
  1905.         signal(SIGQUIT,qstat);
  1906.     }
  1907.     close(0);
  1908.     close(1);
  1909.     if (pd[0] != -1) dup(pd[0]);
  1910.     if (pd[1] != -1) dup(pd[1]);
  1911.     if (pd[0] != -1) close(pd[0]);
  1912.     if (pd[1] != -1) close(pd[1]);
  1913.     if (r) {
  1914.         r = 0;
  1915.         if (x == -1) {
  1916.             printf("?Can't wait for child process?\n");
  1917.         } else if (status != 0) {
  1918.             printf("?Command exit status: %d\n", status);
  1919.         } else r = 1;
  1920.     }
  1921.     concb((char)0/*escchr*/);           /* Restore console to CBREAK mode */
  1922.     return(r);
  1923. }
  1924. #endif /* CK_REDIR */
  1925.  
  1926. /* T T G W S I Z  -- get terminal window size */
  1927. /* The terminal screen size is stored in tt_rows and tt_cols */
  1928. /* We should probably get this from termcap, but for now, just use the page */
  1929. /* length defined for the console device, and assume 80 columns. */
  1930.  
  1931. extern int tt_rows, tt_cols;
  1932.  
  1933. int
  1934. ttgwsiz()
  1935. {
  1936.     tt_rows = ccold.sg_page;
  1937.     tt_cols = 80;
  1938.     return 1;
  1939. }
  1940.