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

  1. char *ckxv = "Atari ST tty I/O, 5A(087), 9 Dec 93";
  2.  
  3. /*  C K S T I O  */
  4.  
  5. /* C-Kermit interrupt, terminal control & i/o functions for Atari ST */
  6.  
  7. /*
  8.  Author: Frank da Cruz (fdc@cunixc.cc.columbia.edu, FDCCU@CUVMA.BITNET),
  9.  Columbia University Center for Computing Activities.  Many other contributors.
  10.  First released January 1985.
  11.  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  12.  York.  Permission is granted to any individual or institution to use, copy, or
  13.  redistribute this software so long as it is not sold for profit, provided this
  14.  copyright notice is retained.
  15.  Extensive modifications for Atari ST by:
  16.  Bruce Moore (mooreb@iccgcc.decnet.ab.com).
  17. */
  18.  
  19. /* Includes for all Unixes (conditional includes come later) */
  20.  
  21. #include "ckcdeb.h"            /* This moved to here. */
  22. #include "ckcnet.h"            /* Symbols for network types. */
  23.  
  24. #include <errno.h>            /* System error numbers */
  25. #include <osbind.h>            /* OS bindings */
  26. #include <xbios.h>            /* Xtended BIOS */
  27. #include <time.h>            /* time_t typedef, etc. */
  28. #include <signal.h>            /* Signals for cc trap */
  29. #define _auxis() (!! Bconstat(1))
  30. #define _auxos() (!! Bcostat(1))
  31. #define _auxin() Bconin(1)
  32. #define _auxout(x) Bconout(1,x)
  33.  
  34. #define _conis() (!! Bconstat(2))
  35. #define _conos() (!! Bcostat(2))
  36. #define _necin() (Bconin(2) & 0x7f)
  37. #define _conout(x) Bconout(2,x)
  38.  
  39. /* Maximum length for the name of a tty device */
  40.  
  41. #ifndef DEVNAMLEN
  42. #define DEVNAMLEN 25
  43. #endif
  44.  
  45. #include "ckuver.h"            /* Version herald */
  46. char *ckxsys = HERALD;
  47.  
  48. /*
  49.  Variables available to outside world:
  50.  
  51.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  52.    dfloc  -- 0 if dftty is console, 1 if external line.
  53.    dfprty -- Default parity
  54.    dfflow -- Default flow control
  55.    ckxech -- Flag for who echoes console typein:
  56.      1 - The program (system echo is turned off)
  57.      0 - The system (or front end, or terminal).
  58.    functions that want to do their own echoing should check this flag
  59.    before doing so.
  60.  
  61.    *flfnam  -- Name of lock file, including its path, e.g.,
  62.                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
  63.    *lkflfn  -- Name of link to lock file, including its paths
  64.    *haslock -- Flag set if this kermit established a uucp lock.
  65.    backgrd -- Flag indicating program executing in background ( & on
  66.                 end of shell command). Used to ignore INT and QUIT signals.
  67.    *rtu_bug -- Set by stptrap().  RTU treats ^Z as EOF (but only when we handle
  68.                 SIGTSTP)
  69.  
  70.  Functions for assigned communication line (either external or console tty):
  71.  
  72.    sysinit()               -- System dependent program initialization
  73.    *syscleanup()            -- System dependent program shutdown
  74.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  75.    ttclos()                -- Close & reset the tty, releasing any access lock.
  76.    *ttsspd(cps)             -- Set the transmission speed of the tty.
  77.    *ttgspd()                -- Get (read) the the transmission speed of the tty.
  78.    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
  79.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  80.                                 or in DIALING or CONNECTED modem control state.
  81.    ttres()                 -- Restore original tty modes.
  82.    *ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
  83.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  84.    ttinc(timo)             -- Timed read character from tty.
  85.    ttchk()                 -- See how many characters in tty input buffer.
  86.    *ttxin(n,buf)            -- Read n characters from tty (untimed).
  87.    ttol(string,length)     -- Write a string to the tty.
  88.    ttoc(c)                 -- Write a character to the tty.
  89.    ttflui()                -- Flush tty input buffer.
  90.    ttsndb()                -- Send BREAK signal.
  91.    ttsndlb()               -- Send Long BREAK signal.
  92.    ttlock(ttname)          -- "Lock" tty device against uucp collisions.
  93.    ttunlck()               -- Unlock tty device.
  94. */
  95.  
  96. /*
  97. Functions for console terminal:
  98.  
  99.    congm()   -- Get console terminal modes.
  100.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  101.    conbin(esc) -- Put the console in binary (raw) mode.
  102.    conres()  -- Restore the console to mode obtained by congm().
  103.    conoc(c)  -- Unbuffered output, one character to console.
  104.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  105.    conola(s) -- Unbuffered output, array of strings to the console.
  106.    conxo(n,s) -- Unbuffered output, n characters to the console.
  107.    conchk()  -- Check if characters available at console (bsd 4.2).
  108.                 Check if escape char (^\) typed at console (System III/V).
  109.    coninc(timo)  -- Timed get a character from the console.
  110.    congks(timo)  -- Timed get keyboard scan code.
  111.    conint()  -- Enable terminal interrupts on the console if not background.
  112.    connoi()  -- Disable terminal interrupts on the console if not background.
  113.  
  114. Time functions
  115.  
  116.    msleep(m) -- Millisecond sleep (already defined by MWC!!!)
  117.    ztime(&s) -- Return pointer to date/time string
  118.    rtimer() --  Reset timer
  119.    gtimer()  -- Get elapsed time since last call to rtimer()
  120. */
  121.  
  122. /* Declarations */
  123.  
  124. time_t time();                /* All Unixes should have this... */
  125.  
  126. extern char *malloc(), *getenv();    /* and these. */
  127. extern int errno;                       /* System call error code. */
  128. long ttgspd();                /* Declared below. */
  129.  
  130. /* dftty is the device name of the default device for file transfer */
  131. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  132.  
  133. int dfloc = 1;                  /* Default local(0) or remote(1) */
  134. char *dftty = CTTNAM;        /* Remote by default, use normal */
  135. char *dfmdm = "con:";        /* controlling terminal name. */
  136.  
  137. int dfprty = 0;            /* Default parity (0 = none) */
  138. int ttprty = 0;            /* Parity in use. */
  139. static int ttpmsk = 0377;    /* Parity stripping mask. */
  140. int ttmdm = 0;            /* Modem in use. */
  141. int ttcarr = CAR_AUT;        /* Carrier handling mode. */
  142. int dfflow = 1;            /* Xon/Xoff flow control */
  143. int backgrd = 0;        /* Assume in foreground (no '&' ) */
  144. int fdflag = 0;            /* Flag for redirected stdio */
  145. int tvtflg = 0;            /* Flag that ttvt has been called */
  146. long ttspeed = -1;        /* For saving speed */
  147. int ttflow = -9;        /* For saving flow */
  148. int ttld = -1;            /* Line discipline */
  149.  
  150. extern int ttnproto;
  151. extern int ttnet;
  152.  
  153. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  154.  
  155. /* Declarations of variables global within this module */
  156.  
  157. static time_t tcount;            /* Elapsed time counter */
  158.  
  159. static char                /* A string of nulls */
  160. *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  161.  
  162. /* static */                /* (Not static any more) */
  163. int ttyfd = -1;                /* TTY file descriptor */
  164.  
  165. static SIGTYP (*cc_handler) ();        /* Our Ctrl-C handler */
  166. static SIGTYP (*oldint) ();        /* And the old one */
  167.  
  168. static int lkf = 0,                     /* Line lock flag */
  169.     cgmf = 0,                           /* Flag that console modes saved */
  170.     xlocal = 0,                         /* Flag for tty local or remote */
  171.     curcarr = 0;            /* Carrier mode: require/ignore. */
  172.  
  173. static int netconn = 0;            /* 1 if network socket */
  174. static char escchr;                     /* Escape or attn character */
  175. static char pushchar = 0;        /* Push character */
  176.  
  177. int haslock = 0;            /* =1 if this kermit locked uucp */
  178. static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
  179.  
  180. _PROTOTYP( static int ttlock, (char *) );
  181. _PROTOTYP( static int ttunlck, (void) );
  182. #ifdef CK_ANSIC
  183. static char *
  184. xxlast(char *s, char c)
  185. #else
  186. static char *
  187. xxlast(s,c) char *s; char c;
  188. #endif /* CK_ANSIC */
  189. /* xxlast */ {        /*  Last occurrence of character c in string s. */
  190.     int i;
  191.     for (i = strlen(s); i > 0; i--)
  192.         if ( s[i-1] == c ) return( s + (i - 1) );
  193.     return(NULL);
  194. }
  195.  
  196. static char ttnmsv[DEVNAMLEN];          /* copy of open path for tthang */
  197.  
  198. /*  S Y S I N I T  --  System-dependent program initialization.  */
  199.  
  200. int
  201. sysinit() {
  202.     return(0);
  203. }
  204.  
  205. /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
  206.  
  207. int
  208. syscleanup() {
  209.     return(0);
  210. }
  211.  
  212. /*  T T O P E N  --  Open a tty for exclusive access.  */
  213.  
  214. /*
  215.   Call with:
  216.     ttname: character string - device name or network host name.
  217.     lcl:
  218.   If called with lcl < 0, sets value of lcl as follows:
  219.   0: the terminal named by ttname is the job's controlling terminal.
  220.   1: the terminal named by ttname is not the job's controlling terminal.
  221.   But watch out: if a line is already open, or if requested line can't
  222.   be opened, then lcl remains (and is returned as) -1.
  223.     modem:
  224.   Less than zero: ttname is a network host name.
  225.   Zero or greater: ttname is a terminal device name.    
  226.   Zero means a local connection (don't use modem signals).
  227.   Positive means use modem signals.  
  228.    timo:
  229.   0 = no timer.
  230.   nonzero = number of seconds to wait for open() to return before timing out.
  231.  
  232.   Returns:
  233.     0 on success
  234.    -5 if device is in use
  235.    -4 if access to device is denied
  236.    -3 if access to lock directory denied
  237.    -2 upon timeout waiting for device to open
  238.    -1 on other error
  239. */
  240. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  241.  
  242.     if (ttyfd > -1) return(0);        /* If already open, ignore this call */
  243.     ttmdm = modem;            /* Make this available to other fns */
  244.     xlocal = *lcl;            /* Make this available to other fns */
  245.  
  246.     if (strcmp(ttname, "aux:") == 0) {
  247.     if (xlocal < 0) {
  248.         if (isatty(0))    /* If con: is controlling terminal */
  249.         xlocal = 1;    /* ttname(aux) not controlling terminal */
  250.         else
  251.         xlocal = 0;    /* ttname(aux) is controlling terminal */
  252.     }
  253.     } else
  254.     return(-1);        /* aux: is the only legal device! */
  255.  
  256. /* Got the line, now set the desired value for local. */
  257.  
  258.     if (*lcl != 0) *lcl = xlocal;
  259.     ttyfd = 1;
  260.  
  261.     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
  262.     debug(F101,"ttopen, ttyfd","",ttyfd);
  263.     debug(F101," lcl","",*lcl);
  264.     return(0);
  265. }
  266.  
  267. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  268.  
  269. int
  270. ttclos(foo) int foo; {            /* Arg req'd for signal() prototype */
  271.     debug(F101,"ttclos ttyfd","",ttyfd);
  272.     if (ttyfd < 0) return(0);           /* Wasn't open. */
  273.     tvtflg = 0;
  274.  
  275.     if (xlocal) {
  276.     debug(F100,"ttclos about to call ttres","",0);
  277.     ttres();                            /* Reset device modes. */
  278.     tthang();
  279.     }
  280.     ttyfd = -1;                         /* Invalidate the file descriptor. */
  281.  
  282.     debug(F100,"ttclos done","",0);
  283.     return(0);
  284. }
  285.  
  286. /*  T T H A N G  --  Hangup phone line or network connection.  */
  287. /*
  288.   Returns:
  289.   0 if it does nothing.
  290.   1 if it believes that it hung up successfully.
  291.  -1 if it believes that the hangup attempt failed.
  292. */
  293.  
  294. int
  295. tthang() {
  296.     /* Maybe later... */
  297.     return (0);
  298. }
  299.  
  300. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  301.  
  302. /* ske@pkmab.se: There are two choices for what this function should do.
  303.  * (1) Restore the tty to current "normal" mode, with carrier treatment
  304.  * according to ttcarr, to be used after every kermit command. (2) Restore
  305.  * the tty to the state it was in before kermit opened it. These choices
  306.  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
  307.  * is currently being called as in choice (1), but ttold basically holds
  308.  * the initial parameters, as in (2), and the description at the beginning
  309.  * of this file says (2).
  310.  *
  311.  * I don't think restoring tty parameters after all kermit commands makes
  312.  * much of a difference.  Restoring them upon exit from kermit may be of
  313.  * some use in some cases (when the line is not restored automatically on
  314.  * close, by the operating system).
  315.  *
  316.  * I can't choose which one it should be, so I haven't changed it. It
  317.  * probably works as it is, too. It would probably even work even with
  318.  * ttres() entirely deleted...
  319.  *
  320.  * (from fdc: Actually, this function operates in remote mode too, so
  321.  * it restores the console (command) terminal to whatever mode it was
  322.  * in before packet operations began, so that commands work right again.)
  323.  */
  324. ttres() {                               /* Restore the tty to normal. */
  325.     if (ttyfd < 0) return(-1);          /* Not open. */
  326.     return(0);
  327. }
  328.  
  329. /*  T T P K T  --  Condition the communication line for packets. */
  330. /*              or for modem dialing */
  331.  
  332. #define DIALING 4               /* flags (via flow) for modem handling */
  333. #define CONNECT 5
  334.  
  335. /*  If called with speed > -1, also set the speed.  */
  336.  
  337. /*  Returns 0 on success, -1 on failure.  */
  338.  
  339. ttpkt(speed,flow,parity) long speed; int flow, parity; {
  340.     int s2;
  341.     int s = 0;
  342.  
  343.     if (ttyfd < 0) return(-1);          /* Not open. */
  344.  
  345.     debug(F101,"ttpkt flow","",flow);
  346.     debug(F101,"ttpkt speed","",(int) speed);
  347.     debug(F101,"ttpkt flow","",flow);
  348.  
  349.     if (tvtflg == 0 && speed == ttspeed && flow == ttflow)
  350.     return(0);            /* Already been called */
  351.  
  352.     ttprty = parity;                    /* Let other tt functions see these. */
  353.     ttpmsk = ttprty ? 0177 : 0377;    /* Parity stripping mask */
  354.     ttspeed = speed;
  355.     ttflow = flow;            /* Now make this available too. */
  356.  
  357.     if (xlocal) {
  358.     s2 = (int) (speed / 10L);    /* Convert bps to cps */
  359.     s = ttsspd(s2);            /* Check and set the speed */
  360.     debug(F101,"ttpkt carrier","",flow);
  361.     } else
  362.     s = 0;
  363.  
  364.     tvtflg = 0;                /* So ttvt() will work next time */
  365.     return(s);
  366. }
  367.  
  368. /*  T T V T -- Condition communication line for use as virtual terminal  */
  369.  
  370. ttvt(speed,flow) long speed; int flow; {
  371.     int s, s2;
  372.  
  373.     debug(F101,"ttvt ttyfd","",ttyfd);
  374.     debug(F101,"ttvt tvtflg","",tvtflg);
  375.     if (ttyfd < 0) return(-1);          /* Not open. */
  376.  
  377.     if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr)
  378.       return(0);            /* Already been called. */
  379.  
  380.     if (xlocal) {            /* For external lines... */
  381.     s2 = (int) (speed / 10L);
  382.     s = ttsspd(s2);            /* Check/set the speed */
  383.     } else
  384.     s = 0;
  385.  
  386.     ttspeed = speed;            /* Done, remember how we were */
  387.     ttflow = flow;            /* called, so we can decide how to */
  388.     ttcarr = curcarr;            /* respond next time. */
  389.     tvtflg = 0;
  390.  
  391.     debug(F101,"ttvt done","",tvtflg);
  392.     return(s);
  393. }
  394.  
  395. /*  T T S S P D  --  Checks and sets transmission rate.  */
  396.  
  397. /*  Call with speed in characters (not bits!) per second. */
  398. /*  Returns internal speed code if successful, -1 otherwise. */
  399.  
  400. int
  401. ttsspd(cps) int cps; {
  402.     int s;
  403.  
  404.     debug(F101,"ttsspd","",cps);
  405.     s = -1;
  406.  
  407.     /* First check that the given speed is valid. */
  408.  
  409.     switch (cps >= 0 ? cps : (-cps)) {
  410.     case 5:    s = 15;    break;    /* Just the common ones. */
  411.     case 11:    s = 13;    break;
  412.     case 15:    s = 11;    break;
  413.     case 30:    s = 9;    break;
  414.     case 60:    s = 8;    break;
  415.     case 120:    s = 7;    break;
  416.     case 180:    s = 6;    break;
  417.     case 240:    s = 4;    break;
  418.     case 480:    s = 2;    break;
  419.     case 960:    s = 1;    break;
  420.     case 1920:    s = 0;    break;
  421.     default:
  422.     return(-1);
  423.     }
  424.  
  425.     if ((long) cps * 10 == ttspeed)
  426.     return(s);
  427.  
  428.     if (cps >= 0) {
  429.     Rsconf(s, !!ttflow, -1,-1,-1,-1);    /* Set speed, flow */
  430.     ttspeed = (long) cps * 10;
  431.     }
  432.  
  433.     return(s);
  434. }
  435.  
  436. /* T T G S P D  -  Get speed of currently selected tty line  */
  437.  
  438. long
  439. ttgspd() {                /* Get current tty speed */
  440.     char *s;
  441.  
  442.     if (ttspeed == -1) {
  443.     if ((s = getenv("SPEED")) || (s=getenv("BAUD")) )
  444.         ttspeed = (long) atoi(s);
  445.     }
  446.     return(ttspeed);
  447. }
  448.  
  449. /*  T T F L U I  --  Flush tty input buffer */
  450.  
  451. int
  452. ttflui() {
  453.     while (_auxis())
  454.     (void) _auxin();
  455.     return(0);
  456. }
  457.  
  458. /* Interrupt Functions */
  459.  
  460. /*  C O N I N T  --  Console Interrupt setter  */
  461.  
  462. /*
  463.   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
  464.   Second arg is pointer to function to handle SIGTSTP (suspend).
  465. */
  466.  
  467. VOID                    /* Set terminal interrupt traps. */
  468. #ifdef CK_ANSIC
  469. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  470. #else
  471. conint(f,s) SIGTYP (*f)(), (*s)();
  472. #endif /* CK_ANSIC */
  473. /* conint */ {
  474.     cc_handler = f;
  475.         oldint = signal(SIGINT,f);    /* Catch terminal interrupt */
  476. }
  477.  
  478. /*  C O N N O I  --  Reset console terminal interrupts */
  479.  
  480. VOID
  481. connoi() {                              /* Console-no-interrupts */
  482.     cc_handler = NULL;
  483.         signal(SIGINT,oldint);        /* Restore old terminal interrupt */
  484. }
  485.  
  486. /*  G E N B R K  --  Simulate a modem break.  */
  487.  
  488. #define BSPEED 5
  489. VOID
  490. genbrk(fn,msec) int fn, msec; {
  491.     int oldspeed;
  492.     int x, y;
  493.  
  494.     oldspeed = (int) (ttgspd() / 10);
  495.     ttsspd(15);                    /* 150 baud */
  496.  
  497.     y = strlen(brnuls);
  498.     x = ( BSPEED * 100 ) / msec;
  499.     if (x > y) x = y;
  500.     ttol(brnuls, (( BSPEED * 100 ) / msec ));    /* A plethora of nuls */
  501.  
  502.     msleep(100);                /* Sleep 100 ms. */
  503.     ttsspd(oldspeed);                /* restore old speed */
  504.     return(0);
  505. }
  506.  
  507. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  508.  
  509. /*  Some callers of this want to know whether there is something to read
  510.  *  either in the system buffers or in our private buffers (and mostly don't
  511.  *  care how many characters, just whether it's more than zero or not), while
  512.  *  some others would be better off with the number of characters in our
  513.  *  private buffers only.
  514.  *
  515.  *  Some systems can say how many characters there are in the system buffers.
  516.  *  Others can not. For those that can't, the number in the private buffers
  517.  *  will have to do (or should we put the tty into O_NDELAY-mode and try to
  518.  *  read one character?). If the system can tell whether there is zero or
  519.  *  more than zero characters, we can return 1 in the latter case even if the
  520.  *  private buffer is empty. (That is good for sliding windows.)
  521.  */
  522. int
  523. ttchk() {
  524.     return(_auxis());
  525. }
  526.  
  527. /*  T T X I N  --  Get n characters from tty input buffer  */
  528.  
  529. /*  Returns number of characters actually gotten, or -1 on failure  */
  530.  
  531. /*  Intended for use only when it is known that n characters are actually */
  532. /*  Available in the input buffer.  */
  533.  
  534. int
  535. ttxin(n,buf) int n; CHAR *buf; {
  536.     CHAR *p;
  537.  
  538.     ttpmsk = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  539.     debug(F101,"ttxin n","",n);
  540.  
  541.     for (p = buf; _auxis() && n--; )
  542.     *p++ = _auxin() & ttpmsk;
  543.  
  544.     *p = '\0';
  545.     return((int) (p - buf));
  546. }
  547.  
  548. /*  T T O L  --  Write string s, length n, to communication device.  */
  549. /*
  550.   Returns:
  551.    >= 0 on success, number of characters actually written.
  552.    -1 on failure.
  553. */
  554. int
  555. ttol(s,n) int n; char *s; {
  556.     int i;
  557.  
  558.     for(i = n; i--; )
  559.     _auxout(*s++);
  560.     return(n);
  561. }
  562.  
  563. /*  T T O C  --  Output a character to the communication line  */
  564.  
  565. /*
  566.  This function should only be used for interactive, character-mode operations,
  567.  like terminal connection, script execution, dialer i/o, where the overhead
  568.  of the signals and alarms does not create a bottleneck.
  569. */
  570. int
  571. #ifdef CK_ANSIC
  572. ttoc(char c)
  573. #else
  574. ttoc(c) char c;
  575. #endif /* CK_ANSIC */
  576. /* ttoc */ {
  577.     c &= 0xff;
  578.     if (ttyfd < 0) return(-1);          /* Check for not open. */
  579.     _auxout(c);
  580.     return(0);
  581. }
  582.  
  583. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  584. /*
  585.   Reads up to "max" characters from the communication line, terminating on:
  586.   
  587.     (a) the packet length field if the "turn" argument is zero, or
  588.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  589.  
  590.   and returns the number of characters read upon success, or if "max" was
  591.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  592.  
  593.   The characters that were input are copied into "dest" with their parity bits
  594.   stripped if parity was selected.  Returns the number of characters read.
  595.   Characters after the eol are available upon the next call to this function.
  596.  
  597.   The idea is to minimize the number of system calls per packet, and also to
  598.   minimize timeouts.  This function is the inner loop of the program and must
  599.   be as efficient as possible.  The current strategy is to use myread().
  600.  
  601.   WARNING: this function calls parchk(), which is defined in another module.
  602.   Normally, ckutio.c does not depend on code from any other module, but there
  603.   is an exception in this case because all the other ck?tio.c modules also
  604.   need to call parchk(), so it's better to have it defined in a common place.
  605. */
  606. #ifdef CTRLC
  607. #undef CTRLC
  608. #endif /* CTRLC */
  609. #define CTRLC '\03'
  610. /*
  611.   We have four different declarations here because:
  612.   (a) to allow Kermit to be built without the automatic parity sensing feature
  613.   (b) one of each type for ANSI C, one for non-ANSI.
  614. */
  615.  
  616. int
  617. #ifdef PARSENSE
  618. #ifdef CK_ANSIC
  619. ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
  620. #else
  621. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
  622. #endif /* CK_ANSIC */
  623. #else /* not PARSENSE */
  624. #ifdef CK_ANSIC
  625. ttinl(CHAR *dest, int max,int timo, CHAR eol)
  626. #else
  627. ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  628. #endif /* __SDTC__ */
  629. #endif /* PARSENSE */
  630. /* ttinl */ {
  631.  
  632.     time_t tfinal;            /* Time to quit */
  633.     int count;                /* Number rec'd so far */
  634.     int c;                /* Current character */
  635.     int ccn;                /* Control-C counter */
  636.  
  637.     if (ttyfd < 0) return(-1);          /* Not open. */
  638.  
  639.     debug(F101,"ttinl max","",max);
  640.     debug(F101,"ttinl timo","",timo);
  641.  
  642.     ccn = 0;                /* Control-C counter */
  643.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Parity stripping mask. */
  644.     *dest = '\0';                       /* Clear destination buffer */
  645.     if (timo < 0) timo = 0;        /* Safety */
  646.  
  647.     tfinal = time(NULL) + timo;
  648.     for (count = 0; count < max; count++) {
  649.     while (timo && ! _auxis()) {    /* Timed read... */
  650.         if (_conis() && (pushchar = coninc(0)) == CTRLC) {    /* ^C on con?*/
  651.         if (cc_handler) {        /* Handler active? */
  652.             pushchar = 0;        /* Flush push character */
  653.             (* cc_handler) (SIGINT);    /* Call handler */
  654.         }
  655.         }
  656.         if (time(NULL) > tfinal) {    /* If read times out */
  657.         debug(F100,"ttinl timout","",0);
  658.         debug(F111," with", dest, count);
  659.         return(-1);        /* Time out */
  660.         }
  661.     }
  662.     c = _auxin();
  663. #ifdef COMMENT
  664. /* Not needed, since we're always in local mode. */
  665.     if ((c & 0x7f) == CTRLC) {
  666.         if (++ccn > 1) {
  667.         fprintf(stderr, "^C...\r\n");    /* Echo Ctrl-C */
  668.         return(-2);
  669.         }
  670.     } else                /* Not ^C, so reset ^C counter */
  671.         ccn = 0;
  672. #endif /* COMMENT */
  673.     if ((c & 0x7f) == eol) {
  674.         debug(F101,"ttinl got eol","",eol);
  675.         *dest = '\0';        /* Yes, terminate the string, */
  676.         break;
  677.     }
  678.     *dest++ = c & ttpmsk;
  679.     }
  680.     return(count);
  681. }
  682.  
  683. /*  T T I N C --  Read a character from the communication line  */
  684. /*
  685.  On success, returns the character that was read, >= 0.
  686.  On failure, returns -1 or other negative myread error code.
  687. */
  688. int
  689. ttinc(timo) int timo; {
  690.     time_t tfinal;
  691.     int m;
  692.  
  693.     if (ttyfd < 0) return(-1);          /* Not open. */
  694.  
  695.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Parity stripping mask. */
  696.     if (timo < 0) timo = 0;        /* Safety */
  697.     tfinal = time(NULL) + timo;
  698.  
  699.     while (timo && ! _auxis()) {    /* Timed read... */
  700.     if (_conis() && (pushchar = coninc(0)) == CTRLC) {    /* ^C on con?*/
  701.         if (cc_handler) {            /* Handler active? */
  702.         pushchar = 0;            /* Flush push character */
  703.         (* cc_handler) (SIGINT);    /* Call handler */
  704.         }
  705.     }
  706.     if (time(NULL) > tfinal)
  707.         return(-1);
  708.     }
  709.     return(_auxin() & ttpmsk);
  710. }
  711.  
  712. /*  S N D B R K  --  Send a BREAK signal of the given duration  */
  713.  
  714. static int
  715. #ifdef CK_ANSIC
  716. sndbrk(int msec)            /* Argument is milliseconds */
  717. #else
  718. sndbrk(msec) int msec;
  719. #endif /* CK_ANSIC */
  720. /* sndbrk */ {
  721.     genbrk(ttyfd, msec);
  722. }
  723.  
  724. /*  T T S N D B  --  Send a BREAK signal  */
  725.  
  726. int
  727. ttsndb() {
  728.     return(sndbrk(275));
  729. }
  730.  
  731. /*  T T S N D L B  --  Send a Long BREAK signal  */
  732.  
  733. int
  734. ttsndlb() {
  735.     return(sndbrk(1500));
  736. }
  737.  
  738. /*  M S L E E P  --  Millisecond version of sleep().  */
  739.  
  740. /*
  741.   Call with number of milliseconds (thousandths of seconds) to sleep.
  742.   Intended only for small intervals.  For big ones, just use sleep().
  743.   Highly system-dependent.
  744.   Returns 0 always, even if it didn't work.
  745.   The problem is that MWC\msleep takes a long.  Kludge, kludge!
  746. */
  747.  
  748. #ifdef GEMDOS
  749. #ifdef msleep
  750. #undef msleep
  751. #else    /* msleep */
  752. #error Must add -Dmsleep=mnap on command line!
  753. #endif    /* msleep */
  754. int
  755. mnap(m) int m; {
  756.     msleep((long) m);            /* Use MWC function */
  757. }
  758. #else    /* GEMDOS */
  759. int
  760. msleep(m) int m; {
  761.     clock_t elapsed;
  762.     clock_t done;
  763.  
  764.     done = clock() + (clock_t) m / CLK_TCK;
  765.     while ((elapsed = clock() - done) < 0x7FFF)
  766.     ;
  767. }
  768. #endif    /* GEMDOS */
  769.  
  770. /*  R T I M E R --  Reset elapsed time counter  */
  771.  
  772. VOID
  773. rtimer() {
  774.     tcount = time( (time_t *) 0 );
  775. }
  776.  
  777.  
  778. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  779.  
  780. int
  781. gtimer() {
  782.     int x;
  783.     x = (int) (time( (time_t *) 0 ) - tcount);
  784.     debug(F101,"gtimer","",x);
  785.     return( (x < 0) ? 0 : x );
  786. }
  787.  
  788.  
  789. /*  Z T I M E  --  Return date/time string  */
  790.  
  791. VOID
  792. ztime(s) char **s; {
  793.     char *ctime();
  794.     time_t clock_storage;
  795.  
  796.     clock_storage = time( (time_t *) 0 );
  797.     *s = ctime( &clock_storage );
  798. }
  799.  
  800. /*  C O N G M  --  Get console terminal modes.  */
  801.  
  802. /*
  803.   Saves initial console mode, and establishes variables for switching
  804.   between current (presumably normal) mode and other modes.
  805.   Should be called when program starts, but only after establishing
  806.   whether program is in the foreground or background.
  807.   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
  808. */
  809. int
  810. congm() {
  811.     return(0);
  812. }
  813.  
  814.  
  815. /*  C O N C B --  Put console in cbreak mode.  */
  816.  
  817. /*  Returns 0 if ok, -1 if not  */
  818.  
  819. int
  820. #ifdef CK_ANSIC
  821. concb(char esc)
  822. #else
  823. concb(esc) char esc;
  824. #endif /* CK_ANSIC */
  825. /* concb */ {
  826.     if (!isatty(0)) return(0);          /* only for real ttys */
  827.     escchr = esc;                       /* Make this available to other fns */
  828.     ckxech = 1;                         /* Program can echo characters */
  829.     return(0);
  830. }
  831.  
  832. /*  C O N B I N  --  Put console in binary mode  */
  833.  
  834. /*  Returns 0 if ok, -1 if not  */
  835.  
  836. int
  837. #ifdef CK_ANSIC
  838. conbin(char esc)
  839. #else
  840. conbin(esc) char esc;
  841. #endif /* CK_ANSIC */
  842. /* conbin */  {
  843.     if (!isatty(0)) return(0);          /* only for real ttys */
  844.     debug(F100,"conbin","",0);
  845.     escchr = esc;                       /* Make this available to other fns */
  846.     ckxech = 1;                         /* Program can echo characters */
  847.     return(0);
  848. }
  849.  
  850.  
  851. /*  C O N R E S  --  Restore the console terminal  */
  852.  
  853. int
  854. conres() {
  855.     debug(F100,"entering conres","",0);
  856.     if (!isatty(0)) return(0);          /* only for real ttys */
  857.     debug(F100,"conres isatty ok","",0);
  858.     ckxech = 0;                         /* System should echo chars */
  859.     return(0);
  860. }
  861.  
  862. /*  C O N O C  --  Output a character to the console terminal  */
  863.  
  864. int
  865. #ifdef CK_ANSIC
  866. conoc(char c)
  867. #else
  868. conoc(c) char c;
  869. #endif /* CK_ANSIC */
  870. /* conoc */ {
  871.     putchar(c);
  872.     fflush(stdout);
  873. }
  874.  
  875. /*  C O N X O  --  Write x characters to the console terminal  */
  876.  
  877. int
  878. conxo(x,s) char *s; int x; {
  879.     while (x--)
  880.     putchar(*s++);
  881.     fflush(stdout);
  882. }
  883.  
  884. /*  C O N O L  --  Write a line to the console terminal  */
  885.  
  886. int
  887. conol(s) char *s; {
  888.     fputs(s, stdout);
  889.     fflush(stdout);
  890. }
  891.  
  892. /*  C O N O L A  --  Write an array of lines to the console terminal */
  893.  
  894. int
  895. conola(s) char *s[]; {
  896.     int i;
  897.     for (i=0 ; *s[i] ; i++) conol(s[i]);
  898. }
  899.  
  900. /*  C O N O L L  --  Output a string followed by CRLF  */
  901.  
  902. int
  903. conoll(s) char *s; {
  904.     fputs(s, stdout);
  905.     fputs("\r\n", stdout);
  906. }
  907.  
  908. /*  C O N C H K  --  Return how many characters available at console  */
  909.  
  910. int
  911. conchk() {
  912.     if (xlocal)            /* If this Kermit is running on a local box */
  913.     return(_conis());    /* Return chars available at console */
  914.     else            /* This Kermit running on remote box */
  915.     return(_auxis());    /* Otherwise return chars available */
  916. }
  917.  
  918. /*  C O N I N C  --  Get a character from the console  */
  919.  
  920. int
  921. coninc(timo) int timo; {
  922.     time_t tfinal;
  923.     CHAR ch;
  924.  
  925.     if (timo < 0) timo = 0;
  926.     tfinal = time(NULL) + timo;
  927.  
  928.     if (pushchar) {            /* Do we have a pushed character? */
  929.     ch = pushchar & 0377;        /* If so, use it */
  930.     pushchar = 0;            /* But only once */
  931.     } else if (xlocal) {        /* If Kermit is running on local box */
  932.     if (timo) {            /* If timed read... */
  933.         while (! _conis()) {        /* While no console chars */
  934.         if (time(NULL) > tfinal)    /* If time is up... */
  935.             return(-1);        /* tell our caller */
  936.         }
  937.     }
  938.     ch = _necin() & 0377;
  939.     } else {            /* This Kermit running on remote box */
  940.     if (timo) {            /* If timed read... */
  941.         while (! _auxis()) {        /* While no console chars */
  942.         if (time(NULL) > tfinal)    /* If time is up... */
  943.             return(-1);        /* tell our caller */
  944.         }
  945.     }
  946.     ch = _auxin() & 0377;
  947.     }
  948.     if (ch == CTRLC) {            /* ^C ? */
  949.     if (cc_handler)            /* Handler active? */
  950.         (* cc_handler) (SIGINT);    /* Call handler */
  951.     }
  952.     return(ch);
  953. }
  954.  
  955. /*  C O N G K S  --  Console Get Keyboard Scancode  */
  956.  
  957. #ifndef congks
  958. /*
  959.   This function needs to be filled in with the various system-dependent
  960.   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
  961.   keyboard scan code.  For now, it's a dummy.
  962. */
  963. int
  964. congks(timo) int timo; {
  965.     return(coninc(timo));
  966. }
  967. #endif /* congks */
  968.  
  969. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  970.  *
  971.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  972.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  973.  *  2 = Auto: For "modem direct": The same as "Off".
  974.  *            For real modem types: Heed carrier during connect, but ignore
  975.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  976.  *
  977.  * As you can see, this setting does not affect dialing, which always ignores
  978.  * carrier (unless there is some special exception for some modem type).  It
  979.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  980.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  981.  * (or should be) always called before any communications is tried, which
  982.  * means that, practically speaking, the effect is immediate.
  983.  *
  984.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  985.  *
  986.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  987.  * environment (or any non-termio using environment).  Until that time, this
  988.  * will simply be a no-op for BSD.
  989.  *
  990.  * Note that in previous versions, the carrier was most often left unchanged
  991.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  992.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  993.  * modes.
  994.  */
  995. int
  996. ttscarr(carrier) int carrier; {
  997.     ttcarr = carrier;
  998.     debug(F101, "ttscarr","",ttcarr);
  999.     return(ttcarr);
  1000. }
  1001.  
  1002. /*  T T G M D M  --  Get modem signals  */
  1003. /*
  1004.  Looks for RS-232 modem signals, and returns those that are on in as its
  1005.  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
  1006.  Returns: 
  1007.  -3 Not implemented
  1008.  -2 if the communication device does not have modem control (e.g. telnet)
  1009.  -1 on error.
  1010.  >= 0 on success, with a bit mask containing the modem signals that are on.
  1011. */
  1012.  
  1013. int
  1014. ttgmdm() {
  1015.     return(-3);
  1016. }
  1017.  
  1018. /*  P S U S P E N D  --  Put this process in the background.  */
  1019.  
  1020. /*
  1021.   Call with flag nonzero if suspending is allowed, zero if not allowed.
  1022.   Returns 0 on apparent success, -1 on failure (flag was zero, or
  1023.   kill() returned an error code.
  1024. */
  1025. int
  1026. psuspend(flag) int flag; {
  1027.  
  1028.     return(-1);
  1029. }
  1030.