home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / a / aos-vs.zip / CKDTIO.C < prev    next >
C/C++ Source or Header  |  1993-01-23  |  93KB  |  2,694 lines

  1. char *ckxv = "Data General tty I/O, 5A(097) 20 Jan 93";
  2.  
  3. /*  C K D T I O  */
  4.  
  5. /* C-Kermit interrupt, terminal control & i/o functions for DG AOS/VS */
  6.  
  7. /*
  8.  Author: Frank da Cruz (SY.FDC@CU20B),
  9.  Columbia University Center for Computing Activities, January 1985.
  10.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  11.  Permission is granted to any individual or institution to use, copy, or
  12.  redistribute this software so long as it is not sold for profit, provided this
  13.  copyright notice is retained. 
  14.  
  15.  This module was originally adapted to the Data General computers by:
  16.  
  17.     Phil Julian, SAS Institute, Inc., Box 8000, Cary, NC 27512-8000
  18.  
  19.  It was brought up to 5A by Eugenia Harris of Data General.
  20.  
  21. */
  22.   
  23. #define MAXINBUF 2048                  /* See ckdcon.c for same definition. */
  24. #nolist
  25. #include <memory.h>
  26. #include <string.h>
  27. #include <dglib.h>
  28. #include <bit.h>
  29. #include <sysid.h>
  30. #include <sys_calls.h>
  31. #include <packets/normal_io.h>
  32. #include <multitask.h>                                  
  33. #include <paru.h>
  34. #include    <stdio.h>
  35. #include    <packets:common.h>
  36. #include <packets:characteristics.h>
  37. #list
  38. #define CONINT_TSK 20                   /* Task id of interrupt-checker */
  39. #define CONINT_PRI 0                    /* Same as calling task */ 
  40. #define CONINT_STACK 02000
  41. int con_reads_mt = 0;                   /* Flag if task is active */
  42. int conint_ch;                          /* MT character read */
  43. int conint_avl;                         /* Flag that char available */
  44. int termtype;
  45. /* Delimiter table -- defaults to CR only */
  46. short idel_tbl[7] = {0x4,0,0,0,0,0,0};
  47. #include <stdio.h>                      /* Unix Standard i/o */
  48.  
  49. #ifndef DEVNAMLEN
  50. #define DEVNAMLEN (L_ctermid + 6)
  51. #endif 
  52.  
  53. #ifdef  NETCONN
  54. #undef DEVNAMLEN
  55. #define DEVNAMLEN 50                    /* longer field for host:service */
  56. #endif  /* NETCONN */
  57.  
  58. #include <sys/dir.h>                    /* Directory */
  59. #include <ctype.h>                      /* Character types */
  60.  
  61. /* Maximum length for the name of a tty device */
  62. #ifndef DEVNAMLEN
  63. #define DEVNAMLEN 25
  64. #endif
  65.  
  66. #include <stdio.h>                      /* Unix Standard i/o */
  67. #include <signal.h>                     /* Interrupts */
  68. #include <setjmp.h>                     /* Longjumps */
  69. #include "ckcdeb.h"                     /* Typedefs, formats for debug() */
  70. #include "ckcnet.h"
  71. #include <sys/stat.h>
  72.  
  73. #ifdef datageneral
  74. char *ckxsys = " Data General AOS/VS";
  75. #endif
  76.  
  77. /* Features... */
  78.  
  79. #define MYREAD
  80.  
  81. /*
  82.  Variables available to outside world:
  83.  
  84.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  85.    dfloc  -- 0 if dftty is console, 1 if external line.
  86.    dfprty -- Default parity
  87.    dfflow -- Default flow control
  88.    ckxech -- Flag for who echoes console typein:
  89.      1 - The program (system echo is turned off)
  90.      0 - The system (or front end, or terminal).
  91.    functions that want to do their own echoing should check this flag
  92.    before doing so.
  93.  
  94.    flfnam -- Name of lock file, including its path, e.g.,
  95.                 "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
  96.    haslock -- Flag set if this kermit established a uucp lock.
  97.    inbufc -- number of tty line rawmode unread characters 
  98.                 (system III/V unixes)
  99.    backgrd -- Flag indicating program executing in background ( & on 
  100.                 end of shell command). Used to ignore INT and QUIT signals.
  101.  
  102. /* Declarations of variables global within this module */
  103.  
  104. static time_t tcount;                   /* Elapsed time counter */
  105. SIGTYP (*saval)() = NULL;               /* For saving alarm handler */
  106.  
  107. /* The following lists of functions are somewhat out of date.  For a
  108.    better listing, see ckutio.c
  109.  
  110. Functions for assigned communication line (either external or console tty):
  111.  
  112.    sysinit()               -- System dependent program initialization
  113.    ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  114.    ttclos()                -- Close & reset the tty, releasing any access lock.
  115.    ttpkt(speed,flow,parity)-- Put the tty in packet mode and set the speed.
  116.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  117.                               or in DIALING or CONNECTED modem control state.
  118.    ttinl(dest,max,timo,eol,start) -- Timed read line from the tty.
  119.    ttinc(timo)             -- Timed read character from tty.
  120.    myread()                -- System 3 raw mode bulk buffer read, gives
  121.                            -- subsequent chars one at a time and simulates
  122.                            -- FIONREAD!
  123.    ttchk()                 -- See how many characters in tty input buffer.
  124.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  125.    ttol(string,length)     -- Write a string to the tty.
  126.    ttoc(c)                 -- Write a character to the tty.
  127.    ttflui()                -- Flush tty input buffer.
  128.    ttfluo()                -- Flush tty output buffer.  (not used)
  129.    ttgmdm()                -- Returns status of modem signals (not used)
  130.    ttgspd()                -- Returns speed of tty line
  131.    ttsspd(cps)             -- Set line speed on tty line
  132.    ttimoff()               -- Turns off all pending timer interrupts
  133.    ttscarr(carrier)        -- Copies argument to global variable
  134.    ttwmdm(mdmsig,timo)     -- Wait for specified signal (not used)
  135.    ttlock(ttname)          -- Lock against uucp collisions (not used)
  136.    ttunlck()               -- Unlock "       "     "       (not used)
  137.    look4lk(ttname)         -- Check if a lock file exists  (not used)
  138.  
  139. Functions for console terminal:
  140.  
  141.    congm()   -- Get console terminal modes.
  142.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  143.    conbin(esc) -- Put the console in binary (raw) mode.
  144.    conres()  -- Restore the console to mode obtained by congm().
  145.    conoc(c)  -- Unbuffered output, one character to console.
  146.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  147.    conola(s) -- Unbuffered output, array of strings to the console.
  148.    conxo(n,s) -- Unbuffered output, n characters to the console.
  149.    conchk()  -- Check if characters available at console (bsd 4.2).
  150.  
  151.                 Check if escape char (^\) typed at console (System III/V).
  152.    coninc(timo)  -- Timed get a character from the console.
  153.    conint()  -- Enable terminal interrupts on the console if not background.
  154.    connoi()  -- Disable terminal interrupts on the console if not background.
  155.    congks(timo) -- Get keyboard scan code (not used)
  156.  
  157. Time functions:
  158.  
  159.    msleep(m) -- Millisecond sleep
  160.    ztime(&s) -- Return pointer to date/time string
  161.    rtimer() --  Reset timer
  162.    gtimer()  -- Get elapsed time since last call to rtimer()
  163. */
  164.  
  165. /* System III, System V */
  166.  
  167. #ifdef UXIII
  168. #ifdef datageneral
  169. /* Console and terminal characteristics vectors */
  170. short *charcurr;
  171. short charconin[$CLMAX];    /* Console input; channel 0 */
  172. short charconout[$CLMAX];   /* Console output; channel 1 */
  173. short chartty[$CLMAX];      /* generic tty channel */
  174. short charttyin[$CLMAX];    /* tty input; channel ttyfd */
  175. short charttyout[$CLMAX];   /* tty output; channel ttyfdout */
  176. short ch_ttold[$CLMAX];
  177. short ch_ttraw[$CLMAX];
  178. short ch_ttvt[$CLMAX]; 
  179. short ch_ccold[$CLMAX];
  180. short ch_ccraw[$CLMAX];
  181. short ch_ccbrk[$CLMAX]; 
  182. #undef ECHO
  183. #include <sys/termio.h>
  184. /* Add synonymns for Unix type ioctl */
  185. #define TCSETAF TCSETA
  186. #define TCSETAW TCSETA
  187. #else
  188. #include <termio.h>
  189. #include <sys/ioctl.h>
  190. #endif datageneral
  191.  
  192. #include <fcntl.h>                      /* directory reading for locking */
  193. #include <errno.h>                      /* error numbers for system returns */
  194. #endif
  195.  
  196. /* Declarations */
  197.  
  198. long time();                            /* All Unixes should have this... */
  199. extern int errno;                       /* System call error return */
  200. extern int ttnproto;
  201. extern int ttnet;
  202.  
  203. /* dftty is the device name of the default device for file transfer */
  204. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  205.  
  206. char *dftty = CTTNAM;                   /* Remote by default, use normal */
  207. int dfloc = 0;                          /* controlling terminal name. */
  208. int dfprty = 0;                         /* Parity (0 = none) */
  209. int dfflow = 1;                         /* Xon/Xoff flow control */
  210. int backgrd = 0;                        /* Assume in foreground (no '&' ) */
  211. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  212.  
  213. /* Declarations of variables global within this module */
  214.  
  215. static long tcount;                     /* Elapsed time counter */
  216. static char *brnuls = "\0\0\0\0\0\0\0"; /* A string of nulls */
  217. static jmp_buf sjbuf, jjbuf;            /* Longjump buffer */
  218.  
  219. static int lkf = 0,                     /* Line lock flag */
  220.     conif = 0,                          /* Console interrupts on/off flag */
  221.     cgmf = 0,                           /* Flag that console modes saved */
  222.     xlocal = 0;                         /* Flag for tty local or remote */
  223.     curcarr = 0;                        /* Carrier mode: require/ignore. */
  224. int ttyfd = -1;                         /* TTY file descriptor */
  225. int tvtflg = 0;
  226. long ttspeed = -1;                      /* For saving speed */
  227. int ttflow = -9;                        /* For saving flow */
  228. int ttld = -1;                          /* Line discipline */
  229. int ttfdflg = 0;
  230. int ttpmsk = 0377;
  231. int ttprty = 0;
  232. int ttpflg = 0;                         /* Parity not sensed yet */
  233. int ttmdm = 0;
  234. int ttcarr = CAR_AUT;                   /* Carrier handling mode. */
  235. int telnetfd = 0;
  236. static int netconn = 0;
  237. int fdflag = 0;
  238. static char escchr;                     /* Escape or attn character */
  239. static int kerld = 0;                   /* Not selected, no special l.d. */
  240. int x25fd = 0;
  241.  
  242. #ifdef UXIII
  243.   static struct termio                  /* sgtty info... */
  244.     ttold, ttraw, tttvt,                /* for communication line */
  245.     ccold, ccraw, cccbrk;               /* and for console */
  246. #else
  247.   static struct sgttyb                  /* sgtty info... */
  248.     ttold, ttraw, tttvt, ttbuf,         /* for communication line */
  249.     ccold, ccraw, cccbrk;               /* and for console */
  250. #endif
  251.  
  252. char flfnam[80];                        /* uucp lock file path name */
  253. int haslock = 0;                        /* =1 if this kermit locked uucp */
  254.  
  255. static int inbufc = 0;                  /* stuff for efficient SIII raw line */
  256. static int ungotn = -1;                 /* pushback to unread character */
  257. static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
  258.  
  259. static int ttlock();                    /* definition of ttlock subprocedure */
  260. static int ttunlck();                   /* and unlock subprocedure */
  261. static char ttnmsv[DEVNAMLEN];          /* copy of open path for tthang */
  262.  
  263. #ifdef datageneral
  264. FILE *ttfile,*ttfileout;                /* Files opened by ttopen */
  265.   
  266. struct p_nio_ex w_io_parms;             /* ?write system call structure */
  267. struct p_nio_ex r_io_parms;             /* ?read system call structure */
  268.  
  269. struct p_nio_ex io_parms;               /* open structure in ttopen */
  270. struct p_nio_ex x_io_parms;             /* ?read/?write structure for ttyfd */
  271. struct p_nio_ex xout_parms;             /* ?write structure for ttyfdout */
  272. struct p_screen x_io_scrn,
  273.        r_io_scrn,io_screen;             /* Edit-read structures */
  274.  
  275. int ttyfdout = -1;                      /* ?write Unix number for remote out */
  276. short timotty = 0;                      /* {Flag for timeouts (=1), value */
  277. short timocon = 0;                      /* tty is ttyfd..., con is Unix 0/1 */
  278. extern char *SPACMD;                    /* returns space in CURRENT dir */
  279. #endif
  280.  
  281. /* Timeout handler for communication line input functions */
  282.  
  283. SIGTYP
  284. timerh(foo) int foo; {                  /* we will try to use this */
  285.     ttimoff();
  286.     longjmp(sjbuf,1);
  287. }
  288.  
  289. /* Control-C trap for communication line input functions */
  290. /* These are not used in the VS implementation.  Instead, there is a task */
  291. /* called conint_mt that reads characters from the keyboard and sets a    */
  292. /* flag when it gets one.  It is then up to other routines (e.g., chkint()*/
  293. /* to determine what to do with the characters (and zero the flag)  --ENH */
  294.  
  295. int cc_int;                             /* Flag */
  296. SIGTYP (* occt)();                      /* For saving old SIGINT handler */
  297.  
  298. SIGTYP
  299. cctrap(foo) int foo; {                  /* Needs arg for ANSI C */
  300.   cc_int = 1;                           /* signal() prototype. */
  301.   return;
  302. }
  303.  
  304. /*  S Y S I N I T  --  System-dependent program initialization.  */
  305.  
  306. int
  307. sysinit() {
  308.  
  309. #ifdef datageneral
  310.      /* Set up many things on the DG system, for initialization, etc. */
  311.      
  312.      short flags[3];
  313.      char *username;
  314.      int err;
  315.      
  316.      signal(SIGALRM,SIG_IGN);
  317.  
  318.      /* Get the terminal type, since DG terminals are different from others,
  319.         especially in the way BS is handled ('\b' is EM).
  320.         termtype = 0 means a regular DG style terminal, and 
  321.         termtype = 1 means an ANSI style terminal with ^H for backspace.
  322.         If Kermit is run in batch or has redirected input, then we do not
  323.         want to test or set the console characteristics.
  324.      */
  325.      termtype = 0;
  326.      if (isatty(0)) {
  327.         if (sys_gchr(channel(0),1<<31,&flags))
  328.              { perror("sysinit: sys_gchr: "); return(1); }
  329.  
  330.         /* Only determine whether or not it is a $TTY */
  331.         if ((flags[1] & $DTYPE) == $TTY) termtype = 1;
  332.      }
  333.  
  334.      zero((char *) &w_io_parms, sizeof(w_io_parms));
  335.      w_io_parms.ich  = channel(1);                   /* stdout */
  336.      w_io_parms.isti = $IBIN|$RTDS|$ICRF|$OFOT;
  337.      w_io_parms.isti &= ~$IPST;
  338.      w_io_parms.imrs = MAXINBUF-1;
  339.      w_io_parms.ibad = -1;
  340.      w_io_parms.ircl = -1;
  341.  
  342.      zero((char *) &r_io_parms, sizeof(r_io_parms));
  343.      r_io_parms.ich  = channel(0);                   /* stdin */
  344.      r_io_parms.isti = $IBIN|$RTFX|$ICRF|$OFIN;
  345.      r_io_parms.isti &= ~$IPST;
  346.      r_io_parms.imrs = MAXINBUF-1;
  347.      r_io_parms.ibad = -1;
  348.      r_io_parms.ircl = -1;
  349.  
  350.      zero((char *) &r_io_scrn, sizeof(r_io_scrn));
  351.      r_io_parms.etsp = 0;              /* Screen management extension */
  352.      r_io_scrn.esfc &= ~$ESNE;         /* Echo input data */
  353.      r_io_scrn.esfc &= ~$ESSE;         /* No screen edit */
  354.      r_io_scrn.esfc |= $ESGT;          /* Dump ring buffer */
  355.  
  356.      zero((char *) &x_io_parms, sizeof(x_io_parms));
  357.      /* $RTDY must be used instead of $RTDS since this causes failure on
  358.       * the Prime, which is probably getting data overruns on output or
  359.       * missing data.  Also, $RTDY is more efficient and faster.
  360.       */
  361.      x_io_parms.isti = $IBIN|$RTFX|$ICRF|$OFIO|$IPKL;
  362.      x_io_parms.isti &= ~$IPST;
  363.      x_io_parms.imrs = MAXINBUF-1;
  364.      x_io_parms.ibad = -1;
  365.      x_io_parms.ircl = -1;
  366.  
  367.      /* IDEL would default to NULL, FF, CR, NL as delimiters.
  368.       * The only delimiters here are CR and NL, for data sensitive 
  369.       * records.
  370.       */
  371.      idel_tbl[0] = 0x24;
  372.      x_io_parms.idel = idel_tbl;
  373.  
  374.      zero((char *) &x_io_scrn, sizeof(x_io_scrn));
  375.      x_io_parms.etsp = &x_io_scrn;     /* Screen management extension */
  376.      x_io_parms.etsp |= BIT0;          /* Turn on the high bit */
  377.      x_io_scrn.esfc &= ~$ESNE;         /* Echo input data */
  378.      x_io_scrn.esfc &= ~$ESSE;         /* No screen edit */
  379.      x_io_scrn.esfc |= $ESGT;          /* Dump ring buffer */
  380.  
  381.      memcpy((char *) &xout_parms,(char *) &x_io_parms,sizeof(x_io_parms));
  382.      xout_parms.isti = $IBIN|$RTDY|$ICRF|$OFOT;
  383.      xout_parms.etsp = 0;              /* Screen management extension */
  384.  
  385.      username = getenv("LOGNAME");
  386.  
  387.      /* Zero the console characteristics arrays */
  388.      zero ((char *) charconin, sizeof(charconin));
  389.      zero ((char *) charconout, sizeof(charconout));
  390.      zero ((char *) chartty, sizeof(chartty));
  391.      zero ((char *) charttyin, sizeof(charttyin));
  392.      zero ((char *) charttyout, sizeof(charttyout));
  393.       
  394.      /* Initialize charconin & out, 
  395.       * and set up the console for CHAR/BREAK=BMOB 
  396.       */
  397.           if (sys_gechr( channel(0), (1<<31)|$CLMAX, charconin)) 
  398.                { perror("sysinit: gechr 0"); return(-1); }
  399.           if (sys_gechr( channel(1), (1<<31)|$CLMAX, charconout)) 
  400.                { perror("sysinit: gechr 1"); return(-1); }
  401.           charconin[4] &= ~$CBKM;
  402.           charconin[4] |= $CBBM;
  403.           if (sys_sechr( channel(0), (1<<31)|$CLMAX, charconin)) 
  404.                { perror("sysinit: sechr stdin "); return(-1); }
  405.           if (sys_sechr( channel(1), (1<<31)|$CLMAX, charconout))
  406.                { perror("sysinit: sechr stdout "); return(-1); }
  407.  
  408.      return(0);
  409. }
  410.  
  411. /* S E T T O -- set timeout on the channel to period.
  412.                 Save the old characteristics in char***in[]. 
  413. */
  414. /* AOS/VS device timeouts are used sparingly in this implementation of    */
  415. /* Kermit.  In most cases, signals are used instead.                --ENH */
  416.  
  417. int setto(chan, period) int chan, period; 
  418. {
  419.      int isconsole = 0;
  420.      int iscon[2];       /* Flags because i/o could be redirected */
  421.  
  422.      /* Setting is done external to here, since they can distinguish the 
  423.         console from ttyfd device.  Both console channels must be set
  424.         the same.
  425.      */
  426.      if ( (chan == channel(0)) || (chan == channel(1)) ) {
  427.           isconsole = 1; zero((char *) iscon, sizeof(iscon));
  428.           chan = channel(0);
  429.           if (sys_gechr( channel(0), (1<<31)|$CLMAX, charconin)) 
  430.                if (isatty(0)) {
  431.                     iscon[0] = 1;
  432.                     perror("setto: gechr 0: "); 
  433.                     return(-1);
  434.                }
  435.           charcurr = charconin;
  436.           if (sys_gechr( channel(1), (1<<31)|$CLMAX, charconout)) 
  437.                if (isatty(1)) {
  438.                     iscon[1] = 1;
  439.                     perror("setto: gechr 1: "); 
  440.                     return(-1);
  441.                }
  442.           timocon = period;
  443.      }
  444.  
  445.      else {
  446.           if (sys_gechr( chan, (1<<31)|$CLMAX, chartty))
  447.                { perror("setto: gechr tty: "); return(-1); }
  448.           charcurr = chartty;
  449.           timotty = period;
  450.      }
  451.  
  452.      charcurr[1] |= (0100000>>$CTO);
  453.      if (sys_sechr( chan, (1<<31)|$CLMAX, charcurr))
  454.           if ((isconsole == 0) || iscon[0]) {
  455.                perror("setto: sechr: "); 
  456.                return(-1); 
  457.           }
  458.      if (sys_stom( chan, 1<<31, period)) 
  459.           if ((isconsole == 0) || iscon[0]) {
  460.                perror("setto: stom: "); 
  461.                return(-1);
  462.           }
  463.  
  464.      if (isconsole == 0) return(0);
  465.      
  466.      chan = channel(1);
  467.      charconout[1] |= (0100000>>$CTO);
  468.      if (sys_sechr( chan, (1<<31)|$CLMAX, charconout)) 
  469.           if (iscon[1]) {
  470.                perror("setto: sechr 1: "); 
  471.                return(-1);
  472.           }
  473.      if (sys_stom( chan, 1<<31, period)) 
  474.           if (iscon[1]) {
  475.                perror("setto: stom 1: "); 
  476.                return(-1);
  477.           }
  478.      return(0);
  479. }
  480.  
  481.  
  482. /* R E S T O -- reset timeouts to the previous values, and restore char */
  483.  
  484. int
  485. resto(chan) int chan;
  486. {
  487.      int i, chan0, chan1, iscon[2];
  488.  
  489.      if ( (chan==channel(0)) || (chan==channel(1)) ) {
  490.  
  491.           chan0 = channel(0);      chan1 = channel(1); 
  492.           iscon[0] = isatty(0);    iscon[1] = isatty(1);
  493.           charconin[1] &= ~(0100000>>$CTO);
  494.           if (sys_stom( chan0, 1<<31, -1)) 
  495.                if (iscon[0]) {
  496.                     perror("resto: stom 0: "); 
  497.                     return(-1);
  498.                }
  499.           for (i = 0; i < $CLMAX; i++) if (charconin[i] != 0) {
  500.                if (sys_sechr( chan0, (1<<31)|$CLMAX, charconin))
  501.                     if (iscon[0]) {
  502.                          perror("resto: sechr 0: "); 
  503.                          return(-1); 
  504.                     }
  505.                break;
  506.           }
  507.           charconout[1] &= ~(0100000>>$CTO);
  508.           if (sys_stom( chan1, 1<<31, -1)) 
  509.                if (iscon[1]) {
  510.                     perror("resto: stom 1: "); 
  511.                     return(-1);
  512.                }
  513.           for (i = 0; i < $CLMAX; i++) if (charconout[i] != 0) {
  514.                if (sys_sechr( chan1, (1<<31)|$CLMAX, charconout)) 
  515.                if (iscon[1]) {
  516.                     perror("resto: sechr 1: "); 
  517.                     return(-1);
  518.                }
  519.                break;
  520.           }
  521.  
  522.           timocon = 0; 
  523.      }
  524.      else {
  525.           chartty[1] &= ~(0100000>>$CTO);
  526.           if (sys_stom( chan, 1<<31, -1)) 
  527.                { perror("setto: stom tty: "); return(-1); }
  528.           for (i = 0; i < $CLMAX; i++) if (chartty[i] != 0) {
  529.                if (sys_sechr( chan, (1<<31)|$CLMAX, chartty))
  530.                     { perror("resto: sechr tty: "); return(-1); }
  531.                break;
  532.           }
  533.           timotty = 0; 
  534.      }
  535.       
  536.      return(0);
  537. }
  538.  
  539.  
  540. /* S E T F L O W -- Set flow control in the device. 
  541.      
  542.     The device is assumed to be an intelligent IAC, where a CHAR/ON/IFC/OFC
  543.     could be done.
  544.  
  545. */
  546. int setflow(chan) int chan;
  547. {
  548.      short termparms[$CLMAX];
  549.  
  550.      if (sys_gechr( chan, (1<<31)|$CLMAX, termparms)) 
  551.           { perror("setflow: gechr "); return(-1); }
  552.  
  553.      bitset(&termparms[4],$XOFC,1);
  554.      bitset(&termparms[4],$XIFC,1);
  555.      
  556.      if (sys_sechr( chan, (1<<31)|$CLMAX, termparms)) 
  557.           { perror("setflow: sechr "); return(-1); }
  558.  
  559.      return(0);
  560. }
  561.  
  562.  
  563. /* R E S F L O W -- Re-Set flow control in the device. 
  564.      
  565.     The device is assumed to be an intelligent IAC, where a CHAR/OFF/IFC/OFC
  566.     could be done.
  567.  
  568. */
  569. int resflow(chan) int chan;
  570. {
  571.      int i;
  572.      short termparms[$CLMAX];
  573.  
  574.      if (sys_gechr( chan, (1<<31)|$CLMAX, termparms)) 
  575.           { perror("resflow: gechr "); return(-1); }
  576.  
  577.      bitset(&termparms[4],$XOFC,0);
  578.      bitset(&termparms[4],$XIFC,0);
  579.      
  580.      if (sys_sechr( chan, (1<<31)|$CLMAX, termparms))
  581.           { perror("resflow: sechr "); return(-1); }
  582.  
  583.      return(0);
  584. }
  585.  
  586.  
  587. /* S E T S P E E D -- Set the baud rate when not possible thru IOCTL.
  588.      
  589.     The device is assumed to be an intelligent IAC, where a CHAR/ON/BAUD=
  590.     could be done.
  591.  
  592. */
  593. int setspeed(sp) int sp;
  594. {
  595.      short termparms[$CLMAX];
  596.  
  597.      /* ttyfd is the Unix file number for the tty device.  Setting the
  598.       * characteristics will set it for both ttyfd and ttyfdout, since
  599.       * it is the device itself which is affected, and not just the 
  600.       * channel.
  601.       */
  602.      if (sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, termparms)) 
  603.           { perror("setspeed: gechr "); return(-1); }
  604.  
  605.      termparms[3] &= ~$BRMSK;            /* Zero out the previous setting */
  606.      termparms[3] |= sp;
  607.      
  608.      if (sys_sechr( channel(ttyfd), (1<<31)|$CLMAX, termparms)) 
  609.           { perror("setspeed: sechr "); return(-1); }
  610.  
  611.      return(0);
  612. }
  613. #endif datageneral
  614.  
  615. /*  S Y S C L E A N U P  --  System-dependent cleanup */
  616.  
  617. int
  618. syscleanup() {
  619.     return(0);
  620.  
  621. /*  T T O P E N  --  Open a tty for exclusive access.  */
  622.  
  623. /*
  624.   Returns:
  625.     0 on success
  626.    -5 if device is in use
  627.    -4 if access to device is denied
  628.    -3 if access to lock directory denied
  629.    -2 upon timeout waiting for device to open
  630.    -1 on other error
  631. /*
  632.   If called with lcl < 0, sets value of lcl as follows:
  633.   0: the terminal named by ttname is the job's controlling terminal.
  634.   1: the terminal named by ttname is not the job's controlling terminal.
  635.   But watch out: if a line is already open, or if requested line can't
  636.   be opened, then lcl remains (and is returned as) -1.
  637. */
  638. int
  639. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem,timo; {
  640.  
  641.     /* AOS/VS special stuff */
  642.     FILE *dg_open();                    /* Custom file open */
  643.     int retrycnt = 0;                   /* Retry if Modem disc in progress */
  644.  
  645.     char *ctermid();                    /* Wish they all had this! */
  646.     char *x;
  647.     extern char* ttyname();
  648.     char cname[DEVNAMLEN+4];
  649.  
  650. #define NAMEFD
  651. #ifdef NAMEFD
  652.     int i, j; char *p;
  653.     debug(F101,"ttopen telnetfd","",telnetfd);
  654. #endif /* NAMEFD */
  655.  
  656.     debug(F111,"ttopen entry modem",ttname,modem);
  657.     debug(F101," ttyfd","",ttyfd);
  658.     debug(F101," lcl","",*lcl);
  659.  
  660.     if (ttyfd > -1) {
  661.         if (strncmp(ttname,ttnmsv,DEVNAMLEN))   /* are old & new the same? */
  662.             ttclos(ttyfd);                      /* no? - close old */
  663.         else                                    /* yes? - ignore this call */
  664.             return(0);                          /* and return */
  665.     }
  666.  
  667. #ifdef NETCONN
  668.     if (modem < 0) {                    /* means special code for net type */
  669.         int x;
  670.         ttmdm = modem;
  671.         modem = -modem;                 /* negative value is net type */
  672.         fdflag = 0;                     /* stdio not redirected */
  673.         ttyfdout = -1;                  /* only use ttyfd for nets */
  674.         netconn = 1;                    /* network connection */
  675.         debug (F111,"ttopen net",ttname,modem);
  676. #ifdef NAMEFD
  677.         for (p = ttname; isdigit(*p); p++) ; /* check for all digits */
  678.         if (*p == '\0' && telnetfd) {
  679.             ttyfd = atoi(ttname);       /* can we test if it's open? */
  680.             ttfdflg = 1;               /* we got an open file descriptor */
  681.             debug(F111,"ttopen got open network fd",ttname,ttyfd);
  682.             strncpy(ttnmsv,ttname,DEVNAMLEN);   /* remember the "name" */
  683.             x = 1;                      /* return code is "good" */
  684.             if (telnetfd) {
  685.                 ttnet = NET_TCPB;
  686.                 ttnproto = NP_TELNET;
  687.             }
  688.         } else {
  689. #endif /* NAMEFD */                             /* hostname or address */
  690.             x = netopen(ttname,lcl,modem);      /* (see ckcnet.h) */
  691.             if (x > -1) {
  692.                 strncpy(ttnmsv,ttname,DEVNAMLEN);
  693.             } else netconn = 0;
  694. #ifdef NAMEFD
  695.         }
  696. #endif NAMEFD
  697.  
  698. /* ENH - left out ifdef sony_news section */
  699.  
  700.         xlocal = *lcl = 1;              /* network connections are local */
  701.         debug(F101,"ttopen net x","",x);
  702.  
  703.         if ((x > -1) && (!x25fd))
  704.             x = tn_ini();               /* initialize telnet protocol */
  705.         return(x);
  706.     } else {                            /* terminal device */
  707. #endif /* NETCONN */
  708.  
  709. #ifdef NAMEFD
  710. /*
  711.   This code lets you give Kermit an open file descriptor for a serial
  712.   communication device, rather than a device name.  Kermit assumes that the
  713.   line is already open, locked, conditioned with the right parameters, etc.
  714. */
  715.         for (p = ttname; isdigit(*p); p++) ;    /* check for all digits */
  716.         if (*p == '\0') {
  717.             ttyfd = atoi(ttname);               /* can we test if open? */
  718.             debug(F111,"ttopen got open fd",ttname,ttyfd);
  719.             strncpy(ttnmsv,ttname,DEVNAMLEN);   /* remember the "name" */
  720.             xlocal = *lcl = 1;                  /* assume it's local */
  721.             netconn = 0;                        /* assume not network */
  722.             tvtflg = 0;                         /* initialize modes? */
  723.             ttmdm = modem;                      /* remember modem type */
  724.             fdflag = 0;                         /* stdio not redirected */
  725.             ttfdflg = 1;                        /* flag we were opened */
  726.                                                 /* this way */
  727. /* ENH - left out ifdef sony_news */
  728.  
  729.             return(0);                          /* return success */
  730.         }
  731. #endif /* NAMEFD */
  732. #ifdef NETCONN
  733.     }                           
  734. #endif /* NETCONN */
  735.  
  736. /* Here we have to open a serial device of the given name */
  737.  
  738.     tvtflg = 0;                         /* flag for use by ttvt() */
  739.                                         /* 0 means ttvt() not called yet */
  740.     fdflag = (!isatty(0) || !isatty(1));/* flag for stdio redirected */
  741.     debug(F101,"ttopen fdflag","",fdflag);
  742.     ttmdm = modem;                      /* Make this available to other fns */
  743.     xlocal = *lcl;                      /* Make this available to other fns */
  744.  
  745. /* Code for handling bidirectional tty lines goes here.
  746. /* Use specified method for turning off logins and suppressing getty. */
  747.  
  748. #ifdef ACUCNTRL
  749.     /* Should put call to priv_on() here, but that would be very risky! */
  750.     acucntrl("disable",ttname);         /* acucntrl() program. */
  751.     /* and priv_off() here... */
  752. #else
  753. #ifdef ATT7300
  754.     if ((attmodem & DOGETY) == 0)       /* offgetty() program. */
  755.       attmodem |= offgetty(ttname);     /* Remember response.  */
  756. #endif /* ATT7300 */
  757. #endif /* ACUCNTRL */
  758.  
  759. #ifdef datageneral
  760.     /* A custom open is done for the device, but a FILE handle is also needed
  761.      * for doing other special operations on the device.  See sysinit() for
  762.      * the initialization of the x_io_parms and xout_parms structures.
  763.      *
  764.      * First open up the output channel ($OFOT) 
  765.      */
  766.     idel_tbl[0] = 0x4;             /* CR only */
  767.     xout_parms.idel = idel_tbl;
  768.     xout_parms.ifnp = ttname;
  769.  
  770. /*
  771.     ttotmo = 0;
  772.     saval = signal(SIGALRM,timerh);
  773.     if (timo > 0) {
  774.         alarm(timo);              
  775.         if (setjmp(sjbuf)) {
  776.         } else {
  777. */           /* Ignore timeout for now - let it take as long as it wants */
  778. retry:
  779.     if ((ttfileout =
  780.        dg_open(ttname, xout_parms.isti, xout_parms.isto, 
  781.                xout_parms.imrs,xout_parms.ires,xout_parms.idel))
  782.        == NULL) {
  783.           /* If a modem disconnect, or one in progress, wait and retry. */
  784.           if ((lasterror() == ERDCT) || (lasterror() == ERCDS))
  785.                if (retrycnt == 0) {
  786.                     retrycnt = 1; 
  787.                     sleep(2); 
  788.                     goto retry; 
  789.                }
  790.           ttyfdout = -1;
  791.           perror("ttopen: output_line: dg_open");
  792.           if ((lasterror() == EREO1) || (lasterror() == EREO2)) /* in use */
  793.               return(-5);                               /* EOF */
  794.           else if (lasterror() == ERFAD)
  795.               return(-4);                               /* access denied */
  796.           else                                          /* some other error */
  797.               return(-1);
  798.     }
  799.     /* Successfull opens fall through here! */
  800.     
  801.     ttyfdout = fileno(ttfileout);               /* Note that ttyfdout is */
  802.     xout_parms.ich = channel(ttyfdout);         /* only used for asynch  */
  803.     
  804.     /* Next, open up the input channel ($OFIN) */
  805.  
  806.     x_io_parms.ifnp = ttname;
  807.     /* IDEL would default to NULL, FF, CR, NL as delimiters.
  808.      * The only delimiters here are CR and NL, for data sensitive 
  809.      * records.
  810.      */
  811.     idel_tbl[0] = 0x24;
  812.     x_io_parms.idel = idel_tbl;
  813.  
  814.     if ((ttfile =
  815.        dg_open(ttname, x_io_parms.isti, x_io_parms.isto, 
  816.                x_io_parms.imrs,x_io_parms.ires,x_io_parms.idel,
  817.                (P_SCREEN *) x_io_parms.etsp))
  818.        == NULL) {
  819.           ttyfd = -1;
  820.           perror("ttopen: input_line: dg_open");
  821.           if ((lasterror() == EREO1) || (lasterror() == EREO2)) /* in use */
  822.               return(-5);                               /* EOF */
  823.           else if (lasterror() == ERFAD)
  824.               return(-4);                               /* access denied */
  825.           else                                          /* some other error */
  826.               return(-1);
  827.        }
  828.     else {
  829.           ttyfd = fileno(ttfile);
  830.           x_io_parms.ich = channel(ttyfd);
  831.     }
  832.  
  833. #endif
  834.  
  835.     /* Make sure it's a real tty. */
  836.     if (!isatty(ttyfd)) {
  837.         fprintf(stderr,"%s is not a tty!\n",ttname);
  838.         debug(F110,"ttopen not a tty",ttname,0);
  839.         close(ttyfd);
  840.         ttyfd = -1;
  841.         return(-1);
  842.     }
  843.  
  844.     strncpy(ttnmsv,ttname,DEVNAMLEN);   /* Open, keep copy of name locally. */
  845.  
  846. /* Caller wants us to figure out if line is controlling tty */
  847.  
  848.     debug(F111,"ttopen ok",ttname,*lcl);
  849.     if (*lcl == -1) {
  850.         if (strcmp(ttname,CTTNAM) == 0) {   /* "/dev/tty" always remote */
  851.             debug(F110," Same as CTTNAM",ttname,0);
  852.             xlocal = 0;
  853.         } else if (isatty(0)) {         /* Else, if stdin not redirected */
  854.             x = ttyname(0);             /* then compare its device name */
  855.             strncpy(cname,x,DEVNAMLEN); /* (copy from internal static buf) */
  856.             debug(F110," ttyname(0)",x,0);
  857.             x = ttyname(ttyfd);         /* ...with real name of ttname. */
  858.             xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
  859.             debug(F111," ttyname",x,xlocal);
  860.         }                               /* Else, if stdin redirected... */
  861.     }    
  862.  
  863. /* Now check if line is locked -- if so fail, else lock for ourselves */
  864.  
  865.     lkf = 0;                            /* Check lock */
  866.     if (xlocal > 0) {
  867.         if (ttlock(ttname) < 0) {
  868.             fprintf(stderr,"Exclusive access to %s denied\n",ttname);
  869.             close(ttyfd); ttyfd = -1;
  870.             debug(F110," Access denied by lock",ttname,0);
  871.  
  872.             return(-3);
  873.         } else lkf = 1;
  874.     }
  875.  
  876. /* Got the line, now set the desired value for local. */
  877.  
  878.     if (*lcl != 0) *lcl = xlocal;
  879.  
  880. /* Request exclusive access on systems that allow it. */
  881.  
  882. #ifdef TIOCEXCL
  883.         if (ioctl(ttyfd,TIOCEXCL, NULL) < 0)
  884.             fprintf(stderr,"Warning, problem getting exclusive access\n");
  885. #endif
  886.  
  887. /* Get tty device settings */
  888.  
  889.     ioctl(ttyfd,TCGETA,&ttold);         /* Same deal for Sys III, Sys V */
  890.     ioctl(ttyfd,TCGETA,&ttraw);
  891.     ioctl(ttyfd,TCGETA,&tttvt);
  892.  
  893.     debug(F101,"ttopen, ttyfd","",ttyfd);
  894.  
  895.     debug(F101,"ttopen, ttyfdout","",ttyfdout);
  896.     /* For DG, also get the tty extended device characteristics. */
  897.     sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttold);
  898.     sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttraw);
  899.     sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttvt);
  900.  
  901.     debug(F101," lcl","",*lcl);
  902.     debug(F111," lock file",flfnam,lkf);
  903.     return(0);
  904. }
  905.  
  906. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  907. int
  908. ttclos(foo) int foo; {
  909.     int x = 0;
  910.  
  911.     debug(F101,"ttclos ttyfd","",ttyfd);
  912.     if (ttyfd < 0) return(0);           /* Wasn't open. */
  913.     if (ttfdflg) return(0);             /* If we got ttyfd from another */
  914.                                         /* process, don't close it. */
  915.     tvtflg = 0;
  916.  
  917. #ifdef  NETCONN
  918.     if (netconn) {                      /* Network connection. */
  919.         debug(F100,"ttclos closing net","",0);
  920.         netclos();                      /* Close it. */
  921.         netconn = 0;
  922.         return(0);
  923.     }
  924. #endif  /* NETCONN */
  925.  
  926.     if (xlocal) {
  927.         debug(F100,"ttclos skipping ttunlck for AOS/VS","",0);
  928.         debug(F100,"ttclos about to call tthang()","",0);
  929.     }
  930.     if (ttyfd > 0) {
  931.                                         /* & timer stuff &  moved closes in */
  932.         saval = signal(SIGALRM,timerh); /* enable timer */
  933.         alarm(5);                       /* allow 5 seconds for completion */
  934.         if (setjmp(sjbuf)) {            /* timer went off */
  935.             x = -1;                     /* set return value */
  936.         } else {                        /* what we're really trying to do */
  937.             if (xlocal) {
  938.                 if (tthang())           /* Hang up first, then... */
  939.                     fprintf(stderr,"Warning, problem hanging up the phone\n");
  940.                 ttres();                /* reset device modes. */
  941.             }
  942. #ifdef TIOCEXCL
  943. #ifdef TIOCNXCL
  944.            if (ioctl(ttyfd, TIOCNXCL, NULL) < 0)
  945.                 fprintf(stderr,"Problem relinquishing exclusive access\n");
  946. #endif
  947. #endif
  948.  
  949.             debug(F101,"ttclos, ttyfd","",ttyfd);
  950.             debug(F101,"ttclos, ttyfdout","",ttyfdout);
  951.             fclose(ttfile);                     /* Close it. */
  952.  
  953.             /* Close the output tty device */
  954.             fclose(ttfileout);                  /* Close it. */
  955.             x = 1;                              /* good return */
  956.         }
  957.         ttimoff();                              /* turn off timer */
  958.         if (x < 0) {
  959.             fprintf(stderr,"?Timed out closing device: %s\n",ttnmsv);
  960.             debug(F100,"ttclos timed out","",0);
  961.         }
  962.     }
  963.     ttyfd = -1;                         /* Mark it as closed. */
  964.     ttyfdout = -1;                      /* Mark it as closed. */
  965.  
  966.     debug(F100,"ttclos done","",0);
  967.     return(0);
  968. }
  969.  
  970. /*  T T H A N G -- Hangup phone line */
  971.  
  972. tthang() {
  973.     unsigned short ttc_save;
  974.     int x;
  975.  
  976.     if (ttyfd < 0) return(0);           /* Not open. */
  977.     if (xlocal < 1) return(0);
  978.  
  979. #ifdef NETCONN
  980.     if (netconn) {                      /* Network connection. */
  981.         return ((netclos() < 0) ?  -1 : 1); /* Close it */
  982.     }
  983. #endif /* NETCONN */
  984.  
  985.     ttc_save = ttraw.c_cflag;
  986.     ttraw.c_cflag &= ~CBAUD;            /* swa: set baud rate to 0 to hangup */
  987.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* do it */
  988.     msleep(100);                        /* let things settle */
  989.     ttraw.c_cflag = ttc_save;
  990.     debug(F100, "tthang disconnecting line","",0);
  991.     if (sys_sechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttraw)) 
  992.          { perror("tthang: sechr "); return(-1); }
  993.     if (ioctl(ttyfd,TCSETAF,&ttraw) < 0) return(-1); /* un-do it */
  994.     return (0);
  995. }
  996.  
  997.  
  998. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  999.  
  1000. ttres() {                               /* Restore the tty to normal. */
  1001.     int x;
  1002.  
  1003.     if (ttyfd < 0) return(-1);          /* Not open. */
  1004.  
  1005.     if (ttfdflg) return(0);             /* Don't mess with terminal modes if */
  1006.                                         /* we got ttyfd from another process */
  1007. #ifdef  NETCONN
  1008.     if (netconn) return (0);            /* Network connection, do nothing */
  1009. #endif  /* NETCONN */
  1010.  
  1011.     x = (ioctl(ttyfd,TCSETAW,&ttold) < 0);       /* restore termio stuff */
  1012.  
  1013.     /* Un-set all the timeouts */
  1014.     if (timotty) {
  1015.          resto(channel(ttyfd));
  1016.          resto(channel(ttyfdout));
  1017.     }
  1018.     if (sys_sechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttold)) 
  1019.          { perror("ttres: sechr "); return(-1); }
  1020.  
  1021.     return(0);
  1022. }
  1023.  
  1024. /* Exclusive uucp file locking control */
  1025. /*
  1026.  by H. Fischer, creative non-Bell coding !
  1027.  copyright rights for lock modules assigned to Columbia University
  1028. */
  1029.  
  1030. /* The AOS/VS implementation does not use uucp locks.   --ENH */
  1031.  
  1032. static char *
  1033. xxlast(s,c) char *s; char c; {          /* Equivalent to strrchr() */
  1034.     int i;
  1035.     for (i = strlen(s); i > 0; i--)
  1036.         if ( s[i-1] == c ) return( s + (i - 1) );
  1037.     return(NULL);           
  1038. }
  1039. static
  1040. look4lk(ttname) char *ttname; {
  1041.     extern char *strcat(), *strcpy();
  1042.     char *device, *devname;
  1043.     char lockfil[50];                   /* Max length for lock file name */
  1044.     char *lockdir = "/usr/spool/uucp";
  1045.  
  1046.     device = ( (devname=xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
  1047.  
  1048.     strcat( strcpy( lockfil, "LCK.." ), device );
  1049.  
  1050.     if (access( lockdir, 04 ) < 0) {    /* read access denied on lock dir */
  1051.         fprintf(stderr,"Warning, read access to lock directory denied\n");
  1052.         return( 1 );                    /* cannot check or set lock file */
  1053.     }
  1054.         
  1055.     strcat(strcat(strcpy(flfnam,lockdir),"/"), lockfil);
  1056.     debug(F110,"look4lk",flfnam,0);
  1057.  
  1058.     if ( ! access( flfnam, 00 ) ) {     /* print out lock file entry */
  1059.         char lckcmd[40] ;
  1060.         strcat( strcpy(lckcmd, "ls -l ") , flfnam);
  1061.         system(lckcmd);
  1062.         if (access(flfnam,02) == 0)
  1063.             printf("(You may type \"! rm %s\" to remove this file)\n",flfnam);
  1064.         return( -1 );
  1065.     }
  1066.     if ( access( lockdir, 02 ) < 0 ) {  /* lock file cannot be written */
  1067.         fprintf(stderr,"Warning, write access to lock directory denied\n");
  1068.         return( 1 );
  1069.     }
  1070.  
  1071.     return( 0 );                        /* okay to go ahead and lock */
  1072. }
  1073.  
  1074. /*  T T L O C K  */
  1075.  
  1076.  
  1077. static
  1078. ttlock(ttyfd) char *ttyfd; {            /* lock uucp if possible */
  1079.  
  1080. #ifdef datageneral
  1081.     /* The Data General locks a device when that device is opened.  So
  1082.      * return that the device is already locked.
  1083.      * Besides, because of internal multi-tasking, locking the device by
  1084.      * the ?ASSIGN call or an $IEXO flag would cause problem for the task
  1085.      * id that did not open the device first.
  1086.      */
  1087. #else datageneral
  1088.     int lck_fil, l4l;
  1089.     int pid_buf = getpid();             /* pid to save in lock file */
  1090.         
  1091.     haslock = 0;                        /* not locked yet */
  1092.     l4l = look4lk(ttyfd);
  1093.     if (l4l < 0) return (-1);           /* already locked */
  1094.     if (l4l == 1) return (0);           /* can't read/write lock directory */
  1095.     lck_fil = creat(flfnam, 0444);      /* create lock file ... */
  1096.     if (lck_fil < 0) return (-1);       /* create of lockfile failed */
  1097.                 /* creat leaves file handle open for writing -- hf */
  1098.     write (lck_fil, &pid_buf, sizeof(pid_buf) ); /* uucp expects int in file */
  1099.     close (lck_fil);
  1100. #endif datageneral
  1101.     haslock = 1;                        /* now is locked */
  1102.     return(0);
  1103. }
  1104.  
  1105. /*  T T U N L O C K  */
  1106.  
  1107. static
  1108. ttunlck() {                             /* kill uucp lock if possible */
  1109. #ifdef datageneral
  1110.     /* The DG automatically unlocks the device when it is closed, or when
  1111.      * the process is terminated for any reason.  Unlocking is not needed.
  1112.      * Also, see the note for ttlock().
  1113.      */
  1114.     return(0);
  1115. #else
  1116.     if (haslock) return( unlink( flfnam ) ); 
  1117. #endif
  1118.  
  1119. }
  1120.  
  1121. /*  T T P K T  --  Condition the communication line for packets. */
  1122. /*              or for modem dialing */
  1123.  
  1124. #define DIALING 4               /* flags (via flow) for modem handling */
  1125. #define CONNECT 5
  1126.  
  1127. /*  If called with speed > -1, also set the speed.  */
  1128.  
  1129. /*  Returns 0 on success, -1 on failure.  */
  1130.  
  1131. ttpkt(speed,xflow,parity) long speed; int xflow, parity; {
  1132.     int s2;
  1133.     int s = -1;
  1134.     int x;
  1135.     extern int flow;                    /* REAL flow-control setting */
  1136.  
  1137.     if (ttyfd < 0) return(-1);          /* Not open. */
  1138.  
  1139.     debug(F101,"ttpkt parity","",parity);
  1140.     debug(F101,"ttpkt xflow","",xflow);
  1141.     debug(F101,"ttpkt speed","",(int) speed);
  1142.  
  1143.     ttprty = parity;                    /* Let other tt functions see these. */
  1144.     ttpflg = 0;                         /* Parity not sensed yet */
  1145.     ttpmsk = ttprty ? 0177 : 0377;      /* Parity stripping mask */
  1146.     ttspeed = speed;
  1147.  
  1148. #ifdef NETCONN                          /* Nothing to do for telnet */
  1149.     if (netconn) return (0);
  1150. #endif /* NETCONN */
  1151.  
  1152.     if (ttfdflg && !isatty(ttyfd)) return(0);
  1153.  
  1154.     if (xflow != FLO_DIAL && xflow != FLO_DIAX)
  1155.       ttflow = xflow;                   /* Now make this available too. */
  1156.  
  1157.     if (xlocal) {
  1158.         s2 = (int) (speed / 10L);       /* convert bps to cps */
  1159.         s = ttsspd(s2);                 /* get associated speed */
  1160.         if (s < 0)
  1161.             return(-1);
  1162.         /* carrctl() call here in UNIX code */  
  1163.     }
  1164.                                         
  1165. #ifdef UXIII
  1166.     if (flow == FLO_XONX) ttraw.c_iflag |= (IXON|IXOFF);
  1167.     else if (flow == FLO_NONE) ttraw.c_iflag &= ~(IXON|IXOFF);
  1168.     else if (flow == FLO_KEEP) {
  1169.         ttraw.c_iflag &= ~(IXON|IXOFF);
  1170.         ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF));
  1171.     } else if (flow == FLO_RTSC) {
  1172.         /* RTS/CTS Flow control... */
  1173. #ifdef RTSXOFF
  1174.         /* This is the preferred way, according to SVID R4 */
  1175.         if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
  1176.             rctsx.x_hflag |= RTSXOFF | CTSXON;
  1177.             ioctl(ttyfd,TCSETX,&rctsx); /* Ignore errors for now. */
  1178.         }
  1179. #else
  1180. #ifdef CRTSCTS
  1181.         /* Found this one in <termios.h> */
  1182.         ttraw.c_iflag |= CRTSCTS;
  1183. #endif /* CRTSCRS */
  1184. #endif /* RTSXOFF */
  1185.     }
  1186.     if (flow == FLO_DTRC) {
  1187.         /* DTR/CD Flow control... */
  1188. #ifdef DTRXOFF
  1189.         /* This is straight out of SVID R3 */
  1190.         if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
  1191.             rctsx.x_hflag |= DTRXOFF | CDXON;
  1192.             ioctl(ttyfd,TCSETX,&rctsx); /* Ignore errors. */
  1193.         }
  1194. #endif /* DTRXOFF */
  1195.     }
  1196.     if (flow == DIALING)  ttraw.c_cflag |= CLOCAL|HUPCL;
  1197.     if (flow == CONNECT)  ttraw.c_cflag &= ~CLOCAL;
  1198.  
  1199.     ttraw.c_lflag &= ~(ICANON|ECHO);
  1200.     ttraw.c_lflag &= ~ISIG;
  1201.     ttraw.c_lflag |= NOFLSH;            /* Don't flush */
  1202.     ttraw.c_iflag |= (BRKINT|IGNPAR);
  1203.     ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
  1204.     ttraw.c_oflag &= ~OPOST;
  1205. #ifdef datageneral
  1206.     ttraw.c_lflag &= ~CSETPM;      /* No DG page mode */
  1207. #endif
  1208.     ttraw.c_cc[4] = 1;
  1209.     ttraw.c_cflag &= ~(CSIZE|PARENB);
  1210.     ttraw.c_cflag |= (CS8|CREAD);
  1211.     ttraw.c_cc[5] = 0;
  1212.  
  1213. #ifdef VINTR                            /* Turn off interrupt character */
  1214.     if (xlocal == 0)                    /* so ^C^C can break us out of */
  1215.       ttraw.c_cc[VINTR] = 0;            /* packet mode. */
  1216. #endif /* VINTR */
  1217.  
  1218.     if (s > -1) {
  1219.         ttraw.c_cflag &= ~CBAUD;
  1220.         ttraw.c_cflag |= s;             /* set speed */
  1221.     }
  1222.  
  1223.     if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1);  /* set new modes . */
  1224. #ifdef datageneral
  1225.     if (flow == FLO_XONX) {
  1226.          setflow(channel(ttyfdout));
  1227.          setflow(channel(ttyfd));
  1228.     }
  1229.     if (flow == FLO_NONE) {
  1230.          resflow(channel(ttyfdout));
  1231.          resflow(channel(ttyfd));
  1232.     }
  1233.     /* if flow is FLO_KEEP, don't do anything */
  1234.     if (sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttraw)) 
  1235.          { perror("ttpkt: gechr: "); return(-1); }
  1236. #endif
  1237.  
  1238.     if (flow == DIALING) {
  1239. #ifdef datageneral
  1240. #ifndef aosvs
  1241.         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0)) < 0 )
  1242.                 return(-1);
  1243. #endif
  1244. #else
  1245.         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  1246.                 return(-1);
  1247.         close( open(ttnmsv,2) );        /* magic to force mode change!!! */
  1248. #endif
  1249.         }
  1250.  
  1251. #endif
  1252.  
  1253.     ttflui();                           /* Flush any pending input */
  1254.     tvtflg = 0;
  1255.     return(0);
  1256. }
  1257.  
  1258. /*  T T V T -- Condition communication line for use as virtual terminal  */
  1259.  
  1260. ttvt(speed,flow) int speed, flow; {
  1261.     int s, s2;
  1262.  
  1263.     debug(F101,"ttvt ttyfd","",ttyfd);
  1264.     debug(F101,"ttvt tvtflg","",tvtflg);
  1265.     debug(F101,"ttvt speed","",speed);
  1266.  
  1267.     if (ttyfd < 0) return(-1);          /* Not open. */
  1268.  
  1269. #ifdef NETCONN
  1270.     if (netconn) {
  1271.         tvtflg = 1;                     /* Network connections */
  1272.         return(0);                      /* require no special setup */
  1273.     }
  1274. #endif /* NETCONN */
  1275.  
  1276.     if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr)
  1277.       return(0);                        /* Already been called. */
  1278.  
  1279.     if (ttfdflg && !isatty(ttyfd)) return(0);
  1280.  
  1281.     if (xlocal) {
  1282.         s2 = (int) (speed / 10L);       /* convert bps to cps */
  1283.         s = ttsspd(s2);                 /* Check the speed */
  1284.         /* ENH - UNIX has call to carrctl here */
  1285.     }
  1286.     if (flow == FLO_XONX) tttvt.c_iflag |= (IXON|IXOFF);
  1287.     else if (flow == FLO_KEEP) {
  1288.         tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
  1289.         tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
  1290.     }else if (flow == FLO_NONE) tttvt.c_iflag &= ~(IXON|IXOFF);
  1291.  
  1292.     if (flow == DIALING)  tttvt.c_cflag |= CLOCAL|HUPCL;
  1293.     if (flow == CONNECT)  tttvt.c_cflag &= ~CLOCAL;
  1294.  
  1295.     tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
  1296.     tttvt.c_iflag |= (IGNBRK|IGNPAR);
  1297.     tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY);
  1298.     tttvt.c_oflag &= ~OPOST;
  1299.     tttvt.c_cflag &= ~(CSIZE|PARENB);
  1300.     tttvt.c_cflag |= (CS8|CREAD);
  1301.     tttvt.c_cc[4] = 1;
  1302.     tttvt.c_cc[5] = 0;
  1303.  
  1304.     if (s > -1) {
  1305.         tttvt.c_cflag &= ~CBAUD;
  1306.         tttvt.c_cflag |= s; /* set speed */
  1307.     }
  1308.  
  1309.     if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1);  /* set new modes . */
  1310.  
  1311. #ifdef datageneral
  1312.     if (flow == FLO_XONX) {
  1313.          setflow(channel(ttyfdout));
  1314.          setflow(channel(ttyfd));
  1315.     }
  1316.     if (flow == FLO_NONE) {
  1317.          resflow(channel(ttyfdout));
  1318.          resflow(channel(ttyfd));
  1319.     }
  1320.     if (sys_gechr( channel(ttyfd), (1<<31)|$CLMAX, ch_ttvt)) 
  1321.          { perror("ttvt: gechr: "); return(-1); }
  1322. #endif
  1323.  
  1324.     if (flow == DIALING) {
  1325. #ifdef datageneral
  1326. #ifndef aosvs
  1327.         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0)) < 0 )
  1328.                 return(-1);
  1329. #endif
  1330. #else
  1331.         if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 )
  1332.                 return(-1);
  1333.         close( open(ttnmsv,2) );        /* magic to force mode change!!! */
  1334. #endif
  1335.         }
  1336.  
  1337.     ttspeed = speed;                    /* Done, remember how we were */
  1338.     ttflow = flow;                      /* called, so we can decide how to */
  1339.     tvtflg = 1;                         /* respond next time. */
  1340.  
  1341.     debug(F101,"ttvt done","",tvtflg);
  1342.     return(0);
  1343. }
  1344.  
  1345. /*  T T S S P D  --  Return the internal baud rate code for 'speed'.  */
  1346.  
  1347. ttsspd(cps) {
  1348.     int s,s2,spdok;
  1349.  
  1350.     debug(F101,"ttsspd","",cps);
  1351.  
  1352. #ifdef  NETCONN
  1353.     if (netconn) return (0);
  1354. #endif  /* NETCONN */
  1355.  
  1356.     if (cps < 0) return(-1);
  1357.         spdok = 1;                      /* Assume arg ok */
  1358.         switch (cps) {
  1359.             case 0:   s = B0;    break; /* Just the common ones. */
  1360.             case 11:  s = B110;  break; /* The others from ttydev.h */
  1361.             case 15:  s = B150;  break; /* could also be included if */
  1362.             case 30:  s = B300;  break; /* necessary... */
  1363.             case 60:  s = B600;  break;
  1364.             case 120: s = B1200; break;
  1365.             case 180: s = B1800; break;
  1366.  
  1367.             case 240: s = B2400; break;
  1368.             case 480: s = B4800; break;
  1369.             case 960: s = B9600; break;
  1370. #ifdef datageneral
  1371.             /* ioctl() allows other speeds */
  1372.             case 5:     s = B50; break;
  1373.             case 7:     s = B75; break;
  1374.             case 13:    s = B134; break;
  1375.             case 360:   s = B3600; break;
  1376.             case 720:   s = B7200; break;
  1377.             case 1920:  s = B19000; break;
  1378.  
  1379.             /* Some speeds are supported by the hardware thru PMGR.
  1380.                We don't bother about 45.5 but it could be added.
  1381.             */
  1382.             case 38400:  if (setspeed($CR38K)) spdok = 0; s = 0; break;
  1383. #endif
  1384.             default:
  1385.                 spdok = 0;
  1386.                 fprintf(stderr,"Unsupported line speed - %d\n",cps * 10);
  1387.                 fprintf(stderr,"Current speed not changed\n");
  1388.                 break;
  1389.         }           
  1390.         if (spdok)
  1391.             return(s);
  1392.         else
  1393.             return(-1);
  1394.  }
  1395.  
  1396. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  1397.  *
  1398.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  1399.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  1400.  *  2 = Auto: For "modem direct": The same as "Off".
  1401.  *            For real modem types: Heed carrier during connect, but ignore
  1402.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  1403.  *
  1404.  * As you can see, this setting does not affect dialing, which always ignores
  1405.  * carrier (unless there is some special exception for some modem type).  It
  1406.  * does affect ttopen() if it is set before ttopen() is used.  This setting
  1407.  * takes effect on the next call to ttopen()/ttpkt()/ttvt().  And they are
  1408.  * (or should be) always called before any communications is tried, which
  1409.  * means that, practically speaking, the effect is immediate.
  1410.  *
  1411.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  1412.  *
  1413.  * Someone has yet to uncover how to manipulate the carrier in the BSD
  1414.  * environment (or any non-termio using environment).  Until that time, this
  1415.  * will simply be a no-op for BSD.
  1416.  *
  1417.  * Note that in previous versions, the carrier was most often left unchanged
  1418.  * in ttpkt()/ttvt() unless they were called with DIALING or CONNECT.  This
  1419.  * has changed.  Now it is controlled by ttcarr in conjunction with these
  1420.  * modes.
  1421.  */
  1422. int
  1423. ttscarr(carrier) int carrier; {
  1424.     ttcarr = carrier;
  1425.     debug(F101, "ttscarr","",ttcarr);
  1426.     return(ttcarr);
  1427. }
  1428.  
  1429. int
  1430. ttgmdm() {                              /* Read modem signals */
  1431.     return(-3);                         /* ENH - return value of -3 means */
  1432. }                                       /* not implemented, which it's not */
  1433.                                         /* because this can't (easily) be */
  1434.                                         /* done in AOS/VS */
  1435.  
  1436. int
  1437. ttwmdm(mdmsig,timo) int mdmsig,timo; {  /* wait timo seconds for specified */
  1438.     return(-3);                         /* modem signals to appear */
  1439. }
  1440.  
  1441.  
  1442. long
  1443. ttgspd() {                              /* Get line speed */
  1444.     P_CHAR_EX   cp;                     /* characteristics packet */
  1445.     int         ac0,ac1,ac2,error;
  1446.     static int  baud_rate[] = {
  1447.                     50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,
  1448.                     7200,9600,19200},
  1449.                 baud_rate_x[] = {45,38400};
  1450.  
  1451. #ifdef NETCONN
  1452.     if (netconn) return (-1);
  1453. #endif /* NETCONN */
  1454.  
  1455.     if (ttyfd < 0)
  1456.         return (-1);
  1457.     else {
  1458.         ac0 = channel(ttyfd);
  1459.         ac1 = $CLMAX | BIT0;
  1460.         ac2 = (P_CHAR_EX *) &cp;
  1461.         error = sys($GECHR,&ac0,&ac1,&ac2);
  1462.         if (error)
  1463.             return(-1);
  1464.  
  1465.         if (cp.char_br0bit == 0)
  1466.             return(baud_rate[cp.char_br_1_4]);
  1467.         else
  1468.             return(baud_rate_x[cp.char_br_1_4]);
  1469.     }
  1470. }
  1471.  
  1472. int
  1473. psuspend() {                            /* ENH - not possible in VS */
  1474.     return(-1);
  1475. }
  1476.  
  1477. /* Interrupt Functions */
  1478.  
  1479. /* Set up terminal interrupts on console terminal */
  1480.  
  1481. #ifdef UXIII
  1482. esctrp() {                              /* trap console escapes (^\) */
  1483.  
  1484.     conesc = 1;
  1485.     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
  1486. }
  1487. #endif
  1488.  
  1489. /*  C O N I N T  --  Console Interrupt setter  */
  1490. VOID
  1491. conint(f,s) SIGTYP (*f)(), (*s)(); {    /* Set an interrupt trap. */
  1492.  
  1493.     if (!isatty(0)) {                   /* only for real ttys */
  1494.         debug(F101,"conint not a tty","",isatty(0));
  1495.         return;
  1496.     }
  1497.     if (backgrd) {                      /* must ignore signals in bkgrd */
  1498.         debug(F101,"conint backgrd ignoring signals","",backgrd);
  1499.         return;
  1500.     }
  1501.     else debug(F101,"conint foreground catching signals","",0);
  1502. /*
  1503.  Except for special cases below, ignore keyboard quit signal.
  1504.  ^\ too easily confused with connect escape, and besides, we don't want
  1505.  to leave lock files around.  (Frank Prindle)
  1506. */
  1507. #ifdef datageneral
  1508.     /* Set up the asynchronous task to read the console. 
  1509.      * But, I don't want them set up all the time, so I will kludge up the
  1510.      * call in  chkint() (ckuus3.c) to see if this asynch task is running:
  1511.      * conint_mt()
  1512.      */
  1513. #endif
  1514.     signal(SIGQUIT,SIG_IGN);
  1515.  
  1516. #ifdef UXIII
  1517.     signal(SIGQUIT,esctrp);             /* console escape in pkt modes */
  1518.     if (conesc) {                       /* clear out pending escapes */
  1519.         conesc = 0;
  1520.     }
  1521. #endif
  1522.  
  1523.     if (conif) return;                  /* Nothing to do if already on. */
  1524.  
  1525. /* check if invoked in background -- if so signals set to be ignored */
  1526.  
  1527.     if (signal(SIGINT,SIG_IGN) == SIG_IGN) {
  1528.         backgrd = 1;                    /*   means running in background */
  1529. #ifdef UXIII
  1530.         signal(SIGQUIT,SIG_IGN);        /*   must leave signals ignored */
  1531. #endif
  1532.         return;
  1533.     }
  1534.     signal(SIGINT,f);                   /* Function to trap to on interrupt. */
  1535.     signal(SIGHUP,f);                   /* Or hangup, so lock file cleared. */
  1536.     conif = 1;                          /* Flag console interrupts on. */
  1537. }
  1538.  
  1539.  
  1540. /*  C O N N O I  --  Reset console terminal interrupts */
  1541.  
  1542. connoi() {                              /* Console-no-interrupts */
  1543.  
  1544.     if (!isatty(0)) return(0);          /* only for real ttys */
  1545.     if (backgrd) return;                /* Ignore signals in background */
  1546.  
  1547. #ifdef datageneral
  1548.     /* Terminate the asynchronous task that reads the console for
  1549.      * interrupt characters. 
  1550.      * But, I don't want to kill this task all the time, so I will kludge 
  1551.      * up the call in input() (ckcfn2.c) to kill the asynch task if it
  1552.      * is running: connoi_mt()
  1553.      */
  1554. #endif
  1555.     signal(SIGINT,SIG_DFL);
  1556.     signal(SIGHUP,SIG_DFL);
  1557.     signal(SIGQUIT,SIG_DFL);
  1558.     conif = 0;                          /* Flag interrupt trapping off */
  1559. }
  1560.  
  1561. #ifdef datageneral
  1562. /* C O N I N T _ M T  -- Asynch read console task */
  1563.  
  1564. void conint_mt() {
  1565.     int count = 0;
  1566.  
  1567.     /* Any input waiting? */
  1568.     con_reads_mt = 1;                   /* Flag that task is active */
  1569.     conint_avl = 0;                     /* Flag that interrupt gotten */
  1570.     while (con_reads_mt)
  1571.         if ((conint_ch = coninc(2)) > 0) { /* If character at keyboard */
  1572.             conint_avl = 1;             /* we set the flag */
  1573.             while ((conint_avl) && (++count <= 5))
  1574.                 sleep(1);               /* & wait for char to be processed */
  1575.         }
  1576.         count = 0;                      /* initialize counter */
  1577.         conint_avl = 0;
  1578. }
  1579.  
  1580.  
  1581. /* C O N N O I _ M T  -- Kill asynch read console task */
  1582.  
  1583. connoi_mt() {
  1584.     conint_avl = 0;
  1585.     if (con_reads_mt) {
  1586.         con_reads_mt = 0;
  1587.         midkill(CONINT_TSK);
  1588.     }
  1589. }
  1590.  
  1591.  
  1592. /* C O N S T A _ M T  --  Start the console asynch read task */
  1593.  
  1594. consta_mt() {
  1595.     if ((con_reads_mt == 0)      /* Not already running */
  1596.      && (mtask(conint_mt, CONINT_STACK, CONINT_TSK, CONINT_PRI) != 0))
  1597.         perror("consta_mt: Can't initiate task:");
  1598. }
  1599. #endif datageneral
  1600.  
  1601. /* Private buffer for myread() and its companions.  Not for use by anything
  1602.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  1603.  * allowed to read my_count.
  1604.  *
  1605.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  1606.  *
  1607.  * A global parity mask variable could be useful too.  We could use it to
  1608.  * let myread() strip the parity on its own, instead of stripping sign
  1609.  * bits as it does now.
  1610.  */
  1611.  
  1612. #define MYBUFLEN 256
  1613. #define PEEKTYPE long
  1614. static CHAR mybuf[MYBUFLEN];            /* Buffer, including push back */
  1615. static int my_count = 0;                /* Number of chars still in mybuf */
  1616. static int my_item = -1;                /* Last index read from mybuf[] */
  1617.  
  1618. /* myread() -- Efficient read of one character from communications line.
  1619.  *
  1620.  * Uses a private buffer to minimize the number of expensive read() system
  1621.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  1622.  * is then returned.  By reading all available input from the system buffers
  1623.  * to the private buffer in one chunk, and then working from this buffer, the
  1624.  * number of system calls is reduced in any case where more than one character
  1625.  * arrives during the processing of the previous chunk, for instance high
  1626.  * baud rates or network type connections where input arrives in packets.
  1627.  * If the time needed for a read() system call approaches the time for more
  1628.  * than one character to arrive, then this mechanism automatically compensates
  1629.  * for that by performing bigger read()s less frequently.  If the system load
  1630.  * is high, the same mechanism compensates for that too.
  1631.  *
  1632.  * myread() is a macro that returns the next character from the buffer.  If the
  1633.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  1634.  * returns.
  1635.  *
  1636.  * This should be efficient enough for any one-character-at-a-time loops.
  1637.  * For even better efficiency you might use memcpy()/bcopy() or such between
  1638.  * buffers (since they are often better optimized for copying), but it may not
  1639.  * be worth it if you have to take an extra pass over the buffer to strip
  1640.  * parity and check for CTRL-C anyway.
  1641.  *
  1642.  * Note that if you have been using myread() from another program module, you
  1643.  * may have some trouble accessing this macro version and the private variables
  1644.  * it uses.  In that case, just add a function in this module, that invokes the
  1645.  * macro.
  1646.  */
  1647.  
  1648. #define myread()  (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
  1649.  
  1650.  
  1651. /* not used right now */
  1652. /*
  1653. myunrd(ch) CHAR ch; {
  1654.     ungotn = ch;
  1655. }
  1656. */
  1657.  
  1658. /* mygetbuf() -- Fill buffer for myread() and return first character.
  1659.  *
  1660.  * This function is what myread() uses when it can't get the next character
  1661.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  1662.  * to read at least one new character into the buffer, and then it returns
  1663.  * the first character just as myread() would have done.  This function also
  1664.  * is responsible for all error conditions that myread() can indicate.
  1665.  *
  1666.  * Returns: When OK     => a positive character, 0 or greater.
  1667.  *          When EOF    => -2.
  1668.  *          When error  => -3, error code in errno.
  1669.  *
  1670.  * Older myread()s additionally returned -1 to indicate that there was nothing
  1671.  * to read, upon which the caller would call myread() again until it got
  1672.  * something.  The new myread()/mygetbuf() always gets something.  If it
  1673.  * doesn't, then make it do so!  Any program that actually depends on the old
  1674.  * behaviour will break.
  1675.  *
  1676.  * The older version also used to return -2 both for EOF and other errors,
  1677.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  1678.  * other errors now return different results, although Kermit currently never
  1679.  * checks to see which it was.  It just disconnects in both cases.
  1680.  *
  1681.  * Kermit lets the user use the quit key to perform some special commands
  1682.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  1683.  * finish without reading anything and return the EINTR error.  This should
  1684.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  1685.  * but if there is nothing to read, this could delay Kermit's reaction to
  1686.  * the command, and make Kermit appear unresponsive.
  1687.  *
  1688.  * The debug() call should be removed for optimum performance.
  1689.  */
  1690. int
  1691. mygetbuf() {
  1692.     my_count = myfillbuf();                     
  1693.     /* debug(F101, "myfillbuf read", "", my_count); */
  1694.     if (my_count <= 0)
  1695.       return(my_count < 0 ? -3 : -2);
  1696.     --my_count;
  1697.     return(255 & (int)mybuf[my_item = 0]);
  1698. }
  1699.  
  1700. /* myfillbuf():
  1701.  * System-dependent read() into mybuf[], as many characters as possible.
  1702.  *
  1703.  * Returns: OK => number of characters read, always more than zero.
  1704.  *          EOF => 0
  1705.  *          Error => -1, error code in errno.
  1706.  *
  1707.  * If there is input available in the system's buffers, all of it should be
  1708.  * read into mybuf[] and the function return immediately.  If no input is
  1709.  * available, it should wait for a character to arrive, and return with that
  1710.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  1711.  * character, but be aware that any such delay lengthens the packet turnaround
  1712.  * time during kermit file transfers.  Should never return with zero characters
  1713.  * unless EOF or irrecoverable read error.
  1714.  *
  1715.  * Correct functioning depends on the correct tty parameters being used.
  1716.  * Better control of current parameters is required than may have been the
  1717.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can
  1718.  * no longer be sometimes off and sometimes on like it used to, unless a
  1719.  * special myfillbuf() is written to handle that.  Otherwise the ordinary
  1720.  * myfillbuf()s may think they have come to EOF.
  1721.  *
  1722.  * If your system has a facility to directly perform the functioning of
  1723.  * myfillbuf(), then use it.  If the system can tell you how many characters
  1724.  * are available in its buffers, then read that amount (but not less than 1).
  1725.  * If the system can return a special indication when you try to read without
  1726.  * anything to read, while allowing you to read all there is when there is
  1727.  * something, you may loop until there is something to read, but probably that
  1728.  * is not good for the system load.
  1729.  */
  1730. int
  1731. myfillbuf() {
  1732.     int n;
  1733.     int retry_count = 5;                        /* max # of retries */
  1734.  
  1735. #ifdef NETCONN
  1736.     if (netconn) {
  1737.         n = read(ttyfd, mybuf, sizeof(mybuf));
  1738.         if (n <= 0)
  1739.             debug(F101,"myfillbuf() got error reading from network, ","",n);
  1740.         return(n);
  1741.     } else {                                      /* console read */
  1742. #endif /* NETCONN */
  1743.         while (1) {
  1744.             n = dgncinb(ttyfd, mybuf, sizeof(mybuf));
  1745.             if (n > 0) {
  1746.                 return(n);
  1747.             }
  1748.             if ((n == -EROVR) || (n == -1) || (n == -2) || (n == 0)) {
  1749.                 if (n == -EROVR)
  1750.                     debug(F101,"myfillbuf() got data overrun ind., ","",-n);
  1751.                 else if (n == -1)
  1752.                     debug(F101,"myfillbuf() got EOF ind., ","",n);
  1753.                 else if (n == -2)
  1754.                     debug(F101,"myfillbuf() got device timeout ind., ","",n);
  1755.                 else
  1756.                     debug(F101,"myfillbuf() got zero characters, ","",n);
  1757.                 if (--retry_count > 0) {
  1758.                     debug(F101,"myfillbuf() tries remaining, ","",retry_count);
  1759.                     sleep(1);   /* keep trying on data over- */
  1760.                     continue;   /* run, EOF (-1), timeout (-2) & 0 */
  1761.                 } 
  1762.             } else if (n < -2)                  /* VS errors complimented */
  1763.                 debug(F101,"myfillbuf() got AOS/VS error ","",-n);
  1764.             if (n == -1)                        /* EOF is -1, but caller */
  1765.                 n = 0;                          /* wants it to be zero   */
  1766.             else n = -1;                        /* all others -1 */
  1767.             return(n);
  1768.         }
  1769. #ifdef NETCONN
  1770.     }
  1771. #endif /* NETCONN */
  1772.  
  1773. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  1774.  
  1775. ttchk() {
  1776.     int x;
  1777.     PEEKTYPE n = 0;
  1778.  
  1779. #ifdef COMMENT
  1780. /*
  1781.   This was REALLY slowing TELNET connections down!  Just do the regular
  1782.   ttyfd-based stuff here.  Let the VMS version call nettchk if it has to...
  1783.   FIONREAD definitely works for TELNET, at least on the NeXT and SUNOS.
  1784. */
  1785. #ifdef NETCONN
  1786.     if (netconn) return (nettchk());
  1787. #endif /* NETCONN */
  1788. #endif /* COMMENT */
  1789.  
  1790.     if (my_count > 0)               /* Sys III, Sys V, Apollo Aegis, etc */
  1791.         n += my_count;
  1792.     debug(F101,"ttchk chars available, ","",n);
  1793.     return(n);
  1794. }
  1795.  
  1796. /*  T T F L U I  --  Flush tty input buffer */
  1797.  
  1798. ttflui() {
  1799.     int ffd;
  1800.  
  1801. #ifndef UXIII
  1802.     long n;
  1803. #endif
  1804.  
  1805.     my_count = 0;                       /* Initialize myread() stuff */
  1806.     my_item = -1;
  1807.  
  1808. #ifdef NETCONN
  1809.     if (netconn) return(netflui());
  1810. #endif /* NETCONN */
  1811.  
  1812.     ffd = xlocal ? ttyfd : 0;           /* If not local, use stdin */
  1813.     debug(F101,"ttflui xlocal","",xlocal);
  1814.     debug(F101,"ttflui ttyfd","",ttyfd);
  1815.     debug(F101,"ttflui ffd","",ffd);
  1816.  
  1817.     if (ffd < 0) return(-1);            /* Not open. */
  1818.     
  1819.  
  1820. #ifdef UXIII
  1821. #ifdef datageneral
  1822.     /* Since $ESGT is turned on in the sys_read packets, there is never a need
  1823.      * to flush the input buffer -- the system automatically does it each time
  1824.      * a read is issued.
  1825.      */
  1826. #endif
  1827. #endif
  1828.  
  1829.     return(0);
  1830. }
  1831.  
  1832. int
  1833. ttfluo() {                              /* Flush output buffer - dummy */
  1834.     return(0);                          /* POSIX is only implementation */
  1835. }                                       /* that needs this */
  1836.  
  1837.  
  1838. /*  T T X I N  --  Get n characters from tty input buffer  */
  1839.  
  1840. /*  Returns number of characters actually gotten, or -1 on failure  */
  1841.  
  1842. /*  Intended for use only when it is known that n characters are actually */
  1843. /*  Available in the input buffer.  */
  1844.  
  1845. ttxin(n,buf) int n; CHAR *buf; {
  1846.     int x;
  1847.     int c;
  1848.  
  1849.     ttpmsk = (ttprty) ? 0177: 0377;             /* parity stripping mask */
  1850.     debug(F101,"ttxin: n","",n);
  1851.  
  1852.     for( x = 0; (x > -1) && (x < n) && (c = myread()) >= 0; )
  1853.       buf[x++] = c & ttpmsk;
  1854.  
  1855.     debug(F101," x","",x);                      
  1856.     for (c = 0; c < n; c++)
  1857.         buf[c] &= ttpmsk;
  1858.     if (x > 0) buf[x] = '\0';
  1859.     else if (x < 0) x = -1;
  1860.     return(x);
  1861. }
  1862.  
  1863. #define TTOLMAXT 5
  1864.  
  1865. /*  T T O L  --  Similar to "ttinl", but for writing.  */
  1866.  
  1867. ttol(s,n) int n; char *s; {
  1868.     int x,len,tries,outfd;
  1869.  
  1870. #ifdef NETCONN
  1871.     if (netconn) {
  1872.         if (ttyfd < 0) return (-1);
  1873.     } else
  1874. #endif /* NETCONN */
  1875.     if (ttyfdout < 0) return (-1);
  1876.  
  1877.     debug(F101,"ttol n","",n);
  1878.     tries = TTOLMAXT;
  1879.     len = n;
  1880.  
  1881.     while ((n > 0) && (tries-- > 0)) {
  1882.         debug(F101,"ttol try","",TTOLMAXT - tries);
  1883. #ifdef NETCONN
  1884.         if (netconn)
  1885.             x = write(ttyfd,s,n);
  1886.         else
  1887. #endif /* NETCONN */
  1888.         x = dgncoub(ttyfdout,s,n); 
  1889.         if (x == n) {
  1890.             debug(F101,"ttol ok","",x);
  1891.             return(len);
  1892.         } else if (x < 0) {
  1893.             debug(F101,"ttol failed","",lasterror());
  1894.             return(-1);
  1895.         } else {
  1896.             debug(F101,"ttol partial","",x);
  1897.             s += x;                     /* update buffer address for next */
  1898.             n -= x;                     /* update length for next read */
  1899.             if (x > 0) msleep(100);
  1900.         }
  1901.     }
  1902.     return((n < 1) ? len : -1);
  1903. }
  1904.  
  1905.  
  1906. /*  T T O C  --  Output a character to the communication line  */
  1907. /*
  1908.  This function should only be used for interactive, character-mode operations,
  1909.  like terminal connection, script execution, dialer i/o, where the overhead
  1910.  of the signals and alarms does not create a bottleneck.
  1911. */
  1912.  
  1913. ttoc(c) char c; {
  1914.     int x,xx;
  1915. #define TTOC_TMO 15
  1916.     c &= 0xff;
  1917.     /* debug(F101,"ttoc","",(CHAR) c); */
  1918. #ifdef NETCONN
  1919.     if (netconn) {
  1920.         if (ttyfd < 0) return(-1);
  1921.     } else
  1922. #endif /* NETCONN */
  1923.     if (ttyfdout < 0) return(-1);  /* Not open. */
  1924.     saval = signal(SIGALRM,timerh);
  1925.     xx = alarm(TTOC_TMO);
  1926.     if (xx < 0) xx = 0;                 /* Save old alarm value. */
  1927.     if (setjmp(sjbuf)) {
  1928.         ttimoff();
  1929.         if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
  1930. #ifdef NETCONN
  1931.         if (!netconn) {
  1932. #endif /* NETCONN */
  1933.             /* debug(F100,"ttoc timeout","",0); */
  1934.             if (ttflow == FLO_XONX) {
  1935.                 debug(F100,"ttoc flow","",ttflow);
  1936.                 /* issue clear device */
  1937.             }
  1938. #ifdef NETCONN
  1939.         }
  1940. #endif /* NETCONN */
  1941.         return(-1);
  1942.     } else {
  1943. #ifdef NETCONN
  1944.         if (netconn)                    /* use ttyfd for tcp connections */
  1945.             x = write(ttyfd,&c,1);
  1946.         else                            /* ttyfdout for local connections */
  1947. #endif /* NETCONN */
  1948.             x = (dgncoub(ttyfdout,&c,1)); 
  1949.         if (x != 1) {
  1950.             ttimoff();                  /* If error, turn off timer, */
  1951.             alarm(xx);
  1952.             debug(F101,"ttoc error x","",x);
  1953.             debug(F101,"ttoc last error","",lasterror());
  1954.             return (-1);
  1955.         }
  1956.     }
  1957.     ttimoff();
  1958.     alarm(xx);
  1959.     return (0);
  1960. }
  1961.  
  1962. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1963. /*
  1964.  Reads up to "max" characters from the communication line, terminating on:
  1965.  
  1966.     (a) the packet length field if the "turn" argument is zero, or
  1967.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  1968.  
  1969.   and returns the number of characters read upon success, or if "max" was
  1970.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  1971.  
  1972.   The characters that were input are copied into "dest" with their parity bits
  1973.   stripped if parity was selected.  Returns the number of characters read.
  1974.   Characters after the eol are available upon the next call to this function.
  1975.  
  1976.   The idea is to minimize the number of system calls per packet, and also to
  1977.   minimize timeouts.  This function is the inner loop of the program and must
  1978.   be as efficient as possible.  The current strategy is to use myread().
  1979.  
  1980.   WARNING: this function calls parchk(), which is defined in another module.
  1981.   Normally, ckutio.c does not depend on code from any other module, but there
  1982.   is an exception in this case because all the other ck?tio.c modules also
  1983.   need to call parchk(), so it's better to have it defined in a common place.
  1984. */
  1985.  
  1986. /* ENH -- assume PARSENSE */
  1987.  
  1988. #ifdef CTRLC
  1989. #undef CTRLC
  1990. #endif /* CTRLC */
  1991. #define CTRLC '\03'
  1992.  
  1993. int
  1994. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest,eol,start; {
  1995.     int pktlen = -1;
  1996.     int j;
  1997.     CHAR ch;
  1998.     int lplen = 0;
  1999.     int havelen = 0;
  2000.  
  2001.     if (ttyfd < 0) return(-1);          /* Not open. */
  2002.     if (turn)
  2003.         debug(F101,"ttinl read until eol, turn","",turn);
  2004.     else
  2005.         debug(F101,"ttinl read packet-length characters, turn","",turn);
  2006.     debug(F101,"ttinl max","",max);
  2007.     debug(F101,"ttinl timo","",timo);
  2008.  
  2009.     *dest = '\0';                       /* Clear destination buffer */
  2010.  
  2011.     if (timo < 0) timo = 0;
  2012.    
  2013.     if (timo) {                         /* Don't time out if timo == 0 */
  2014.         saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
  2015.         alarm(timo);                    /* Set it. */
  2016.     }
  2017.     if (setjmp(sjbuf)) {                /* Timer went off? */
  2018.         debug(F100,"ttinl timout","",0); /* Get here on timeout. */
  2019.         debug(F110," with",(char *) dest,0);
  2020.         ttimoff();                      /* Turn off timer */
  2021.         return(-1);                     /* and return error code. */
  2022.     } else {
  2023.         int i, m, n;
  2024.         int ccn = 0;
  2025.         int flag = 0;
  2026.  
  2027.         debug(F000,"ttinl start","",start);
  2028.         flag = 0;                       /* Start of packet flag */
  2029.  
  2030.         ttpmsk = m = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */
  2031.  
  2032. /* Now read into destination, stripping parity and looking for the */
  2033. /* the packet terminator, and also for two Ctrl-C's typed in a row. */
  2034.  
  2035.         i = 0;                          /* Destination index */
  2036.         debug(F101,"ttinl eol","",eol);
  2037.         while (i < max-1) {
  2038.             /* debug(F101,"ttinl i","",i); */
  2039.             if ((n = myread()) < 0) {
  2040.                 debug(F101,"ttinl myread failure, n","",n);
  2041.                 debug(F101,"ttinl myread errno,","",errno);
  2042.                 /* Don't let EINTR break packets. */
  2043.                 if (n == -3 && errno == EINTR && i > 0) {
  2044.                     debug(F101,"ttinl myread i","",i);
  2045.                     continue;
  2046.                 }
  2047.                 break;
  2048.             }
  2049.             debug(F101,"ttinl char","", (n & ttpmsk)); 
  2050. /*
  2051.   Figure out what the length is supposed to be in case the packet
  2052.   has no terminator (as with Honeywell GCOS-8 Kermit).
  2053. */
  2054. #ifndef xunchar
  2055. #define xunchar(ch) (((ch) - 32 ) & 0xFF )      /* Character to number */
  2056. #endif /* xunchar */
  2057.             if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
  2058.             if (flag) dest[i++] = n & ttpmsk;
  2059. /*
  2060.   If we have not been instructed to wait for a turnaround character, we
  2061.   can go by the packet length field.  If turn != 0, we must wait for the
  2062.   end of line (eol) character before returning.
  2063. */
  2064.             if (i == 2) {
  2065.                 pktlen = xunchar(dest[1]);
  2066.                 havelen = (pktlen > 1);
  2067.                 debug(F101,"ttinl length","",pktlen);
  2068.             } else if (i == 5 && pktlen == 0) {
  2069.                 lplen = xunchar(dest[4]);
  2070.             } else if (i == 6 && pktlen == 0) {
  2071.                 pktlen = lplen * 95 + xunchar(dest[5]) + 5;
  2072.                 havelen = 1;
  2073.                 debug(F101,"ttinl length","",pktlen);
  2074.             }
  2075.             if ((n & 0x7f) == CTRLC) {  /* Check for ^C^C */
  2076.                 if (++ccn > 1) {        /* If we got 2 in a row, bail out. */
  2077.                     if (timo) {         /* Clear timer. */
  2078.                         ttimoff();
  2079.                     }
  2080.                     fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  2081.                     return(-2);
  2082.                 }
  2083.             } else ccn = 0;             /* Not ^C, so reset ^C counter, */
  2084.             if (flag == 0) {
  2085.                 debug(F101,"ttinl skipping","",n);
  2086.                 continue;
  2087.             }
  2088.  
  2089.     /* Check for end of packet */
  2090.  
  2091.             if (((n & 0x7f) == eol) || (!turn && havelen && (i > pktlen+1))) {
  2092.                 if ((n & 0x7f) != eol) {
  2093.                     debug(F101,"ttinl EOP length","",pktlen);
  2094.                     debug(F101,"ttinl i","",i);
  2095.                 } else debug(F101,"ttinl got eol","",eol);
  2096.                 dest[i] = '\0';         /* Terminate the string, */
  2097.  
  2098. /* Here's where we actually check and adjust the parity. */
  2099. /* The major flaw here is if parity is NONE (ttprty = 0) and the packets */
  2100. /* really do have no parity, then parchk() is called for every packet. */
  2101. /* In practice, this doesn't really harm efficiency noticably, but it would */
  2102. /* be better if ttinl() had a way of knowing to stop doing this once a */
  2103. /* particular file transfer had been started and checked. */
  2104.                 if (ttpflg++ == 0 && ttprty == 0) {
  2105.                     if ((ttprty = parchk(dest,start,i)) > 0) {
  2106.                         int j;
  2107.                         debug(F101,"ttinl senses parity","",ttprty);
  2108.                         debug(F110,"ttinl packet before",dest,0);
  2109.                         ttpmsk = 0x7f;
  2110.                         for (j = 0; j < i; j++)
  2111.                           dest[j] &= 0x7f;      /* Strip parity from packet */
  2112.                         debug(F110,"ttinl packet after ",dest,0);
  2113.                     } else debug(F101,"parchk","",ttprty);
  2114.                 }
  2115.                 if (timo) {                     /* Turn off timer. */
  2116.                     ttimoff();
  2117.                 }
  2118.                 debug(F111,"ttinl got", dest,i);
  2119.                 return(i);
  2120.             }
  2121.         }                               /* end of while() */
  2122.         ttimoff();
  2123.         return(-1);
  2124.     }
  2125.  
  2126. /*  T T I N C --  Read a character from the communication line  */
  2127. /*
  2128.  On success, returns the character that was read, >= 0.
  2129.  On failure, returns -1 or other negative myread error code.
  2130. */
  2131.  
  2132. int
  2133. ttinc(timo) int timo; {
  2134.     int n = 0;
  2135.     CHAR ch = 0;
  2136.  
  2137.     if (ttyfd < 0) return(-1);          /* Not open. */
  2138.     if (timo <= 0) {                    /* Untimed. */
  2139.         /* comm line failure returns -1 thru myread, so no &= 0377 */
  2140.         n = myread();                   /* Wait for a character... */
  2141.         /* debug(F101,"ttinc n","",n); */
  2142.         return(n < 0 ? n : n & ttpmsk);
  2143.     } else {
  2144.         int xx;
  2145.         saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
  2146.         xx = alarm(timo);               /* calls because I'm getting errors  */
  2147.         if (setjmp(sjbuf))              /* about these signal calls -- " the */
  2148.             n = -1;                     /* destination of a non-local GOTO is*/
  2149.         else {                          /* an inactive block" */
  2150.             n = myread();               /* If managing own buffer... */
  2151.             /* debug(F101,"ttinc myread","",n); */
  2152.         }
  2153.         ttimoff();
  2154. #ifdef NETCONN
  2155.         if (netconn) {
  2156.             if (n == -2) {              /* read() returns 0 */
  2157.                 netclos();              /* on network read failure */
  2158.                 netconn = 0;            /* ENH - deleted errno = ENOTCON */
  2159.             }
  2160.         }
  2161. #endif  /* NETCONN */
  2162.         return( (n < 0) ? n : (n & ttpmsk) ); /* Return masked char or neg. */
  2163.     }
  2164. }
  2165.  
  2166. /*  T T S N D B  --  Send a BREAK signal  */
  2167.  
  2168. ttsndb() {
  2169.     int x; long n; char spd;            /* In VS, the duration of the break */
  2170.                                         /* is until next write() or charac- */
  2171.     debug(F101,"ttsndb ttyfd","",ttyfd); /* teristics change                */
  2172.     if (ttyfd < 0) return(-1);          /* Not open. */
  2173.  
  2174. #ifdef NETCONN
  2175.     if (netconn)                        /* Send network BREAK */
  2176.       return(netbreak());
  2177. #endif /* NETCONN */
  2178.  
  2179. #ifdef UXIII
  2180. #ifdef datageneral
  2181.     if (sys_clrdv(channel(ttyfdout),1<<31,$CDSBRK)) {   /* Send a BREAK */
  2182.         perror("Can't send BREAK");
  2183.         return(-1);
  2184.     }
  2185.     return(0);
  2186. #endif
  2187. #endif
  2188. }
  2189.  
  2190. /* T T S N D L B  --  Send a "long" BREAK signal */
  2191.  
  2192. ttsndlb() {             /* In VS, they're long by default -- see ttsndb() */
  2193.     return(ttsndb());
  2194. }
  2195.  
  2196.  
  2197. /*  M S L E E P  --  Millisecond version of sleep().  */
  2198.  
  2199. /*
  2200.  Intended only for small intervals.  For big ones, just use sleep().
  2201. */
  2202.  
  2203. msleep(m) int m; {
  2204.  
  2205. #ifdef UXIII
  2206. #define CLOCK_TICK 17                   /* 1/60 sec */
  2207.     extern long times();
  2208.     long t1, t2, tarray[4];
  2209.     int t3;
  2210.  
  2211.     if (m <= 0) return(0);
  2212.     if ((t1 = times(tarray)) < 0) return(-1);
  2213.     while (1) {
  2214.         if ((t2 = times(tarray)) < 0) return(-1);
  2215.         t3 = ((int)(t2 - t1)) * CLOCK_TICK;
  2216.         if (t3 > m) return(t3);
  2217.     }
  2218. #endif
  2219. }
  2220.  
  2221.  
  2222. /*  R T I M E R --  Reset elapsed time counter  */
  2223.  
  2224. rtimer() {
  2225.     tcount = time( (long *) 0 );
  2226. }
  2227.  
  2228.  
  2229. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  2230.  
  2231. gtimer() {
  2232.     int x;
  2233.     x = (int) (time( (long *) 0 ) - tcount);
  2234.     debug(F101,"gtimer","",x);
  2235.     /* rtimer(); */
  2236.     return( (x < 0) ? 0 : x );
  2237. }
  2238.  
  2239.  
  2240. /*  Z T I M E  --  Return date/time string  */
  2241.  
  2242. ztime(s) char **s; {
  2243.  
  2244. #ifdef UXIII
  2245.     extern long time();                 /* Sys III/V way to do it */
  2246.     char *ctime();
  2247.     long clock_storage;
  2248.  
  2249.     clock_storage = time( (long *) 0 );
  2250.     *s = ctime( &clock_storage );
  2251. #endif
  2252. }
  2253.  
  2254.  
  2255. /*  C O N G M  --  Get console terminal modes.  */
  2256.  
  2257. /*
  2258.  Saves current console mode, and establishes variables for switching between 
  2259.  current (presumably normal) mode and other modes.
  2260. */
  2261.  
  2262. congm() {
  2263.     if (backgrd || !isatty(0)) {  /* only for real ttys */
  2264.         cgmf = -1;
  2265.         return (-1);            /* it used to return a zero for this case */
  2266.     }
  2267.      ioctl(0,TCGETA,&ccold);
  2268.      ioctl(0,TCGETA,&cccbrk);
  2269.      ioctl(0,TCGETA,&ccraw);
  2270.      /* For DG, also get the tty extended device characteristics. */
  2271.      sys_gechr( channel(0), (1<<31)|$CLMAX, ch_ccold);
  2272.      sys_gechr( channel(0), (1<<31)|$CLMAX, ch_ccraw);
  2273.      sys_gechr( channel(0), (1<<31)|$CLMAX, ch_ccbrk);
  2274.      cgmf = 1;                          /* Flag that we got them. */
  2275. }
  2276.  
  2277.  
  2278.  
  2279. /*  C O N C B --  Put console in cbreak mode.  */
  2280.  
  2281. /*  Returns 0 if ok, -1 if not  */
  2282.  
  2283. concb(esc) char esc; {
  2284.     int x;
  2285.     debug(F101,"concb backgrd","",backgrd);
  2286.     if (!isatty(0)) return(0);          /* only for real ttys */
  2287.     debug(F100,"concb isatty","",0);
  2288.     if (backgrd) return(0);
  2289.     if (cgmf == 0) congm();             /* Get modes if necessary. */
  2290.     escchr = esc;                       /* Make this available to other fns */
  2291.     ckxech = 1;                         /* Program can echo characters */
  2292. #ifdef datageneral
  2293.     cccbrk.c_lflag |= CBREAK;
  2294. #endif
  2295.     cccbrk.c_lflag &= ~(ICANON|ECHO);
  2296.     cccbrk.c_cc[0] = 003;               /* interrupt char is control-c */
  2297.     cccbrk.c_cc[1] = escchr;            /* escape during packet modes */
  2298.     cccbrk.c_cc[4] = 1;
  2299.     cccbrk.c_cc[5] = 1;
  2300.     x = ioctl(0,TCSETAW,&cccbrk);       /* set new modes . */
  2301. #ifdef datageneral
  2302.     if (sys_gechr( channel(0), (1<<31)|$CLMAX, ch_ccbrk)) 
  2303.          { perror("concb: gechr: "); return(-1); }
  2304. #endif
  2305. #ifndef NOSETBUF
  2306.     if (x > -1) setbuf(stdout,NULL);    /* Make console unbuffered. */
  2307. #endif /* NOSETBUF */
  2308.     return(x);
  2309. }
  2310.  
  2311. /*  C O N B I N  --  Put console in binary mode  */
  2312.  
  2313. /*  Returns 0 if ok, -1 if not  */
  2314.  
  2315. conbin(esc) char esc; {
  2316. int filedes,filedes2;
  2317.  
  2318.     if (!isatty(0)) return(0);          /* only for real ttys */
  2319.     if (cgmf == 0) congm();             /* Get modes if necessary. */
  2320.     escchr = esc;                       /* Make this available to other fns */
  2321.     ckxech = 1;                         /* Program can echo characters */
  2322.     ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
  2323.     ccraw.c_iflag |= (BRKINT|IGNPAR);
  2324.     ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
  2325.                         |INPCK|ISTRIP);
  2326.     ccraw.c_oflag &= ~OPOST;
  2327.  
  2328. /*** Kermit used to put the console in 8-bit raw mode, but some users have
  2329.  *** pointed out that this should not be done, since some sites actually
  2330.  *** use terminals with parity settings on their Unix systems, and if we
  2331.  *** override the current settings and stop doing parity, then their terminals
  2332.  *** will display blotches for characters whose parity is wrong.  Therefore,
  2333.  *** the following two lines are commented out (Larry Afrin, Clemson U):
  2334.  ***
  2335.  ***   ccraw.c_cflag &= ~(PARENB|CSIZE);
  2336.  ***   ccraw.c_cflag |= (CS8|CREAD);
  2337.  ***
  2338.  *** Sys III/V sites that have trouble with this can restore these lines.
  2339.  ***/
  2340.     ccraw.c_cc[4] = 1;
  2341.     ccraw.c_cc[5] = 1;
  2342. #ifdef datageneral
  2343.     if (ioctl(0,TCSETAW,&ccraw)) return(-1);    /* set new modes . */
  2344.     if (sys_gechr( channel(0), (1<<31)|$CLMAX, ch_ccraw))
  2345.          { perror("conbin: gechr: "); return(-1); }
  2346.     return(0);
  2347. #else
  2348.     return(ioctl(0,TCSETAW,&ccraw) );   /* set new modes . */
  2349. #endif
  2350. }
  2351.  
  2352.  
  2353. /*  C O N R E S  --  Restore the console terminal  */
  2354.  
  2355. conres() {
  2356.     if (cgmf == 0) return(0);           /* Don't do anything if modes */
  2357.     if (!isatty(0)) return(0);          /* only for real ttys */
  2358. #ifdef datageneral
  2359.     if (timocon) 
  2360.          /* Timeouts are set, so un-set them. */
  2361.          resto(channel(0));
  2362. #endif
  2363.     ckxech = 0;                         /* System should echo chars */
  2364. #ifdef datageneral
  2365.     if (ioctl(0,TCSETAW,&ccold)) return(-1);    /* set new modes . */
  2366.     if (sys_sechr( channel(0), (1<<31)|$CLMAX, ch_ccold))
  2367.          { perror("conres: sechr "); return(-1); }
  2368.     return(0);
  2369. #else
  2370.     return(ioctl(0,TCSETAW,&ccold));
  2371. #endif
  2372. }
  2373.  
  2374.  
  2375. /*  C O N O C  --  Output a character to the console terminal  */
  2376.  
  2377. conoc(c) char c; {
  2378.     write(1,&c,1);
  2379. }
  2380.  
  2381. /*  C O N X O  --  Write x characters to the console terminal  */
  2382.  
  2383. conxo(x,s) char *s; int x; {
  2384.     write(1,s,x);
  2385. }
  2386.  
  2387. /*  C O N O L  --  Write a line to the console terminal  */
  2388.  
  2389. conol(s) char *s; {
  2390.     int len;
  2391.     len = strlen(s);
  2392.     write(1,s,len);
  2393. }
  2394.  
  2395. /*  C O N O L A  --  Write an array of lines to the console terminal */
  2396.  
  2397. conola(s) char *s[]; {
  2398.     int i;
  2399.     for (i=0 ; *s[i] ; i++) conol(s[i]);
  2400. }
  2401.  
  2402. /*  C O N O L L  --  Output a string followed by CRLF  */
  2403.  
  2404. conoll(s) char *s; {
  2405.     conol(s);
  2406.     write(1,"\r\n",2);
  2407. }
  2408.  
  2409.  
  2410. /*  C O N C H K  --  Return how many characters available at console  */
  2411.  
  2412. conchk() {
  2413.     int x; long n;
  2414.  
  2415.     if (!isatty(0)) return (0);
  2416. #ifdef UXIII
  2417.     if (conesc) {                       /* Escape typed */
  2418.         conesc = 0;
  2419.         signal(SIGQUIT,esctrp);         /* Restore escape */
  2420.         return(1);
  2421.     }
  2422.     return(0);
  2423. #else
  2424. #ifdef FIONREAD
  2425.     x = ioctl(0, FIONREAD, &n);         /* BSD and maybe some others */
  2426.     return((x < 0) ? 0 : n);
  2427. #else
  2428.     return(0);                          /* Others can't do. */
  2429. #endif
  2430. #endif
  2431. }
  2432.  
  2433.  
  2434. #ifdef datageneral
  2435.  
  2436. /* D G N C O U B -- Output len characters to the file number filenum */
  2437.  
  2438. dgncoub(filenum,chs,len) int filenum, len; char *chs; 
  2439. {
  2440.      int ac2,err;
  2441.  
  2442.      if (len == 0) return(0);
  2443.  
  2444.      if (filenum == ttyfdout) {
  2445.           xout_parms.ibad = chs;
  2446.           xout_parms.ircl = len;
  2447.           ac2 = &xout_parms;
  2448.      } else {
  2449.           w_io_parms.ich = channel(filenum);
  2450.           w_io_parms.ibad = chs;
  2451.           w_io_parms.ircl = len;
  2452.           ac2 = &w_io_parms;
  2453.      }
  2454.      
  2455.      if ((err = sys_write(ac2)) == 0)
  2456.          return(((P_NIO_EX *) ac2)->irlr);  /* ENH - change to return length */
  2457.      if ( err != ERLTL && err != EREOF ) {
  2458.           perror("dgncoub: sys_write ");
  2459.           return(-err);                     /* ENH - change to return */
  2460.      }                                      /* negative of error code */
  2461.      else return(((P_NIO_EX *) ac2)->irlr);
  2462. }
  2463.  
  2464.  
  2465. /* D G N C I N B -- System level read of len characters from file number 
  2466.    fileno.  The global DG i/o structures are used for this.
  2467.  
  2468.    Return codes:  irlr if data read ok, where irlr=length of data
  2469.                   -1 if EOF
  2470.                   -2 if timeout occured
  2471.                   -err if an AOS/VS error occured, where err is errno
  2472. */                  
  2473.  
  2474. dgncinb(filenum,chs,len)
  2475. int filenum,len; char *chs; 
  2476. {               
  2477.      int ac2,                       /* I/O parameter address block */
  2478.          err,                       /* Error from sys_read */
  2479.          irlr;                      /* Number of bytes read */
  2480.      int rbe;                       /* Ring buffer empty on ESGT read */
  2481.  
  2482.      if (filenum == ttyfd) {
  2483.           x_io_parms.ibad = chs;
  2484.           x_io_parms.ircl = len;
  2485.           ac2 = (P_NIO_EX *) &x_io_parms;
  2486.           err = sys_read(ac2);
  2487.           irlr = x_io_parms.irlr;
  2488.           if (err == 0) {
  2489.               return(irlr);
  2490.           }
  2491.           rbe = (x_io_parms.etsp == 0) ? 0 : (x_io_scrn.esfc & $ESBE);
  2492.      } else {
  2493.           r_io_parms.ich  = channel(filenum); 
  2494.           r_io_parms.ibad = chs;
  2495.           r_io_parms.ircl = len;
  2496.           ac2 = (P_NIO_EX *) &r_io_parms;
  2497.           err = sys_read(ac2);
  2498.           irlr = r_io_parms.irlr;
  2499.           if (err == 0) {
  2500.               return(irlr);
  2501.           }
  2502.           rbe = (r_io_parms.etsp == 0) ? 0 : (r_io_scrn.esfc & $ESBE);
  2503.      }
  2504.  
  2505.      if ((err != ERLTL) && (err != ERDTO) && (err != EREOF)) {
  2506.           /* NOT line-too-long, timeout, or EOF errors.
  2507.            * Don't print error when it is a data overrun.
  2508.            */
  2509.           if (err != EROVR) perror("dgncinb: sys_read error");
  2510.           return(-err);
  2511.      } else {
  2512.           /* If the system read buffer was empty when a screen management
  2513.           * packet was supplied, then there is a virtual EOF condition.  
  2514.           * So we return an EOF flag in that case (rbe != 0).
  2515.           */
  2516.           if ((err == EREOF) || rbe) return(-1);            /* EOF */
  2517.           if (err == ERDTO) 
  2518.               if (irlr <= 0)                            /* if no data, */ 
  2519.                   return (-2);                          /* return -2 */
  2520.           return(irlr);                                 /* else chars read */
  2521.      }
  2522. }
  2523. #endif datageneral
  2524.  
  2525. /*  C O N I N C  --  Get a character from the console  */
  2526.  
  2527. coninc(timo) int timo; {
  2528.     int n = 0; char ch;
  2529.  
  2530.     if (timo <= 0) {            /* no timeout specified */
  2531.       while (1) {
  2532.         /* Binary input */
  2533.         n = dgncinb(0,&ch,1);
  2534.         if (n == 0) continue;
  2535.         if (n > 0)
  2536.             return(ch & 0377);                 /* Return the char if read */
  2537.         else {
  2538.             if (lasterror() == EINTR)
  2539.               if (conesc)  {            /* If by SIGQUIT, */
  2540.                  conesc = 0;            /* the conesc variable is set, */
  2541.                  return(escchr);        /* so return the escape character. */
  2542.               } else continue;           /* By other signal, try again. */
  2543.             else if (n == -2) {            /* won't happen unless ?STOM */
  2544.                 debug(F101,"coninc got timeout ","",n);   /* has happened */
  2545.                 continue;
  2546.             } else if (n == -1)                         /* behind our back */
  2547.                 debug(F101,"coninc got eof indication","",n);
  2548.             else if (n < -2)            /* -n = VS error code */
  2549.                 debug(F101,"coninc got AOS/VS error","",-n);
  2550.             return(-1);
  2551.         }
  2552.       }
  2553.     }
  2554.     saval = signal(SIGALRM,timerh);     /* else timeout specified */
  2555.     alarm(timo);
  2556.     if (setjmp(sjbuf)) n = -2;
  2557.     else 
  2558.         n = dgncinb(0, &ch, 1);
  2559.     ttimoff();                          /* Turn off timer */
  2560.     if (n > 0) return(ch & 0377);
  2561.     else {
  2562.         debug(F101, "coninc(timo) n","",n);
  2563.         debug(F101, "coninc(timo) errno","",lasterror());
  2564.         if ((lasterror() == EINTR) && conesc != 0) {
  2565.             conesc = 0;
  2566.             return(escchr);             /* User entered escape character. */
  2567.         } else if (n == -2)                        /* won't happen */
  2568.             debug(F101, "coninc got DEVICE timeout","",n);
  2569.         else if (n == -1)
  2570.             debug(F101,"coninc got eof indication","",n);
  2571.         else if (n < -2)                    /* -n = VS error code */
  2572.             debug(F101,"coninc got AOS/VS error","",-n);
  2573.         return(-1); 
  2574.         }
  2575.  
  2576.                 
  2577. }
  2578.  
  2579. /*  C O N G K S  --  Console Get Keyboard Scancode  */
  2580.  
  2581. #ifndef congks
  2582. /*
  2583.   This function needs to be filled in with the various system-dependent
  2584.   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
  2585.   keyboard scan code.  For now, it's a dummy.
  2586. */
  2587. int
  2588. congks(timo) int timo; {
  2589.     return(coninc(timo));
  2590. }
  2591. #endif /* congks */
  2592.  
  2593.  
  2594. /* These security routines are here, but they're not used.  There's no */
  2595. /* need for them in the AOS/VS implementation.  When they were here,   */
  2596. /* they caused superuser to be turned off when kermit was started with */
  2597. /* it on.  Seemed to cause problems instead of solve them.       --ENH */
  2598.  
  2599. int
  2600. priv_ini()                                  /* if superu is on, turn off    */
  2601. {
  2602.     int     ac0,ac1,ac2,error;
  2603.  
  2604.     ac0 = ac1 = ac2 = 0;
  2605.  
  2606.     error = sys( $SUSER, &ac0, &ac1, &ac2 );
  2607.     if( ac0 == -1 )                         /* if it's on...                */
  2608.         priv_off();                         /* turn it off                  */
  2609.  
  2610.     return  0;
  2611. }
  2612.  
  2613. int
  2614. priv_on()                                   /* turn superu on               */
  2615. {
  2616.     int     ac0,ac1,ac2,error;
  2617.  
  2618.     ac0 = -1;                               /* turn it on                   */
  2619.     ac1 = ac2 = 0;
  2620.  
  2621.     error = sys( $SUSER, &ac0, &ac1, &ac2 );
  2622.     if( error != NULL )
  2623.         error = -1;                         /* an error                     */
  2624.  
  2625.     return  error;
  2626. }
  2627.  
  2628. int
  2629. priv_off()
  2630. {
  2631.     int     ac0,ac1,ac2;
  2632.  
  2633.     ac0 = 1;                                /* turn it off                  */
  2634.     ac1 = ac2 = 0;
  2635.  
  2636.     return  sys( $SUSER, &ac0, &ac1, &ac2 );
  2637. }
  2638.  
  2639. int
  2640. priv_can()
  2641. {
  2642.     return  priv_off();
  2643. }
  2644.  
  2645. int
  2646. priv_chk()
  2647. {
  2648.     return  priv_off();
  2649. }
  2650.  
  2651. VOID
  2652. ttimoff() {                           /* Turn off any timer interrupts */
  2653.     alarm(0);
  2654.     if (saval)
  2655.       signal(SIGALRM,saval);
  2656.     else
  2657.       signal(SIGALRM,SIG_DFL);
  2658.     saval = NULL;
  2659. }
  2660.  
  2661. /* Similarly, this ctrlc_chk() routine is here, but it's not used. */
  2662.  
  2663. void
  2664. ctrlc_chk(buffer,n) int *buffer; int n; {
  2665. #nolist
  2666. #include <ckcker.h>
  2667. #list
  2668.     extern int local,what;
  2669.     int i;
  2670.     extern SIGTYP trap();
  2671.  
  2672.     debug(F101,"Entering ctrlc_chk -- number of chars in buf","",n);
  2673.     debug(F101,"ctrlc_chk local =","",local);
  2674.     debug(F101,"ctrlc_chk what =","",what);
  2675.     if (what == W_CONNECT)                  /* ignore ^C's in connect mode */
  2676.         return;
  2677.     if (what == W_NOTHING)                  /* don't know what's what here */
  2678.         return;                             /* so ignore ^C in case data   */
  2679.     if ((!local) &&
  2680.         ((what == W_SEND) || (what == W_RECV) || (what == W_REMO)))
  2681.         return;
  2682.     for (i = 0; i < n; i++)                 /* otherwise it's W_SEND, W_RECV */
  2683.                                             /* or W_REMOTE in local mode or  */
  2684.                                             /* W_COMMAND in either mode      */
  2685.         if ((buffer[i] & 0177) == CTRLC) {
  2686.             debug (F101,"Got ^C...","",what);
  2687.             my_count = 0;                   /* clear out buffer */
  2688.             trap(what);                     /* call signal handler */
  2689.         }
  2690. }
  2691.