home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckdtio.c < prev    next >
C/C++ Source or Header  |  1994-08-24  |  97KB  |  2,698 lines

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