home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckmtio.c < prev    next >
C/C++ Source or Header  |  1994-08-19  |  55KB  |  1,819 lines

  1. char *ckxv = "Communications I/O, 5A(082), 17 Aug 94";
  2.  
  3. /*  C K M T I O  --  interrupt, console, and port functions for Mac Kermit  */
  4. /*
  5. COPYRIGHT NOTICE:
  6.  
  7.   Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New
  8.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  9.   sold for profit as a software product itself, nor may it be included in or
  10.   distributed with commercial products or otherwise distributed by commercial
  11.   concerns to their clients or customers without written permission of the
  12.   Office of Kermit Development and Distribution, Columbia University.  This
  13.   copyright notice must not be removed, altered, or obscured.
  14. */
  15. /*
  16.  Variables:
  17.  
  18.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  19.    dfloc  -- 0 if dftty is console, 1 if external line.
  20.    dfprty -- Default parity
  21.    dfflow -- Default flow control
  22.    ckxech -- Flag for who echoes console typein:
  23.      1 - The program (system echo is turned off)
  24.      0 - The system (or front end, or terminal).
  25.    functions that want to do their own echoing should check this flag
  26.    before doing so.
  27.  
  28.  Functions for assigned communication line (either external or console tty):
  29.  
  30.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  31.    ttclos()                -- Close & reset the tty, releasing any access lock.
  32.    ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
  33.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  34.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  35.    ttinc(timo)             -- Timed read character from tty.
  36.    ttchk()                 -- See how many characters in tty input buffer.
  37.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  38.    ttol(string,length)     -- Write a string to the tty.
  39.    ttoc(c)                 -- Write a character to the tty.
  40.    ttflui()                -- Flush tty input buffer.
  41.  
  42. Functions for console terminal:
  43.  
  44.    congm()   -- Get console terminal modes.
  45.    concb()   -- Put the console in single-character wakeup mode with no echo.
  46.    conbin()  -- Put the console in binary (raw) mode.
  47.    conres()  -- Restore the console to mode obtained by congm().
  48.    conoc(c)  -- Unbuffered output, one character to console.
  49.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  50.    conxo(n,s) -- Unbuffered output, n characters to the console.
  51.    conchk()  -- Check if characters available at console.
  52.    coninc()  -- Get a character from the console.
  53.    conint()  -- Enable terminal interrupts on the console.
  54.    connoi()  -- Disable terminal interrupts on the console.
  55.  
  56. Time functions
  57.  
  58.    msleep(m) -- Millisecond sleep
  59.    ztime(&s) -- Return pointer to date/time string
  60. */
  61.  
  62. #include <StdArg.h>
  63.  
  64. #include "ckcdeb.h"        /* Formats for debug() */
  65. #include "ckcker.h"        /* kermit defs */
  66. #include "ckmdef.h"        /* macintosh defs */
  67. #include "ckcasc.h"
  68. #include "ckmwin.h"
  69. #include "ckmcon.h"
  70. #include "ckmptp.h"        /* ckm* Prototypes */
  71. #include "ckuusr.h"
  72.  
  73. char *dftty = "Modem";
  74.  
  75. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  76.  
  77. int dfloc = 1;
  78.  
  79. /* Other defaults */
  80.  
  81. int dfprty = 0;            /* Default parity */
  82. int ttprty = 0;            /* Parity in use. */
  83. long ttspeed = -1;        /* For saving speed */
  84. int dfflow = 1;            /* Xon/Xoff flow control */
  85. int ttflow = -9;        /* For saving flow */
  86. int fDTR = 0;            /* DTR input flow control */
  87. int fCTS = 0;            /* CTS output flow control */
  88. int fInX = 0;            /* send xoff when buffer almost full */
  89.  
  90. int backgrd = 0;        /* a Mac is allways in foreground */
  91.  
  92. /* Local variables */
  93.  
  94. int drop_dtr = 0;        /* drop DTR on Quit */
  95.  
  96. /* buffer and pointer for input processing */
  97. static char *my_input_buf;    /* we give this to the serial driver queue */
  98.  
  99. /* Private buffer for myread() and its companions.  Not for use by anything
  100.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  101.  * allowed to read my_count.
  102.  *
  103.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  104.  *
  105.  * A global parity mask variable could be useful too.  We could use it to
  106.  * let myread() strip the parity on its own, instead of stripping sign
  107.  * bits as it does now.
  108.  */
  109.  
  110. /* #define MYBUFLEN 256 */
  111. #define MYBUFLEN 2048
  112. static unsigned char *mybufp;        /* Buffer, including push back */
  113. static int my_count = 0;        /* Number of chars still in mybuf */
  114. static int my_item = -1;        /* Last index read from mybuf[] */
  115.  
  116.  
  117. #ifdef COMMENT
  118. #define TTBUFL 200        /* good size (it's RBUFL guys!) */
  119. static unsigned char *ttbuf;
  120. #endif
  121.  
  122. static char *tto_buf;            /* output buffer for ttol() */
  123. static ParamBlockRec iopb;        /* paramater block for ttol() */
  124. static long tto_startticks;        /* when we started the output */
  125. #define XOFFTIMEO 480L            /* a timeout of 8 seconds (in ticks) */
  126.  
  127. short dfltVol;                /* Volume for Take- and Log-File */
  128.  
  129. /* true if using RAM serial driver (usually TRUE) */
  130. extern Boolean usingRAMdriver, 
  131.   have_128roms;                /* True if we are a Plus or better */
  132. extern char ttname[];
  133.  
  134. extern  SIGTYP (*alarmfunc)();
  135. extern  SIGTYP (*intfunc)();
  136. typedef unsigned long ulong;
  137. extern ulong alarmtime;            /* Global alarm time */
  138.  
  139. extern int pflag;
  140.  
  141. static void ucharout (char c);
  142.  
  143. /****************************************************************************/
  144. /*  S Y S I N I T  --  System-dependent program initialization.  */
  145. /****************************************************************************/
  146. sysinit() {
  147.     ParamBlockRec pb;
  148.     
  149.     mac_init ();            /* Set up the Mac */
  150.  
  151.     /* Get the default volume reference number for Take- and Log-Files */
  152.     pb.volumeParam.ioNamePtr = NIL;
  153.     PBGetVol (&pb, FALSE);
  154.     dfltVol = pb.volumeParam.ioVRefNum;
  155.  
  156.     findfinderfiles();            /* See if file was selected */
  157.     mac_post_load_init();        /* Show the terminal window etc */
  158.     return(0);
  159. } /* sysinit */
  160.  
  161. /* init terminal I/O buffers */
  162. inittiobufs()
  163. {
  164. #ifdef COMMENT
  165.     if ((ttbuf = (unsigned char *) NewPtr(TTBUFL + 1)) == NIL)
  166.         macfatal("Can't allocate ttbuf", 0);
  167. #endif
  168.     if ((mybufp = (unsigned char *) NewPtr(MYBUFLEN + 4)) == NIL)
  169.         macfatal("Can't allocate mybufp", 0);
  170.     my_count = 0;        /* Number of chars still in mybuf */
  171.     my_item = -1;        /* Last index read from mybuf[] */
  172.  
  173.     if ((tto_buf = (char *) NewPtr(MAXSP)) == NIL)
  174.         macfatal("Can't allocate tto_buf", 0);
  175.     if ((my_input_buf = (char *) NewPtr(MYBUFSIZE)) == NIL)
  176.         macfatal("Can't allocate my_input_buf", 0);
  177. }
  178.  
  179. /****************************************************************************/
  180. /* P O R T _ O P E N -- Open and init a serial port.  port is either -6 (for */
  181. /*  the modem port) or -8 (for the printer port)                */
  182. /****************************************************************************/
  183.  
  184. #ifdef MPW
  185. #define RamSDOpen RAMSDOPEN        /* fix routine name */
  186. #else    /* !MPW (Think C) */
  187. #define RamSDOpen(n)    (noErr)        /* don't really do anything */
  188. #endif    /* !MPW */
  189.  
  190. port_open (int port)
  191. {
  192.     int err;
  193.         
  194.     if ((port != -6) && (port != -8))
  195.     port = -6;
  196.  
  197. try_again:
  198.     /* Set up IO drivers */
  199.     innum = port;
  200.     outnum = port - 1;
  201.     if (innum == -6) {
  202.     if (((err = OpenDriver ("\p.AIn", &innum)) != noErr) ||
  203.         ((err = OpenDriver ("\p.AOut", &outnum)) != noErr)) {
  204.         printerr ("Could not open the Modem port: ", err);
  205.         innum = outnum = 0;        /* Mark the port as closed */
  206.         return;
  207.     }
  208.     } else {
  209.     if (((err = OpenDriver ("\p.BIn", &innum)) != noErr) ||
  210.         ((err = OpenDriver ("\p.BOut", &outnum)) != noErr)) {
  211.         printerr("Could not open the Printer port.  Try\
  212.  turning off Appletalk.", 0);
  213.         port = -6;
  214.         goto try_again;
  215.     }
  216.     }
  217.         
  218.     /* try for the RAM driver */
  219.     if (innum == -6)
  220.     err = RamSDOpen (sPortA);
  221.     else
  222.     err = RamSDOpen (sPortB);
  223.     
  224.     if (err == noErr) {
  225.     usingRAMdriver = TRUE;
  226.     } else {
  227.     usingRAMdriver = FALSE;
  228.     printerr("Can't open RAM serial driver; using the ROM driver\
  229.  (without flow control).",0);
  230.     }
  231.  
  232.     err = SerSetBuf (innum, my_input_buf, MYBUFSIZE);
  233.             /* Make driver use larger buff */
  234.     if (err)
  235.     printerr ("Trouble making IO buffer:", err);
  236.  
  237.     switch (port) {
  238.     case -6:
  239.     strcpy(ttname, "Modem");
  240.     break;
  241.     case -8:
  242.     strcpy(ttname, "Printer");
  243.     break;
  244.     }
  245. }
  246.  
  247. /*****************************************************************************/
  248. /* P O R T _ C L O S E -- Close down the serial port.                 */
  249. /*****************************************************************************/
  250.  
  251. #ifdef MPW
  252. #define RamSDClose RAMSDCLOSE
  253. #else    /* !MPW (Think C) */
  254. #define RamSDClose(n)        /*NOTHING*/
  255. #endif    /* !MPW */
  256.  
  257. port_close()
  258. {
  259.     int err;
  260.     ParamBlockRec cpb;
  261.     
  262.     if (!innum)
  263.         return;            /* already closed */
  264.  
  265.     err = KillIO(innum);    /* Kill off IO drivers */
  266.     if (err != noErr)
  267.         printerr("trouble KillIO-ing serial input driver:",err);
  268.     err = KillIO(outnum);    /* Kill off IO drivers */
  269.     if (err != noErr)
  270.         printerr("trouble KillIO-ing serial output driver:",err);
  271.  
  272.     err = SerSetBuf (innum, NULL, 0);    /* Make driver default buffer */
  273.     if (err != noErr)
  274.         printerr("trouble resetting serial IO buffer:",err);
  275.  
  276.     if (usingRAMdriver) {
  277.     if (!drop_dtr) {
  278.         bzero((char *) &cpb, sizeof(cpb));
  279.         cpb.cntrlParam.ioNamePtr = NULL;    /* IM-IV p226 */
  280.         /* tell the ram driver not to lower DTR on close */
  281.         cpb.cntrlParam.csCode = 16;        /* misc serial control */
  282.         *((unsigned char *) cpb.cntrlParam.csParam) = 0x80;
  283.                 /* don't lower DTR */
  284.         cpb.cntrlParam.ioCRefNum = innum;
  285.         err = PBControl(&cpb, FALSE);
  286.         if ((err != noErr) && (err != -1))
  287.         printerr(
  288.           "trouble telling RAM serial driver (in) not to lower DTR:",
  289.              err);
  290.  
  291.         bzero((char *) &cpb, sizeof(cpb));
  292.         cpb.cntrlParam.ioNamePtr = NULL;    /* IM-IV p226 */
  293.         cpb.cntrlParam.csCode = 16;        /* misc serial control */
  294.         /* don't lower DTR */
  295.         *((unsigned char *) cpb.cntrlParam.csParam) = 0x80;
  296.         cpb.cntrlParam.ioCRefNum = outnum;
  297.         err = PBControl(&cpb, FALSE);
  298.         if ((err != noErr) && (err != -1))
  299.           printerr("\
  300. trouble telling RAM serial driver (out) not to lower DTR:",err);
  301.     }
  302.  
  303.     RamSDClose (sPortA);    /* this "returns" void */
  304.     }
  305.     
  306.     err = CloseDriver (innum);
  307.     if (err != noErr)
  308.     printerr("trouble closing serial input driver:",err);
  309. /*
  310.  * For some reason or other, doing this close on a 64k ROM machine will cause
  311.  * the mouse to freeze.  Since the input driver is the only one that really
  312.  * matters, we just close it.
  313.  */
  314.     if (have_128roms) {
  315.     err = CloseDriver (outnum);
  316.     if (err != noErr)
  317.         printerr("trouble closing serial output driver:",err);
  318.     }
  319.     
  320.     /* mark things as closed */
  321.     innum = outnum = 0;
  322. }
  323.  
  324. /****************************************************************************/
  325. /*  T T O P E N  --  Open a tty for exclusive access.  */
  326. /*                                                       */
  327. /*  ttname = C string, name of communications device     */
  328. /*  lcl    = (doesn't mean anything in Mac Kermit        */
  329. /*  modem  = 0 if no modem, positive if there is a modem */
  330. /*  timeo  = (not used in Mac Kermit)                    */
  331. /*                                                       */
  332. /*  Returns 0 on success, -1 on failure.                 */
  333. /****************************************************************************/
  334. int
  335. ttopen (ttname, lcl, modem, timeo)
  336. char *ttname;
  337. int *lcl;
  338. int modem;
  339. int timeo;
  340. #pragma unused (modem, timeo)
  341. {
  342.     int port, *aport;
  343.     char tmp[100];
  344.  
  345.     my_count = 0;            /* Initialize myread() stuff */
  346.     my_item = -1;
  347.  
  348.     if (*lcl < 0)
  349.       *lcl = 1;                /* Always in local mode */
  350.  
  351.     if (mybufp == NIL)
  352.       macfatal("No mybufp", 0);
  353.     if (tto_buf == NIL)
  354.       macfatal("No tto_buf", 0);
  355.     if (my_input_buf == NIL)
  356.       macfatal("No my_input_buf", 0);
  357.  
  358.     iopb.ioParam.ioResult = 0;        /* No pending output */
  359.     
  360.     iopb.ioParam.ioActCount = 0;    /* For error checking in ttol() */
  361.     iopb.ioParam.ioReqCount = 0;
  362.     
  363.     /* Re-open the port if it has changed. */
  364.  
  365.     strcpy(tmp, ttname);
  366.     (void) lower(tmp);
  367.     if (strcmp(tmp, "printer") == 0)
  368.       port = -8;
  369.     else if (strcmp(tmp, "modem") == 0)
  370.       port = -6;
  371.     else {
  372.     printfalert("Unknown port \"%s\" (\"%s\"), using Modem", ttname, tmp);
  373.     port = -6;
  374.     }
  375.     aport = &port;
  376.     if (port != innum) {        /* If port changed */
  377.     int saved_drop_dtr;
  378.     saved_drop_dtr = drop_dtr;
  379.     drop_dtr = 1;            /* So we don't confuse AppleTalk */
  380.     port_close();
  381.     drop_dtr = saved_drop_dtr;
  382.     port_open(port);
  383.     if (!setserial (innum, outnum, speed, KPARITY_NONE))
  384.       printfalert("Problem setting port speed");
  385.     (void) sershake(flow);        /* Set flow control */
  386.     }
  387.     return (0);
  388. } /* ttopen */
  389.  
  390. /****************************************************************************/
  391. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  392. /****************************************************************************/
  393. int
  394. ttclos ()
  395. {
  396.     my_count = 0;            /* Initialize myread() stuff */
  397.     my_item = -1;
  398.  
  399.     return 0;
  400. }                /* ttclos */
  401.  
  402. /*
  403.  * sershake
  404.  * Set handshake parameters on serial port.
  405.  */
  406. int sershake (int flow)
  407. {
  408.     int err;
  409.     ParamBlockRec pb;
  410.     SerShk *controlparam;    /* To change serial driver paramaters */
  411.  
  412.     if (!innum)
  413.         return 0;        /* if port closed, do nothing */
  414.  
  415.     bzero((char *)&pb, sizeof(pb));
  416.     controlparam = (SerShk *) &pb.cntrlParam.csParam;
  417.     /*
  418.      * Old code used to issue controls to in and out sides. IM-IV
  419.      * says to use the output driver.
  420.      */
  421.     pb.cntrlParam.ioCRefNum = outnum;
  422.     if (have_128roms)
  423.       pb.cntrlParam.csCode = 14;    /* SerHShake + DTR */
  424.     else
  425.       pb.cntrlParam.csCode = 10;    /* SerHShake */
  426.  
  427.     if (flow)
  428.       controlparam->fXOn = TRUE;    /* obey flow control */
  429.     else
  430.       controlparam->fXOn = FALSE;    /* ignore flow control */
  431.     controlparam->fCTS = fCTS;        /* output flow control */
  432.     controlparam->xOn = 17;
  433.     controlparam->xOff = 19;
  434.     controlparam->errs = FALSE;
  435.     controlparam->evts = FALSE;
  436.     if (flow && usingRAMdriver && fInX)    /* old ROM driver can't do this */
  437.     controlparam->fInX = TRUE;     /* send flow control when almost full */
  438.     else
  439.     controlparam->fInX = FALSE;
  440.     controlparam->fDTR = fDTR;        /* input flow control */
  441.  
  442.     err = PBControl(&pb, FALSE);
  443.     if (err != noErr) {
  444.     printfalert("sershake: problem setting handshake: %d", err);
  445.     return -1;
  446.     }
  447.  
  448.     return 0;
  449. }
  450.  
  451.  
  452.  
  453. /****************************************************************************/
  454. /*  T T P K T  --  Condition the communication line for packets. */
  455. /*  If called with speed > -1, also set the speed.  */
  456. /*  Returns 0 on success, -1 on failure.  */
  457. /****************************************************************************/
  458. int
  459. ttpkt (long spd, int flow, int parity)    /* we only care about flow here */
  460. {
  461. #pragma unused (spd)
  462.  
  463.     ttprty = parity;                    /* Let other tt functions see these. */
  464.     ttspeed = speed;        /* $$$ is this correct? */
  465.     ttflow = flow;            /* Now make this available too. */
  466.  
  467.     fInX = TRUE;
  468.     return(sershake(flow));
  469. }
  470.  
  471.  
  472. /****************************************************************************/
  473. /*  T T V T  --  Condition the communication line for a virtual terminal. */
  474. /*  If called with spd > -1, also set the spd.  */
  475. /*  Returns 0 on success, -1 on failure.  */
  476. /****************************************************************************/
  477. int
  478. ttvt (spd, flow, parity)    /* all ignoreed */
  479. long spd;
  480. int flow;
  481. int parity;
  482. #pragma unused (spd, flow, parity)
  483. {
  484.     (void) ttres();
  485.     return (0);
  486. }                /* ttvt */
  487.  
  488.  
  489. /****************************************************************************/
  490. /*  T T F L U I  --  Flush tty input buffer */
  491. /****************************************************************************/
  492. int
  493. ttflui ()
  494. {
  495.     int err;
  496.  
  497.     my_count = 0;            /* Initialize myread() stuff */
  498.     my_item = -1;
  499.  
  500.     if (!innum)
  501.         return 0;            /* if port closed, do nothing */
  502.  
  503.     err = KillIO (innum);
  504.     if (err)
  505.     printerr ("Bad input clear", err);
  506.  
  507.     return (0);
  508. }                /* ttflui */
  509.  
  510. int
  511. ttfluo()                /* Flush output buffer */
  512. {
  513.     int err;
  514.  
  515.     if (!innum)
  516.         return 0;            /* if port closed, do nothing */
  517.  
  518.     err = KillIO (outnum);
  519.     if (err)
  520.     printerr ("Bad ouput clear", err);
  521.  
  522.     return (0);                /* (dummy for now) */
  523. }
  524.  
  525. /****************************************************************************/
  526. /*  T T S N D B  --  Send a break */
  527. /****************************************************************************/
  528. ttsndb() {
  529.     long finalticks;
  530.  
  531.     if (!innum)
  532.         return 0;            /* if port closed, do nothing */
  533.  
  534.     /* delay wants 1/60th units */
  535.  
  536.     SerSetBrk (outnum);        /* start breaking */
  537.     Delay ((long) 15, &finalticks);    /* delay about 250ms */
  538.     SerClrBrk (outnum);        /* stop breaking */
  539.     return 0;
  540. }
  541.  
  542. /****************************************************************************/
  543. /*
  544.  *   Flushio:
  545.  *      Initialize some communications constants, and clear screen and
  546.  *      character buffers. */
  547. /****************************************************************************/
  548. flushio ()
  549. {
  550.     int err;
  551.  
  552.     if (!innum)
  553.         return 0;            /* if port closed, do nothing */
  554.  
  555.     err = KillIO (innum);
  556.     if (err)
  557.     printerr ("Bad input clear", err);
  558.     err = KillIO (outnum);
  559.     if (err)
  560.     printerr ("Bad ouput clear", err);
  561.     return 0;
  562. }                /* flushio */
  563.  
  564.  
  565.  
  566. /****************************************************************************/
  567. /* sendbreak - sends a break across the communictions line.
  568.  *
  569.  * The argument is in units of approximately 0.05 seconds (or 50
  570.  * milliseconds).  To send a break of duration 250 milliseconds the
  571.  * argument would be 5; a break of duration 3.5 seconds would be (umm,
  572.  * lets see now) 70.
  573.  *
  574.  */
  575. /****************************************************************************/
  576. sendbreak (msunit)
  577. int msunit;
  578. {
  579.     long finalticks;
  580.  
  581.     if (!innum)
  582.         return 0;            /* if port closed, do nothing */
  583.  
  584. /* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
  585.  
  586.     msunit = msunit * 3;
  587.  
  588.     SerSetBrk (outnum);        /* start breaking */
  589.     Delay ((long) msunit, &finalticks);    /* delay */
  590.     SerClrBrk (outnum);        /* stop breaking */
  591.     return 0;
  592. }                /* sendbreak */
  593.  
  594. /****************************************************************************/
  595. /* toggledtr - Turn DTR off, wait a bit, turn it back on.
  596.  *
  597.  * the argument is in the same units as sendbreak (see above).
  598.  */
  599. /****************************************************************************/
  600. toggle_dtr (msunit)
  601. int msunit;
  602. {
  603.     long finalticks;
  604.     ParamBlockRec pb;
  605.     int err;
  606.  
  607.     if (!innum)
  608.         return 0;            /* if port closed, do nothing */
  609.  
  610.     if (usingRAMdriver) {
  611.     /* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
  612.  
  613.     msunit = msunit * 3;
  614.  
  615.     pb.cntrlParam.csCode = 18;        /* lower DTR */
  616.     pb.cntrlParam.ioCRefNum = outnum;
  617.     err = PBControl (&pb, FALSE);
  618.     if (err != noErr)
  619.         printerr ("toggle_dtr() trouble lowering DTR: ", err);
  620.  
  621.         Delay ((long) msunit, &finalticks);    /* delay */
  622.  
  623.     pb.cntrlParam.csCode = 17;        /* raise DTR */
  624.     pb.cntrlParam.ioCRefNum = outnum;
  625.     err = PBControl (&pb, FALSE);
  626.     if (err != noErr)
  627.         printerr ("toggle_dtr() trouble raising DTR: ", err);
  628.    }
  629.    return 0;
  630. }                /* sendbreak */
  631.  
  632. /****************************************************************************/
  633. /* do_xon - xon the output port and send an xon (control-Q) character        */
  634. /****************************************************************************/
  635. do_xon ()
  636. {
  637.     ParamBlockRec pb;
  638.     int err;
  639.  
  640.     if (!innum)
  641.         return 0;            /* if port closed, do nothing */
  642.  
  643.     if (usingRAMdriver) {
  644.     pb.cntrlParam.csCode = 22;    /* clear XOFF for my output */
  645.     pb.cntrlParam.ioCRefNum = outnum;
  646.     err = PBControl (&pb, FALSE);
  647.     if (err != noErr)
  648.         printerr ("do_xon() trouble unblocking output port: ", err);
  649.  
  650.     pb.cntrlParam.csCode = 24;    /* unconditionally send XON */
  651.     pb.cntrlParam.ioCRefNum = outnum;
  652.     err = PBControl (&pb, FALSE);
  653.     if (err != noErr)
  654.         printerr ("do_xon() trouble sending XON: ", err);
  655.    } else {
  656.        OutputChar (ttermw, '\021');    /* XON */
  657.    }
  658.    return 0;
  659. }                /* sendbreak */
  660.  
  661. /****************************************************************************/
  662. /*  T T S S P D  --  Set tty speed */
  663. /****************************************************************************/
  664.  
  665. ttsspd (cps) int cps; {    
  666.     if (!innum)
  667.         return 0;        /* if port closed, do nothing */
  668.  
  669.     if (setserial (innum, outnum, cps*10, KPARITY_NONE))
  670.     return(0);
  671.     else
  672.     return (-1);
  673. }
  674.  
  675.  
  676. /****************************************************************************/
  677. /*  T T G S P D  --  Set tty speed */
  678. /****************************************************************************/
  679.  
  680. long
  681. ttgspd () {
  682.     if (speed <= 0L && innum != 0)
  683.         printerr("Speed got reset, now == ", (int) speed);
  684.     return (speed);
  685. }
  686.  
  687.  
  688. /* Interrupt Functions */
  689.  
  690. /****************************************************************************/
  691. /* Set up terminal interrupts on console terminal */
  692. /* Set an interrupt trap. */
  693. /****************************************************************************/
  694. VOID conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  695. {
  696. #pragma unused (f, s)
  697.     return;
  698. }                /* conint */
  699.  
  700.  
  701.  
  702. /****************************************************************************/
  703. /* Reset console terminal interrupts */
  704. /****************************************************************************/
  705. VOID connoi ()
  706. {
  707.     return;
  708. }                /* connoi */
  709.  
  710. /****************************************************************************/
  711. /* writeps - write a pascal string to the serial port.
  712.  *
  713.  */
  714. /****************************************************************************/
  715. void
  716. writeps (StringPtr s)
  717. {
  718.     long wcnt, w2;
  719.     StringPtr s2;
  720.  
  721.     w2 = wcnt = *s++;        /* get count */
  722.  
  723.     for (s2 = s; w2 > 0; w2--, s2++)    /* add parity */
  724.     *s2 = dopar (*s2);
  725.     
  726.     (void) ttol((CHAR *) s, wcnt);    /* ttol will printerr() if it has a problem */
  727.  
  728.     return;
  729. }                /* writeps */
  730.  
  731. extern Boolean have_multifinder;/* true if running under MF */
  732. extern Boolean in_background;    /* becomes true if running MF and in bg */
  733. extern long mf_sleep_time;    /* number of 60ths between task time */
  734.  
  735. /****************************************************************************/
  736. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  737. /****************************************************************************/
  738. ttol (s, n)
  739. CHAR *s;
  740. int n;
  741. {
  742.     long finalticks;
  743.     int err;
  744.     ParamBlockRec cpb;
  745.  
  746.     if (!innum)
  747.         return (-1);        /* if port closed, do nothing */
  748.  
  749. #ifdef COMMENT
  750.     debug(F101,"ttol n","",n);
  751.     debug(F101," s","",s);
  752.  
  753.     /*
  754.      * the straight-forward way to write out a buffer: synchronously
  755.      */
  756.     finalticks = n;
  757.     err = FSWrite(outnum, &finalticks, s);
  758.     if ((err != noErr) || (finalticks != n)) {
  759.     printerr("ttol FSWrite error: ", err);
  760.     return (-1);
  761.     }
  762.     return (n);
  763. #endif
  764.  
  765.     /*
  766.      * The fancy to write out strings: do async writes, waiting for the
  767.      * previous call to finish first (and possibly unsticking the serial
  768.      * driver)
  769.      */
  770.  
  771.     /* wait for previous call to finish */
  772.     /* while the prev. request is still running */
  773.     while (iopb.ioParam.ioResult == 1) {
  774.     /* if we're running protocol */
  775.     if (have_multifinder && protocmd != 0) {
  776.         miniparser (TRUE);    /* keep mac running */
  777.         finalticks = TickCount ();
  778.     } else {        /* else terminal emulation */
  779.         Delay ((long) 1, &finalticks);    /* wait for a bit */
  780.     }
  781.     /* (PWP) If we have waited too long, unblock the output (keep the
  782.        Mac from freezing up) */
  783.     if ((usingRAMdriver) && (finalticks > (tto_startticks + XOFFTIMEO))) {
  784.         cpb.cntrlParam.csCode = 22;    /* clear XOFF for my output */
  785.         cpb.cntrlParam.ioCRefNum = outnum;
  786.         err = PBControl (&cpb, FALSE);
  787.         if (err != noErr)
  788.         printerr ("ttol() trouble unblocking output port: ", err);
  789.         tto_startticks = TickCount (); /* Get starting time */
  790.     }
  791.     }
  792.     
  793.     /* check for errors in previous call */
  794.     if (iopb.ioParam.ioResult) {
  795.     printerr ("Error in previous PBWrite:", iopb.ioParam.ioResult);
  796.     return (-1);
  797.     }
  798.     if (iopb.ioParam.ioActCount != iopb.ioParam.ioReqCount) {
  799.     printerr ("PBWrite to serial didn't write enough: ",
  800.           iopb.ioParam.ioActCount);
  801.     printerr ("(asked for:)", iopb.ioParam.ioReqCount);
  802.     return (-1);
  803.     }
  804.  
  805.     /* the previous call is now done, so we can load in our new information */
  806.     
  807.     if (n > MAXSP) {            /* MAXSP == sizeof(tto_buf) */
  808.         printerr("ttol asked to write too many chars: ", n);
  809.     return (-1);
  810.     }
  811.     bcopy((char *) s, tto_buf, n);    /* in ckmfio.h if nowhere else */
  812.  
  813.     iopb.ioParam.ioCompletion = NULL;
  814.     iopb.ioParam.ioNamePtr = NULL;
  815.     iopb.ioParam.ioVRefNum = 0;
  816.  
  817.     iopb.ioParam.ioRefNum = outnum;
  818.     iopb.ioParam.ioVersNum = 0;
  819.     iopb.ioParam.ioPermssn = 0;
  820.     iopb.ioParam.ioMisc = NULL;
  821.     iopb.ioParam.ioBuffer = tto_buf;
  822.     iopb.ioParam.ioReqCount = (long) n;
  823.     iopb.ioParam.ioPosMode = 0;
  824.     iopb.ioParam.ioPosOffset = 0;
  825.     
  826.     tto_startticks = TickCount ();    /* get starting time */
  827.  
  828.     PBWrite (&iopb, TRUE);        /* request an async. write */
  829.     if (protocmd != 0)
  830.       miniparser (TRUE);        /* allow other tasks to run */
  831.     return (n);                /* fake a good run */
  832. } /* ttol */
  833.  
  834.  
  835. /*  T T O C  --  Output a character to the communication line  */
  836.  
  837. /*
  838.  This function should only used for interactive, character-mode operations,
  839.  like terminal connection, script execution, dialer i/o, where the overhead
  840.  of the signals and alarms does not create a bottleneck.
  841. */
  842.  
  843. ttoc(char c) {
  844.     char foo[2];
  845.     
  846.     foo[0] = c;
  847.     foo[1] = '\0';
  848.     return (ttol((CHAR *) foo, 1));
  849. }
  850.  
  851. /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
  852.  
  853.  
  854. /* myread() -- Efficient read of one character from communications line.
  855.  *
  856.  * Uses a private buffer to minimize the number of expensive read() system
  857.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  858.  * is then returned.  By reading all available input from the system buffers
  859.  * to the private buffer in one chunk, and then working from this buffer, the
  860.  * number of system calls is reduced in any case where more than one character
  861.  * arrives during the processing of the previous chunk, for instance high
  862.  * baud rates or network type connections where input arrives in packets.
  863.  * If the time needed for a read() system call approaches the time for more
  864.  * than one character to arrive, then this mechanism automatically compensates
  865.  * for that by performing bigger read()s less frequently.  If the system load
  866.  * is high, the same mechanism compensates for that too.
  867.  *
  868.  * myread() is a macro that returns the next character from the buffer.  If the
  869.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  870.  * returns.
  871.  *
  872.  * This should be efficient enough for any one-character-at-a-time loops.
  873.  * For even better efficiency you might use memcpy()/bcopy() or such between
  874.  * buffers (since they are often better optimized for copying), but it may not
  875.  * be worth it if you have to take an extra pass over the buffer to strip
  876.  * parity and check for CTRL-C anyway.
  877.  *
  878.  * Note that if you have been using myread() from another program module, you
  879.  * may have some trouble accessing this macro version and the private variables
  880.  * it uses.  In that case, just add a function in this module, that invokes the
  881.  * macro.
  882.  */
  883.  
  884. #define mac_myread(timeo_ticks,intim)  (--my_count < 0 \
  885.             ? mac_mygetbuf(timeo_ticks,intim) \
  886.             : (int) (mybufp[++my_item]))
  887.  
  888. /* Specification: Push back up to one character onto myread()'s queue.
  889.  *
  890.  * This implementation: Push back characters into mybuf. At least one character
  891.  * must have been read through myread() before myunrd() may be used.  After
  892.  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
  893.  * one character can be pushed back, but only one character is guaranteed.
  894.  * Since a previous myread() must have read its character out of mybuf[],
  895.  * that guarantees that there is space for at least one character.  If push
  896.  * back was really needed after EOF, a small addition could provide that.
  897.  *
  898.  * myunrd() is currently not called from anywhere inside kermit...
  899.  */
  900. #ifdef NOTUSED
  901. myunrd(ch) CHAR ch; {
  902.     if (my_item >= 0) {
  903.     mybufp[my_item--] = ch;
  904.     ++my_count;
  905.     }
  906. }
  907. #endif
  908.  
  909. /* mygetbuf() -- Fill buffer for myread() and return first character.
  910.  *
  911.  * This function is what myread() uses when it can't get the next character
  912.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  913.  * to read at least one new character into the buffer, and then it returns
  914.  * the first character just as myread() would have done.  This function also
  915.  * is responsible for all error conditions that myread() can indicate.
  916.  *
  917.  * Returns: When OK    => a positive character, 0 or greater.
  918.  *        When EOF    => -2.
  919.  *        When error    => -3, error code in errno.
  920.  *
  921.  * Older myread()s additionally returned -1 to indicate that there was nothing
  922.  * to read, upon which the caller would call myread() again until it got
  923.  * something.  The new myread()/mygetbuf() always gets something.  If it 
  924.  * doesn't, then make it do so!  Any program that actually depends on the old
  925.  * behaviour will break.
  926.  *
  927.  * The older version also used to return -2 both for EOF and other errors,
  928.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  929.  * other errors now return different results, although Kermit currently never
  930.  * checks to see which it was.  It just disconnects in both cases.
  931.  *
  932.  * Kermit lets the user use the quit key to perform some special commands
  933.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  934.  * finish without reading anything and return the EINTR error.  This should
  935.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  936.  * but if there is nothing to read, this could delay Kermit's reaction to
  937.  * the command, and make Kermit appear unresponsive.
  938.  *
  939.  * The debug() call should be removed for optimum performance.
  940.  */
  941. /* myfillbuf():
  942.  * System-dependent read() into mybuf[], as many characters as possible.
  943.  *
  944.  * Returns: OK => number of characters read, always more than zero.
  945.  *          EOF => 0
  946.  *          Error => -1, error code in errno.
  947.  *
  948.  * If there is input available in the system's buffers, all of it should be
  949.  * read into mybuf[] and the function return immediately.  If no input is
  950.  * available, it should wait for a character to arrive, and return with that
  951.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  952.  * character, but be aware that any such delay lengthens the packet turnaround
  953.  * time during kermit file transfers.  Should never return with zero characters
  954.  * unless EOF or irrecoverable read error.
  955.  *
  956.  * Correct functioning depends on the correct tty parameters being used.
  957.  * Better control of current parameters is required than may have been the
  958.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can 
  959.  * no longer be sometimes off and sometimes on like it used to, unless a 
  960.  * special myfillbuf() is written to handle that.  Otherwise the ordinary 
  961.  * myfillbuf()s may think they have come to EOF.
  962.  *
  963.  * If your system has a facility to directly perform the functioning of
  964.  * myfillbuf(), then use it.  If the system can tell you how many characters
  965.  * are available in its buffers, then read that amount (but not less than 1).
  966.  * If the system can return a special indication when you try to read without
  967.  * anything to read, while allowing you to read all there is when there is
  968.  * something, you may loop until there is something to read, but probably that
  969.  * is not good for the system load.
  970.  */
  971.  
  972. int
  973. mac_mygetbuf(long timeo_tics, long intim) {
  974.     long avail;                /* can't be register */
  975.     long finaltics;            /* can't be register */
  976.     int err;
  977.     extern int tlevel;
  978.     
  979.     if (mybufp == NIL)
  980.       macfatal("No mybufp (in mac_mygetbuf())", 0);
  981.  
  982.     if (!innum)
  983.       return -1;            /* if port closed, do nothing */
  984.  
  985.     for (;;) {
  986.     SerGetBuf (innum, &avail);    /* Get available count */
  987.  
  988.     if (avail > 0)
  989.       break;            /* we can get these chars */
  990.     
  991.     /* no chars availiable yet */
  992.     if ((protocmd != 0) || (tlevel > -1) || intfunc) {
  993.         miniparser (TRUE);        /* keep mac running */
  994.         if (sstate == 'a')    {    /* abort occured? */
  995.         if (intfunc) {
  996.             sstate = '\0';
  997.             (*intfunc)(0);
  998.         } else
  999.             return (-1);    /* ugh, look like timeout */
  1000.         }
  1001.     }
  1002.         
  1003.     /*
  1004.      * Check alarm() timeouts.
  1005.      */
  1006.     if (alarmtime && alarmfunc && (((ulong)TickCount() - alarmtime) > 0))
  1007.         (*alarmfunc)(0);
  1008.  
  1009.     finaltics = TickCount ();
  1010.     if (timeo_tics > 0) {        /* Want to do timeout? */
  1011.         if (intim + timeo_tics < finaltics) {
  1012.         return (-1);        /* Too long, give up */
  1013.         }
  1014.     }
  1015.     
  1016.     /* go back and try to get more chars */
  1017.     }
  1018.  
  1019.     if (avail > MYBUFLEN)
  1020.       avail = MYBUFLEN;
  1021.  
  1022.     /*
  1023.      * CAREFUL: the Mac FSRead() function gets how much to read,
  1024.      * AND PUTS HOW MUCH IT DID READ into avail
  1025.      */
  1026.     err = FSRead (innum, &avail, mybufp); /* Into our buffer */
  1027.  
  1028.     if (err != noErr) {
  1029.     screen(SCR_EM,0,(long) err,"Serial input error:");
  1030.     return (-3);    /* return input error */
  1031.     }
  1032.     if (avail <= 0) {
  1033.     screen(SCR_EM, 0, (long) avail,
  1034.            "No serial input error, but didn't read any:");
  1035.     return (-3);    /* return input error */
  1036.     }
  1037.  
  1038.     /* not at end of packet yet, so let other tasks have a chance */
  1039.     if (in_background)
  1040.       miniparser (TRUE);        /* allow other tasks to run */
  1041.  
  1042.     my_count = (int) avail;
  1043.     
  1044.     /* debug(F101, "myfillbuf read", "", my_count); */
  1045.  
  1046.     --my_count;
  1047.     return((int) (mybufp[my_item = 0]));
  1048. }
  1049.  
  1050. /****************************************************************************/
  1051. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1052. /*
  1053.   If no break character encountered within "max", return "max" characters,
  1054.   with disposition of any remaining characters undefined.  Otherwise, return
  1055.   the characters that were read, including the break character, in "dest" and
  1056.   the number of characters read as the value of function, or 0 upon end of
  1057.   file, or -1 if an error occurred.  Times out & returns error if not completed
  1058.   within "timo" seconds.
  1059. */
  1060. /*
  1061.   Reads up to "max" characters from the communication line, terminating on
  1062.   the packet-end character (eol), or timing out and returning -1 if the eol
  1063.   character not encountered within "timo" seconds.  The characters that were
  1064.   input are copied into "dest" with their parity bits stripped if parity was
  1065.   selected.  Returns the number of characters read.  Characters after the
  1066.   eol are available upon the next call to this function.
  1067.  
  1068.   The idea is to minimize the number of system calls per packet, and also to
  1069.   minimize timeouts.  This function is the inner loop of the program and must
  1070.   be as efficient as possible.  The current strategy is to use myread().
  1071.  
  1072.   WARNING: this function calls parchk(), which is defined in another module.
  1073.   Normally, ckutio.c does not depend on code from any other module, but there
  1074.   is an exception in this case because all the other ck?tio.c modules also
  1075.   need to call parchk(), so it's better to have it defined in a common place.
  1076. */
  1077. /****************************************************************************/
  1078.  
  1079. #define CTRLC '\03'
  1080.  
  1081. #ifdef PARSENSE
  1082. int
  1083. ttinl(CHAR *dest, int max, int timo, CHAR eol, CHAR start) {
  1084.     int flag;
  1085. #else
  1086. int
  1087. ttinl(CHAR *dest, int max, int timo, CHAR eol) {
  1088. #endif
  1089.     register int i, m, n;        /* local variables */
  1090.     int x;
  1091.     long timeoticks;
  1092.     long intim;            /* when we started */
  1093.     
  1094.     debug(F101,"ttinl max","",max);
  1095.     debug(F101,"ttinl timo","",timo);
  1096.  
  1097. #ifdef PARSENSE
  1098.     debug(F000,"ttinl start","",start);
  1099.     flag = 0;                /* Start of packet flag */
  1100. #endif
  1101.  
  1102.     x = 0;                /* Return code */
  1103.     m = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  1104.     *dest = '\0';                       /* Clear destination buffer */
  1105.  
  1106.     if (timo <= 0) {        /* untimed */
  1107.     timo = 0;        /* Safety */
  1108.     intim = 0;        /* tell mac_myread not to timeout */
  1109.     timeoticks = 0;
  1110.     } else {
  1111.     timeoticks = timo * 60;
  1112.     intim = TickCount ();    /* now */
  1113.     }
  1114.  
  1115.     i = 0;
  1116.     while (i < max-1) {
  1117.     /* debug(F101,"ttinl i","",i); */
  1118.     if ((n = mac_myread(timeoticks,intim)) < 0) {
  1119.         debug(F101,"ttinl myread failure, n","",n);
  1120.         x = -1; break;
  1121.     }
  1122.     /* debug(F101,"ttinl char","",n&m); */
  1123.  
  1124. #ifdef PARSENSE
  1125.     if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
  1126.     if (flag) dest[i++] = n & m;
  1127. #else
  1128.     dest[i++] = n & m;
  1129. #endif /* PARSENSE */
  1130.  
  1131. #ifdef PARSENSE
  1132.     if (flag == 0) {
  1133.         debug(F101,"ttinl skipping","",n);
  1134.         continue;
  1135.     }
  1136. #endif /* PARSENSE */
  1137.  
  1138.     /* Check for end of packet */
  1139.  
  1140.     if ((n & 0x7f) == eol) {
  1141.         debug(F101,"ttinl got eol","",eol);
  1142.         dest[i] = '\0';        /* Yes, terminate the string, */
  1143.         /* debug(F101,"ttinl i","",i); */
  1144.         
  1145. #ifdef PARSENSE
  1146. /* Here's where we actually check and adjust the parity. */
  1147. /* The major flaw here is if parity is NONE (ttprty = 0) and the packets */
  1148. /* really do have no parity, then parchk() is called for every packet. */
  1149. /* In practice, this doesn't really harm efficiency noticably, but it would */
  1150. /* be better if ttinl() had a way of knowing to stop doing this once a */
  1151. /* particular file transfer had been started and checked. */
  1152.         if (ttprty == 0) {
  1153.         if ((ttprty = parchk(dest,start,i)) > 0) {
  1154.             register int j;
  1155.             debug(F101,"ttinl senses parity","",ttprty);
  1156.             debug(F110,"ttinl packet before",dest,0);
  1157.             for (j = 0; j < i; j++)
  1158.             dest[j] &= 0x7f; /* Strip parity from packet */
  1159.             debug(F110,"ttinl packet after ",dest,0);
  1160.         } else debug(F101,"parchk","",ttprty);
  1161.         }
  1162. #endif
  1163.         debug(F111,"ttinl got", dest,i);
  1164.         return(i);
  1165.     }
  1166.     }        /* end while (i < max-1) */
  1167.     debug(F100,"ttinl timout","",0);    /* Get here on timeout. */
  1168.     debug(F111," with",dest,i);
  1169.     return(x);                          /* and return error code. */
  1170.  
  1171. }                /* ttinl */
  1172.  
  1173.  
  1174. /****************************************************************************/
  1175. /* ttinc(timo) - read a character with timeout.  Return -1 on timeout. */
  1176. /****************************************************************************/
  1177. int
  1178. ttinc (int timo)
  1179. {
  1180.     register int m, n = 0;
  1181.     long timeoticks;
  1182.     long intim;            /* when we started */
  1183.  
  1184.     if (timo <= 0) {        /* untimed */
  1185.     intim = 0;        /* tell mac_myread not to timeout */
  1186.     timeoticks = 0;
  1187.     } else {
  1188.     timeoticks = timo * 60;
  1189.     intim = TickCount ();    /* now */
  1190.     }
  1191.     
  1192.     m = (ttprty) ? 0177 : 0377;         /* Parity stripping mask. */
  1193.  
  1194.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  1195.     n = mac_myread(timeoticks,intim);    /* Wait for a character... */
  1196.  
  1197.     /* debug(F101,"ttinc n","",n); */
  1198.     return(n < 0 ? n : n & m);
  1199. } /* ttinc */
  1200.  
  1201. /****************************************************************************/
  1202. /* PWP: input as many chars as we can read from the serial line right now   */
  1203. /****************************************************************************/
  1204. int
  1205. ttinm(register char *buf, register int max)
  1206. {
  1207.     long avil, num;
  1208.     int err, i;
  1209.  
  1210.     if (!innum)
  1211.         return 0;        /* if port closed, do nothing */
  1212.     /*
  1213.      * DANGER WILL ROBINSON: this KNOWS about how mac_myread works
  1214.      * (in an incestuous way), so BE CAREFUL!!!
  1215.      */
  1216.     if (my_count > 0) {        /* do we have chars buffered up? */
  1217.         for (i = 0; (my_count > 0) && (i < max); i++)
  1218.       *buf++ = mac_myread(0L, 0L);
  1219.     return (i);        /* return contents of previous read buffer */
  1220.     }
  1221.  
  1222.     SerGetBuf (innum, &avil);    /* Get available count */
  1223.  
  1224.     if (avil > 0) {            /* Have something? */
  1225.     num = (avil > max) ? max : avil; /* Set max */
  1226.  
  1227.     err = FSRead (innum, &num, buf); /* Into our buffer */
  1228.     if (err != noErr)
  1229.         printerr ("Serial input error: ", err);
  1230.     return (num);            /* return how many */
  1231.     } else {
  1232.         return (0);
  1233.     }
  1234. }
  1235.  
  1236. /****************************************************************************/
  1237. /****************************************************************************/
  1238. int
  1239. ttchk ()
  1240. {
  1241.     long avcnt;                /* pascal long */
  1242.  
  1243.     if (!innum)
  1244.       return 0;                /* if port closed, none available */
  1245.  
  1246.     SerGetBuf (innum, &avcnt);        /* get available */
  1247.  
  1248.     return (avcnt + my_count);        /* return avail plus our own */
  1249. } /* ttchk */
  1250.  
  1251.  
  1252. /****************************************************************************/
  1253. /* T T R E S -- Reset the serial line after doing a protocol things        */
  1254. /****************************************************************************/
  1255. ttres ()
  1256. {
  1257.     fInX = FALSE;
  1258.     return(sershake(flow));
  1259. }
  1260.  
  1261.  
  1262. unsigned long starttime;
  1263. Boolean timerRunning = FALSE;
  1264.  
  1265. /****************************************************************************/
  1266. /*  R T I M E R --  Reset elapsed time counter  */
  1267. /****************************************************************************/
  1268. VOID rtimer ()
  1269. {
  1270.     GetDateTime (&starttime);
  1271.     timerRunning = TRUE;
  1272. }                /* rtimer */
  1273.  
  1274. /****************************************************************************/
  1275. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  1276. /****************************************************************************/
  1277. int
  1278. gtimer ()
  1279. {
  1280.     unsigned long secs;
  1281.  
  1282.     if (timerRunning) {
  1283.     GetDateTime (&secs);
  1284.     return (secs - starttime);
  1285.     timerRunning = FALSE;
  1286.     } else
  1287.       return (0);
  1288. } /* gtimer */
  1289.  
  1290. /****************************************************************************/
  1291. /*  Z T I M E  --  Return date/time string  */
  1292. /* Various bits stolen from Unix Kermit assume that ztime() returns */
  1293. /* a asctime() format string, vis: */
  1294. /* "Thu Feb  8 12:00:00 1990" */
  1295. /****************************************************************************/
  1296. VOID ztime (s)
  1297. char **s;
  1298. {
  1299. /*
  1300.   ztime() MUST return a string in asctime() format.
  1301. */
  1302.     unsigned long secs;
  1303.     DateTimeRec dtrec;
  1304.     static char dtime[32];    /* really only 25 needed, but be safe */
  1305.     static char *month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1306.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  1307.     static char *day_names[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  1308.  
  1309.     GetDateTime (&secs);
  1310.     Secs2Date (secs, &dtrec);
  1311.     sprintf(dtime, "%3s %3s %2d %2d:%02d:%02d %4d",
  1312.         day_names[dtrec.dayOfWeek - 1],
  1313.         month_names[dtrec.month - 1],
  1314.         dtrec.day, dtrec.hour, dtrec.minute, dtrec.second, dtrec.year);
  1315.  
  1316.     *s = dtime;
  1317.  
  1318. #ifdef COMMENT
  1319. #include <Time.h>
  1320.     time_t time(time_t *timer);
  1321.     char *ctime(const time_t *timer);
  1322.     
  1323.     time_t time_now;
  1324.     time_now = time( (time_t) 0 );
  1325.     *s = ctime( &time_now );
  1326. #endif /* COMMENT */
  1327. }                /* ztime */
  1328.  
  1329. /* Console IO routines.  The console is implemented as a text edit structure.
  1330.  * These routines are supported:
  1331.  *
  1332.  * conoc(c)   -- output one character to TE record at insertion point
  1333.  * conol(s)   -- output null terminated string to TE record " "
  1334.  * conoll(s)  -- same but with CR on the end
  1335.  * conxo(n,s) -- n character to TE record " "
  1336.  *
  1337.  */
  1338.  
  1339. #define NILTE ((TEHandle ) NILPTR)
  1340. #define LF 012
  1341. #define CR 015
  1342.  
  1343. /****************************************************************************/
  1344. /*  C O N X O  --  Output string of length len to console text edit record  */
  1345. /****************************************************************************/
  1346. conxo (len, s)
  1347.     int len;
  1348.     register char *s;
  1349. {
  1350.     register char *t;
  1351.     
  1352.     /* change NLs to CRs for the Mac */
  1353.     for (t = s; *t && (t - s < len); t++)
  1354.         if (*t == LF)
  1355.         *t = CR;
  1356.  
  1357.     /* debug (F101, "conxo here: ", s, len); */
  1358.     if (rcmdw->teh == NULL)
  1359.     return(0);
  1360.  
  1361.     TEDeactivate(rcmdw->teh);
  1362.     (void) trimcon(rcmdw, len);
  1363.     TEInsert (s, (long) len, rcmdw->teh);    /* insert the string */
  1364.     TESetSelect(TE_MAX, TE_MAX, rcmdw->teh);
  1365.     TEActivate(rcmdw->teh);
  1366.     rcdwscroll (rcmdw);        /* possibly scroll it */
  1367.  
  1368.     return (0);
  1369. }                /* conxo */
  1370.  
  1371.  
  1372. /****************************************************************************/
  1373. /*  C O N O C  --  Output a character to the console text edit record */
  1374. /****************************************************************************/
  1375. conoc (char c)
  1376. {
  1377.     (void) conxo (1, &c);
  1378. }                    /* conoc */
  1379.  
  1380.  
  1381.  
  1382. /****************************************************************************/
  1383. /****************************************************************************/
  1384. conopen ()
  1385. {
  1386.     return (1);
  1387. }                                        /* conopen */
  1388.  
  1389.  
  1390.  
  1391. /****************************************************************************/
  1392. /*  C O N O L  --  Write a line to the console text edit record  */
  1393. /****************************************************************************/
  1394. conol (s)
  1395. register char *s;
  1396. {
  1397.     return (conxo (strlen (s), s));
  1398. }                                        /* conol */
  1399.  
  1400.  
  1401.  
  1402.  
  1403. /****************************************************************************/
  1404. /*  C O N O L L  --  Output a string followed by CRLF  */
  1405. /****************************************************************************/
  1406. conoll (s)
  1407. char *s;
  1408. {
  1409.     (void) conol (s);            /* first the string */
  1410.     (void) conoc (CR);            /* now the return */
  1411.     return (0);
  1412. }                /* conoll */
  1413.  
  1414.  
  1415. /*****************************************
  1416.  *    C-Kermit Compatibility routines    *
  1417.  *****************************************/
  1418.  
  1419. /*
  1420.  * dummy routines for MAC
  1421.  */
  1422. #define CINC(v,l)((v+1 == l)? 0 : v+1)
  1423. #define CBL 25                /* console buffer length */
  1424. int cbin = 0;                /* circular buffer pointers */
  1425. int cbout = 0;
  1426. unsigned char cbuf[CBL];        /* console buffer */
  1427.  
  1428. concb (char esc)
  1429. {
  1430. #pragma unused (esc)
  1431. }
  1432.  
  1433. conres ()
  1434. {
  1435. }
  1436.  
  1437. conchk ()
  1438. {
  1439.     if (sstate == 'a')            /* if cmd-. in miniparser */
  1440.     return 1;
  1441.     else
  1442.     return 0;
  1443. }
  1444.  
  1445. tthang ()
  1446. {
  1447.     toggle_dtr(70);
  1448.     return(1);
  1449. }
  1450.  
  1451. VOID setint ()
  1452. {
  1453. }
  1454.  
  1455. /*
  1456.  * ttgmdm
  1457.  * Get modem control signals.
  1458.  * The mac only has one input handshake (CTS) and one output
  1459.  * line (DTR).  DTR may not be present on older MACS with 
  1460.  * DB-9 (instead of DIN-8) connectors.
  1461.  */
  1462. ttgmdm() 
  1463. {
  1464.     int err, r;
  1465.     SerStaRec stat;
  1466.  
  1467.     err = SerStatus(outnum, &stat);
  1468.     if (err != noErr) {
  1469.     printfalert("ttgmdm: Error getting serial status: %d", err);
  1470.     return -1;            /* not available */
  1471.     }
  1472.     r = 0;
  1473.     if (!stat.ctsHold)
  1474.     r |= BM_CTS;
  1475.     /* 
  1476.      * Always say dtr is on. We may be lying if we've enabled
  1477.      * dtr input flow control.
  1478.      */
  1479.     r |= BM_DTR;
  1480.  
  1481.     return r;
  1482. }
  1483.  
  1484.  
  1485. /*
  1486.  * Things from ckutio.c
  1487.  */
  1488. int ckxech = 1;       /* 0 if system normally echoes console characters, else 1 */
  1489.  
  1490. int ttcarr = CAR_AUT;            /* Carrier handling mode. */
  1491.  
  1492. #include "ckuver.h"            /* Version herald */
  1493. char *ckxsys = HERALD;
  1494.  
  1495. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  1496.  *
  1497.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  1498.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  1499.  *  2 = Auto: For "modem direct": The same as "Off".
  1500.  *            For real modem types: Heed carrier during connect, but ignore
  1501.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  1502.  *
  1503.  * As you can see, this setting does not affect dialing, which always ignores
  1504.  * carrier (unless there is some special exception for some modem type).  It
  1505.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  1506.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  1507.  * (or should be) always called before any communications is tried, which
  1508.  * means that, practically speaking, the effect is immediate.
  1509.  *
  1510.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  1511.  *
  1512.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  1513.  * environment (or any non-termio using environment).  Until that time, this
  1514.  * will simply be a no-op for BSD.
  1515.  *
  1516.  * Note that in previous versions, the carrier was most often left unchanged
  1517.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  1518.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  1519.  * modes.
  1520.  */
  1521. int ttscarr (carrier) 
  1522.     int carrier; 
  1523. {
  1524.     ttcarr = carrier;
  1525.     debug(F101, "ttscarr","",ttcarr);
  1526.     return(ttcarr);
  1527. }
  1528.  
  1529.  
  1530. VOID bgchk () 
  1531. {                                        /* Check background status */
  1532. #ifdef notdef
  1533.     if (bgset < 0) pflag = !backgrd;
  1534.     else pflag = (bgset == 0 ? 1 : 0);
  1535. #endif
  1536. }
  1537.  
  1538. /*  T T X I N  --  Get n characters from tty input buffer  */
  1539.  
  1540. /*  Returns number of characters actually gotten, or -1 on failure  */
  1541.  
  1542. /*  Intended for use only when it is known that n characters are actually */
  1543. /*  Available in the input buffer.  */
  1544.  
  1545. int ttxin (n,buf) 
  1546.     int n; 
  1547.     CHAR *buf; 
  1548. {
  1549.     int i, c;
  1550.  
  1551.     for (i = 0; i < n; i++) {
  1552.     c = ttinc(0);
  1553.     if (c < 0)
  1554.         return -1;
  1555.     *buf++ = ttinc(0);        /* ignore errors */
  1556.     }
  1557.  
  1558.     return n;
  1559. }
  1560.     
  1561.  
  1562. /*  C O N I N C  --  Get a character from the console  */
  1563.  
  1564. int coninc (timo) 
  1565.     int timo; 
  1566. {
  1567.     int c;
  1568.     
  1569.     newparser(1, 0, (long) timo);    /* wait till timeout, no menus */
  1570.     
  1571.     if (cbin == cbout)            /* if timeout */
  1572.     return -1;
  1573.  
  1574.     c = cbuf[cbout];
  1575.     cbout = CINC(cbout, CBL);        /* advance pointer */
  1576.     
  1577.     return c;
  1578. }
  1579.  
  1580. /*
  1581.  * puts for mac console
  1582.  */
  1583. int
  1584. mac_puts (const char *string)
  1585. {
  1586.     const char *cp;
  1587.  
  1588.     if (cmdinterminal)
  1589.     cursor_erase (ttermw);
  1590.  
  1591.     for (cp = string; *cp; cp++)
  1592.     ucharout(*cp);
  1593.     
  1594.     if (cmdinterminal) {
  1595.     if (ttermw->scroll_amount) 
  1596.         flushscroll(ctermw);    /* sync the screen */
  1597.     if (ctermw->out_maxcol)        /* KLUDGE */
  1598.         flushbuf(ctermw);        
  1599.     cursor_draw(ctermw);
  1600.     }
  1601.  
  1602.     return 1;            /* $$$ what should this be? */
  1603. }
  1604.  
  1605.  
  1606. /*
  1607.  * printf for mac console
  1608.  */
  1609. int
  1610. mac_printf (const char *format, ...) {
  1611.     int i, rc;
  1612.     char string[512];        /* Hope that this is big enough!! */
  1613.     char *cp;
  1614.     va_list ap;
  1615.  
  1616.     va_start(ap, format);
  1617.     rc = vsprintf(string, format, ap);
  1618.     va_end(ap);
  1619.  
  1620.     if ((i = strlen(string)) >= sizeof(string))
  1621.     printerr("Overran allocation for string in printf(), len:", i);
  1622.  
  1623.     if (cmdinterminal)
  1624.     cursor_erase (ttermw);
  1625.  
  1626.     for (cp = string; *cp; cp++)
  1627.     ucharout(*cp);
  1628.  
  1629.     if (cmdinterminal) {
  1630.     if (ctermw->scroll_amount) 
  1631.         flushscroll(ctermw);        /* sync the screen */
  1632.     if (ctermw->out_maxcol)        /* KLUDGE */
  1633.         flushbuf(ctermw);
  1634.     cursor_draw(ctermw);
  1635.     }
  1636.     return (rc);
  1637. }
  1638.  
  1639. int
  1640. mac_perror (const char *s) {
  1641.     mac_printf("MacError: %s\n",s);
  1642. }
  1643.  
  1644. /*
  1645.  * putchar for mac console
  1646.  */
  1647. int
  1648. mac_putchar (int c)
  1649. {
  1650.     if (cmdinterminal)
  1651.     cursor_erase (ttermw);
  1652.  
  1653.     ucharout(c);
  1654.  
  1655.     if (cmdinterminal) {
  1656.     if (ctermw->scroll_amount) 
  1657.         flushscroll(ctermw);        /* sync the screen */
  1658.     if (ctermw->out_maxcol)        /* KLUDGE */
  1659.         flushbuf(ctermw);
  1660.     cursor_draw(ctermw);
  1661.     }
  1662.     return 1;                /* $$$ what should this be? */
  1663. }
  1664.  
  1665.  
  1666. /*
  1667.  * outchar
  1668.  * output a character to a termw window.
  1669.  */
  1670. void outchar (struct termw *termw, char c)
  1671. {
  1672.     unsigned char buf[2];
  1673.  
  1674.     buf[0] = c;
  1675.     buf[1] = 0;
  1676.  
  1677.     printem(termw, buf, 1);
  1678. }
  1679.  
  1680.  
  1681. /*
  1682.  * Send a single character to the console, unix format.
  1683.  * The MPW compiler thinks that '\r' is 0x0a and that
  1684.  * '\n' is 0x0d.  In this routine, we translate things
  1685.  * to the appropriate action.  
  1686.  *
  1687.  * This will be broken if we call this routine with chars
  1688.  * that are already correct, e.g.: CR.
  1689.  */
  1690. static void
  1691. ucharout (char c)
  1692. {
  1693.     switch (c) {
  1694.     case '\n':                /* unix newline -> CR, LF */
  1695.     cmdout(LF);
  1696.     cmdout(CR);
  1697.     return;
  1698.     case '\r':                /* \r -> CR */
  1699.     cmdout(CR);
  1700.     return;
  1701.     default:
  1702.     cmdout(c);
  1703.     return;
  1704.     }
  1705. }
  1706.  
  1707.  
  1708. /*
  1709.  * cmdout
  1710.  * write a character to the command window
  1711.  * (copied from conxo)
  1712.  */
  1713. VOID cmdout (char c)
  1714. {
  1715.     unsigned char buf[2];
  1716.  
  1717.     buf[0] = c;
  1718.     buf[1] = 0;
  1719.     
  1720.     /*
  1721.      * Output to terminal window if no command window.
  1722.      */
  1723.     if (cmdinterminal) {
  1724.     printem(ttermw, buf, 1);
  1725.     return;
  1726.     }
  1727.  
  1728.     printem(ctermw, buf, 1);
  1729. }
  1730.  
  1731.  
  1732. /*
  1733.  * getchar for mac console
  1734.  */
  1735. int
  1736. mac_getchar ()
  1737. {
  1738.     int c;
  1739.     
  1740.     while (cbin == cbout) {        /* while buffer is empty */
  1741.     if (sstate = newparser(1, 1, 0L)) {
  1742.         if (sstate == 'p')        /* if wakeup flag */
  1743.         sstate = '\0';
  1744.         else if (sstate == 'n') {    /* if null command state */
  1745.         sstate = '\0';
  1746.         return (-3);
  1747.         } else
  1748.         return(-3);            /* NULL command */
  1749.     }
  1750.     }
  1751.  
  1752.     c = cbuf[cbout];
  1753.     cbout = CINC(cbout, CBL);        /* advance pointer */
  1754.     
  1755.     return c;
  1756. }
  1757.  
  1758. #ifdef THINK_C
  1759. /* Just a dummy so that we can use so ckuus*.c */
  1760. char *
  1761. getenv(const char *s)
  1762. {
  1763.     return (NULL);        /* the Mac doesn't have an "environment" */
  1764. }
  1765. #endif /* THINK_C */
  1766.  
  1767.  
  1768. /*
  1769.  * writecbc
  1770.  * Store a character into the console input buffer.
  1771.  */
  1772. writecbc (c)
  1773.     char c;
  1774. {
  1775.     int t;
  1776.  
  1777.     cbuf[cbin] = c;
  1778.     t = CINC(cbin, CBL);        /* advance pointer */
  1779.     if (t == cbout)            /* if buffer was full */
  1780.     return;                /* drop character */
  1781.     cbin = t;
  1782. }
  1783.  
  1784.  
  1785. /*
  1786.  * writecb
  1787.  * Store a pascal string into the console input buffer.
  1788.  */
  1789. writecb (string)
  1790.     char *string;
  1791. {
  1792.     int l, i;
  1793.  
  1794.     l = *string++;            /* length */
  1795.     for (i = 0; i < l; i++)
  1796.     writecbc(*string++);
  1797. }
  1798.  
  1799. /*  C O N B I N  --  Put console in binary mode  */
  1800.  
  1801. /*  Returns 0 if ok, -1 if not  */
  1802.  
  1803. int
  1804. conbin (char esc)
  1805. {
  1806. #pragma unused (esc)
  1807.     return 0;
  1808. }
  1809.  
  1810. /*
  1811.  * Junk so Emacs will set local variables to be compatible with Mac/MPW.
  1812.  * Should be at end of file.
  1813.  * this module uses 8 char tabs
  1814.  * 
  1815.  * Local Variables:
  1816.  * tab-width: 8
  1817.  * End:
  1818.  */
  1819.