home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckl196.zip / ckltio.c < prev    next >
C/C++ Source or Header  |  1999-12-05  |  92KB  |  3,245 lines

  1. #include "ckcsym.h"     /* emulate most compilers -DSYMBOL feature */
  2.  
  3. char *ckxv = "Stratus VOS Communications support 6.1.007, 15 January 1998";
  4.  
  5. /*  C K L T I O  */
  6.  
  7. /* C-Kermit interrupt, terminal control & i/o functions for STRATUS VOS */
  8.  
  9. /*
  10.   Author: Frank da Cruz (fdc@columbia.edu),
  11.   The Kermit Project, Columbia University
  12.   Adapted to Stratus VOS by David R. Lane, SoftCom Systems, Inc., Nov 93.
  13.  
  14.   Copyright (C) 1985, 1999,
  15.     Trustees of Columbia University in the City of New York.
  16.     All rights reserved.  See the C-Kermit COPYING.TXT file or the 
  17.     copyright text in the ckcmai.c module for disclaimer and permissions.
  18. */
  19.  
  20. /* Includes */
  21.  
  22. #include "ckcdeb.h"            /* This moved to here. */
  23. #include <errno.h>            /* System error numbers */
  24. #include "ckcnet.h"            /* Symbols for network types. */
  25. #include <signal.h>                     /* Signals */
  26. #include <setjmp.h>
  27. #include <system_io_constants.h>
  28. #include <term_control_opcodes.h>
  29. #include <get_port_info.h>
  30. #include <terminal_info.h>
  31. #include <process_info_structures.h>
  32. #include <fcntl.h>
  33. #include <time.h>
  34. #include <terminal_modes.h>
  35. #include <error_codes.h>
  36.  
  37. /* In releases prior to 13, get_port_info is a struct tag.  In 13, it
  38.    becomes a typedef.  No, it's not in the SRB, it's just an incompatible
  39.    change in a system include file. (YECH!)  The cklmak.cm macro tries
  40.    to set this define on releases before 13.  YMMV, unfortunately.
  41. */
  42. #ifdef GET_PORT_INFO_IS_STRUCT
  43. typedef struct get_port_info get_port_info;
  44. #endif
  45.  
  46. typedef struct
  47. {
  48.   unsigned  filler  : 8;
  49.   unsigned  baud    : 8;
  50.   unsigned  stop    : 8;
  51.   unsigned  parity  : 8;
  52. } term_configure;
  53.  
  54. typedef struct
  55. {
  56.   short            version;
  57.   unsigned short    flags;
  58. } DATA_SET_STATUS_INFO;
  59.  
  60. #define DSSI_CLEAR_TO_SEND    0x8000
  61. #define DSSI_CARRIER_DETECT    0x4000
  62. #define DSSI_DATA_SET_READY    0x2000
  63.  
  64. /* We know these are set here.  MUST unset them before the definitions. */
  65. #define signal vsignal
  66. #define alarm valarm
  67. SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
  68. int valarm(int interval);
  69.  
  70. /* Maximum length for the name of a tty device */
  71.  
  72. #ifndef DEVNAMLEN
  73. #define DEVNAMLEN 66
  74. #endif
  75.  
  76. #ifdef    NETCONN
  77. #undef DEVNAMLEN
  78. #define DEVNAMLEN 132            /* longer field for host:service */
  79. #endif  /* NETCONN */
  80.  
  81. #include "ckuver.h"            /* Version herald */
  82. char *ckxsys = HERALD;
  83.  
  84. /*
  85.  Variables available to outside world:
  86.  
  87.    dftty  -- Pointer to default tty name string, like "/dev/tty".
  88.    dfloc  -- 0 if dftty is console, 1 if external line.
  89.    dfprty -- Default parity
  90.    dfflow -- Default flow control
  91.    ckxech -- Flag for who echoes console typein:
  92.      1 - The program (system echo is turned off)
  93.      0 - The system (or front end, or terminal).
  94.    functions that want to do their own echoing should check this flag
  95.    before doing so.
  96.  
  97.    backgrd -- Flag indicating program executing in background, such as
  98.         as a batch server. Used to ignore INT and QUIT signals.
  99.  
  100.    myttystr -- name of terminal tty
  101.  
  102.  Functions for assigned communication line (either external or console tty):
  103.  
  104.    sysinit()               -- System dependent program initialization
  105.    syscleanup()            -- System dependent program shutdown
  106.    ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
  107.    ttclos()                -- Close & reset the tty, releasing any access lock.
  108.    ttsspd(cps)             -- Set the transmission speed of the tty.
  109.    ttgspd()                -- Get (read) the the transmission speed of the tty.
  110.    ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
  111.    ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
  112.                                 or in DIALING or CONNECTED modem control state.
  113.    ttres()                 -- Restore original tty modes.
  114.    ttscarr(carrier)        -- Set carrier control mode, on/off/auto.
  115.    ttinl(dest,max,timo)    -- Timed read line from the tty.
  116.    ttinc(timo)             -- Timed read character from tty.
  117.    ttchk()                 -- See how many characters in tty input buffer.
  118.    ttxin(n,buf)            -- Read n characters from tty (untimed).
  119.    ttol(string,length)     -- Write a string to the tty.
  120.    ttoc(c)                 -- Write a character to the tty.
  121.    ttflui()                -- Flush tty input buffer.
  122.    ttsndb()                -- Send BREAK signal.
  123.    ttsndlb()               -- Send Long BREAK signal.
  124. */
  125.  
  126. /*
  127. Functions for console terminal:
  128.  
  129.    congm()   -- Get console terminal modes.
  130.    concb(esc) -- Put the console in single-character wakeup mode with no echo.
  131.    conbin(esc) -- Put the console in binary (raw) mode.
  132.    conres()  -- Restore the console to mode obtained by congm().
  133.    conoc(c)  -- Unbuffered output, one character to console.
  134.    conol(s)  -- Unbuffered output, null-terminated string to the console.
  135.    conola(s) -- Unbuffered output, array of strings to the console.
  136.    conxo(n,s) -- Unbuffered output, n characters to the console.
  137.    conchk()  -- Check if characters available at console.
  138.    coninc(timo)  -- Timed get a character from the console.
  139.    congks(timo)  -- Timed get keyboard scan code.
  140.    conint()  -- Enable terminal interrupts on the console if not background.
  141.    connoi()  -- Disable terminal interrupts on the console if not background.
  142.  
  143. Time functions
  144.  
  145.    msleep(m) -- Millisecond sleep
  146.    ztime(&s) -- Return pointer to date/time string
  147.    rtimer() --  Reset timer
  148.    gtimer()  -- Get elapsed time since last call to rtimer()
  149. */
  150.  
  151. /* Declarations */
  152.  
  153. /* dftty is the device name of the default device for file transfer */
  154. /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
  155.  
  156. #ifndef DFTTY
  157.     char *dftty = "(terminal_name)";
  158.     char *dfmdm = "none";
  159.     int dfloc = 0;
  160. #else
  161.     char *dftty = DFTTY;        /* Default location specified on */
  162.     char *dfmdm = "none";        /* command line. */
  163.     int dfloc = 0;                      /* controlling terminal name. */
  164. #endif /* DFTTY */
  165.  
  166.     int dfprty = 0;                     /* Default parity (0 = none) */
  167.     int ttprty = 0;                     /* The parity that is in use. */
  168.     int ttpflg = 0;            /* Parity not sensed yet. */
  169.     static int ttpmsk = 0377;        /* Parity stripping mask. */
  170.     int ttmdm = 0;                      /* Modem in use. */
  171.     int ttcarr = CAR_AUT;        /* Carrier handling mode. */
  172.     int dfflow = FLO_XONX;        /* Default is Xon/Xoff */
  173.     int backgrd = 0;                    /* Assume in foreground (no '&' ) */
  174.  
  175.     int fdflag = 0;            /* Flag for redirected stdio */
  176.     int ttfdflg = 0;            /* Open File descriptor was given */
  177.     int tvtflg = 0;            /* Flag that ttvt has been called */
  178.     long ttspeed = -1;            /* For saving speed */
  179.     long comspd = -1;            /* speed of console device */
  180.     int ttflow = -9;            /* For saving flow */
  181.     int ttld = -1;            /* Line discipline */
  182.  
  183. extern int ttnproto;            /* Defined in ckcnet.c */
  184. extern int ttnet;            /* Defined in ckcnet.c */
  185. extern int xfrcan, xfrchr, xfrnum;    /* Defined in ckcmai.c */
  186.  
  187. int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
  188.  
  189. /* Declarations of variables global within this module */
  190.  
  191. static time_t tcount;            /* Elapsed time counter */
  192. static SIGTYP (*saval)() = NULL;    /* For saving alarm() handler */
  193. static long vosbaud[] = {0, 50, 75, 110, 134, 150, 300, 600, 1200, 1800,
  194.     2400, 3600, 4800, 7200, 9600, 19200, 38400, 76800, 56000, 64000};
  195. #define NUMBAUDS    ((sizeof vosbaud) / (sizeof vosbaud[0]))
  196.  
  197. /*
  198.   BREAKNULS is defined for systems that simulate sending a BREAK signal
  199.   by sending a bunch of NUL characters at low speed.  This may be all we
  200.   can do, if we don't have support for TERM_SEND_BREAK.
  201. */
  202.  
  203. static char                /* A string of nulls */
  204. *brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  205.  
  206. static jmp_buf sjbuf;            /* Longjump buffers */
  207. static jmp_buf jjbuf;            /* Longjump buffers */
  208.  
  209. /* these are for CONNECT processing */
  210. static long eventids[2];    /* 0 is con, 1 is tty, same as src argument */
  211. static long eventcnts[2];
  212. static int no_wait = 0; 
  213.  
  214. static char cinbuff[256];
  215. static int  cincnt;
  216. static int  cinbp;
  217.  
  218. char myttystr[DEVNAMLEN+1];        /* name of console device */
  219.  
  220. /* static */                /* (Not static any more) */
  221. int ttyfd = -1;                /* TTY file descriptor */
  222.  
  223. int telnetfd = 0;            /* File descriptor is for telnet */
  224. int x25fd = 0;                /* File descriptor is for X.25 */
  225.  
  226. static int lkf = 0,                     /* Line lock flag */
  227.     cgmf = 0,                           /* Flag that console modes saved */
  228.     xlocal = 0,                         /* Flag for tty local or remote */
  229.     curcarr = 0;            /* Carrier mode: require/ignore. */
  230.  
  231. static int netconn = 0;            /* 1 if network connection active */
  232. static char escchr;                     /* Escape or attn character */
  233.  
  234. /* this is for our incredible ALARM hack.  it sucks wind, but it works. */
  235. /* if Stratus would add alarm() to the runtime, we wouldn't have to do this. */
  236. /* at least SIGALRM is defined, and kill() works... */
  237.  
  238. static time_t    deadline = 0;
  239. #define chkalrm() ((deadline) ? chkalarm () : 0)
  240. _PROTOTYP(chkalarm, (void));
  241.  
  242. /* these are various terminal info modes, when filled in */
  243.  
  244. static long
  245.     ttold, ttraw, tttvt, ttcur,
  246.     ccold, ccraw, cccbrk;
  247.  
  248. static int plines = 0;
  249.  
  250. static int conraw = 0;    /* is console in a raw mode?  0=no, 1=cb, 2=bin */
  251. static int ttyraw = 0;            /* ditto for the tty */
  252.  
  253. static int conesc = 0;                  /* set to 1 if esc char (^\) typed */
  254.  
  255. static char ttnmsv[DEVNAMLEN];        /* Copy of open path for tthang */
  256. static char ttnmful[DEVNAMLEN];        /* full path name of device     */
  257.  
  258. /* ANSI-style prototypes for internal functions. */
  259. /* Functions used outside this module are prototyped in ckcker.h. */
  260.  
  261. _PROTOTYP( VOID cancio, (void) );
  262.  
  263. _PROTOTYP( SIGTYP timerh, (int) );
  264. _PROTOTYP( SIGTYP cctrap, (int) );
  265. _PROTOTYP( SIGTYP esctrp, (int) );
  266.  
  267. _PROTOTYP( int do_open, (char *) );
  268. _PROTOTYP( VOID conbgt, (int) );
  269. #ifdef ACUCNTRL
  270. _PROTOTYP( VOID acucntrl, (char *, char *) );
  271. #endif /* ACUCNTRL */
  272. _PROTOTYP( int netwait, (int, int, long *, long *) );
  273. _PROTOTYP( int carrctl, (long *, int) );
  274. _PROTOTYP( static int conout, (char *, int) );
  275.  
  276. /* same as isatty, but uses port ids instead of file descriptors.
  277.  * file descriptors are an artifact of the c-runtime on VOS, so we use
  278.  * ports to get some reasonable performance.  open/close/read/write use
  279.  * file descriptors, and the s$ calls use ports.  The control operations
  280.  * involved in changing from binary to normal modes are not in the c 
  281.  * runtime (ioctl and its kin), so we need to use ports for that, and the
  282.  * c runtime loses its mind if you change the modes behind its back.
  283.  */
  284. _PROTOTYP( int vostty, (int) );
  285. _PROTOTYP( static char *connam, (void) ); /* roll our own ttyname() */
  286. _PROTOTYP( long congspd, (void) ); /* returns speed of console device */
  287.  
  288. /* prototypes for VOS calls */
  289.  
  290. _PROTOTYP( extern VOID s$attach_port, (CV(32) *port_name, 
  291.     CV(256)* path, short *hold, short *port_id, short *status) );
  292.  
  293. _PROTOTYP( extern VOID s$close, (short *port_id, short *status) );
  294.  
  295. _PROTOTYP( extern VOID s$control, (short *port_id, short *opcode,
  296.     VOID *control, short *status) );
  297.  
  298. _PROTOTYP( extern VOID s$detach_port, (short *port_id, short *status) );
  299.  
  300. _PROTOTYP( extern VOID s$get_data_set_status, (CV(66) *channel,
  301.     VOID *info, short *status) );
  302.  
  303. _PROTOTYP( extern VOID s$get_lockers, (CV(256) *path, short *maxlock,
  304.     short *nbrlock, long *pids, short *locktyp, short *status) );
  305.  
  306. _PROTOTYP (extern VOID s$get_port_info, (short *port,
  307.     get_port_info *pinfo, short *status) );
  308.  
  309. _PROTOTYP( extern VOID s$get_process_id, (long *process_id) );
  310.  
  311. _PROTOTYP( extern VOID s$get_process_info, (long *process_id, VOID *info,
  312.     short *status) );
  313.  
  314. _PROTOTYP( extern VOID s$expand_module_name, (CV(66) *src,
  315.     CV(66) *dest, short *status) );
  316.  
  317. _PROTOTYP( extern VOID s$get_home_dir, (CV(256) *path) );
  318.  
  319. _PROTOTYP( extern int s$is_file_type_a_terminal, (short *type) );
  320.  
  321. _PROTOTYP( extern void s$jiffy_date_time, (void *jiffy) );
  322.  
  323. _PROTOTYP( extern VOID s$open, (short *port_id, short *organization,
  324.     short *max_rec_len, short *io_type, short *locking_type,
  325.     short *access_mode, CV(32) *index_name, short *status) );
  326.  
  327. _PROTOTYP( extern VOID s$read_event, (long *event_id, long *event_count,
  328.     short *event_status, short *status) );
  329.  
  330. _PROTOTYP( extern VOID s$read_raw, (short *port_id, short *buff_size,
  331.     short *rec_len, VOID *buffer, short *status) );
  332.  
  333. _PROTOTYP( extern VOID s$seq_open, (CV(256) *port_id, short *io_type, 
  334.     short *port, short *status) );
  335.  
  336. _PROTOTYP( extern VOID s$seq_read, (short *port_id, short *buff_size,
  337.      short *rec_len, VOID *buffer, short *status) );
  338.  
  339. _PROTOTYP( extern VOID s$seq_write_partial, (short *port_id,
  340.      short *rec_len, VOID *buffer, short *status) );
  341.  
  342. _PROTOTYP( extern VOID s$set_io_time_limit, (short *port, long *timeout,
  343.     short *status) );
  344.  
  345. _PROTOTYP( extern VOID s$set_no_wait_mode, (short *port_id, long *event_id,
  346.     short *status) );
  347.  
  348. _PROTOTYP( extern VOID s$set_wait_mode, (short *port_id, short *status) );
  349.  
  350. _PROTOTYP( extern VOID s$sleep, (int *ticks, short *status) );
  351.  
  352. _PROTOTYP( extern VOID s$wait_event, (short *count, long *event_id_array,
  353.     long *event_count_array, long *timeout, short *which_event,
  354.     short *status) );
  355.  
  356. _PROTOTYP( extern VOID s$write_raw, (short *port_id, short *length,
  357.      void *buffer, short *status) );
  358.  
  359. #ifdef CK_ANSIC
  360. static char *
  361. xxlast(char *s, char c)
  362. #else
  363. static char *
  364. xxlast(s,c) char *s; char c;
  365. #endif /* CK_ANSIC */
  366. /* xxlast */ {        /*  Last occurrence of character c in string s. */
  367.     return(strrchr (s, c));
  368. }
  369.  
  370. /* Timeout handler for communication line input functions */
  371.  
  372. SIGTYP
  373. timerh(foo) int foo; {
  374.     ttimoff();
  375.     longjmp(sjbuf,1);
  376. }
  377.  
  378. /* Control-C trap for communication line input functions */
  379.  
  380. int cc_int;                /* Flag */
  381. SIGTYP (* occt)();            /* For saving old SIGINT handler */
  382.  
  383. SIGTYP
  384. cctrap(foo) int foo; {            /* Needs arg for ANSI C */
  385.   cc_int = 1;                /* signal() prototype. */
  386.   debug(F101,"cctrap arg","",foo);
  387.   SIGRETURN;
  388. }
  389.  
  390. /*  S Y S I N I T  --  System-dependent program initialization.  */
  391.  
  392. int
  393. sysinit() {
  394.     int x;
  395.     short conport = TERMINAL_PORT_ID;
  396.     short opcode = SET_PAUSE_LINES_OPCODE;
  397.     short status;
  398.     short lines = 0;
  399.  
  400.     strcpy (myttystr, connam());
  401.     dftty = myttystr;
  402.     strcpy (ttnmful, myttystr);
  403.  
  404.     conbgt(0);                /* See if we're in the background */
  405.     congm();                /* save console modes */
  406.  
  407. /* Initialize the setuid package. */
  408. /* Change to the user's real user and group id. */
  409. /* If this can't be done, don't run at all. */
  410.  
  411.     if (x = priv_ini()) {
  412.     if (x | 1) fprintf(stderr,"Fatal: setuid failure.\n");
  413.     if (x | 2) fprintf(stderr,"Fatal: setgid failure.\n");
  414.     if (x | 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
  415.     exit(1);
  416.     }
  417.  
  418.     if (!backgrd && vostty(conport)) {    /* only if at terminal */
  419.     s$control (&conport, &opcode, &lines, &status);
  420.     }
  421.  
  422.     return(0);
  423. }
  424.  
  425. /*  S Y S C L E A N U P  --  System-dependent program cleanup.  */
  426.  
  427. int
  428. syscleanup() {
  429.     short conport = TERMINAL_PORT_ID;
  430.     short opcode = SET_PAUSE_LINES_OPCODE;
  431.     short status;
  432.     short lines = plines;
  433.  
  434.     /* No need to call anything in the suid package here, right? */
  435.  
  436.     if (!backgrd && vostty(conport)) {    /* only if at terminal */
  437.     s$control (&conport, &opcode, &lines, &status);
  438.     }
  439.  
  440.     return(0);
  441. }
  442.  
  443. /*  T T O P E N  --  Open a tty for exclusive access.  */
  444.  
  445. /*
  446.   Call with:
  447.     ttname: character string - device name or network host name.
  448.     lcl:
  449.   If called with lcl < 0, sets value of lcl as follows:
  450.   0: the terminal named by ttname is the job's controlling terminal.
  451.   1: the terminal named by ttname is not the job's controlling terminal.
  452.   But watch out: if a line is already open, or if requested line can't
  453.   be opened, then lcl remains (and is returned as) -1.
  454.     modem:
  455.   Less than zero: ttname is a network host name.
  456.   Zero or greater: ttname is a terminal device name.    
  457.   Zero means a local connection (don't use modem signals).
  458.   Positive means use modem signals.  
  459.    timo:
  460.   0 = no timer.
  461.   nonzero = number of seconds to wait for open() to return before timing out.
  462.  
  463.   Returns:
  464.     0 on success
  465.    -5 if device is in use
  466.    -4 if access to device is denied
  467.    -3 if access to lock directory denied
  468.    -2 upon timeout waiting for device to open
  469.    -1 on other error
  470. */
  471. int
  472. ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
  473.  
  474.     char *x;
  475.     int  temp;
  476.  
  477.     char cname[DEVNAMLEN+4];
  478.  
  479.     debug(F111,"ttopen called ttname & timo",ttname,timo);
  480.     if (ttyfd > -1) {            /* if device already opened */
  481.     debug(F111,"ttopen ttyfd set, ttnmsv",ttnmsv,ttyfd);
  482.         if (strncmp(ttname,ttnmsv,DEVNAMLEN)) { /* are new & old names same? */
  483.         ttclos(ttyfd);        /* no, close old ttname, open new */
  484.         }
  485.         else                 /* else same, ignore this call, */
  486.         return(0);            /* and return. */
  487.     }
  488.  
  489.     chkalrm();
  490.  
  491.     /* we save the name we were called with, full name goes elsewhere */
  492.     strcpy(ttnmsv,ttname);
  493.  
  494. #ifdef    NETCONN
  495.     if (modem < 0) {            /* modem < 0 = special code for net */
  496.     int x;
  497.     ttmdm = modem;
  498.     modem = -modem;            /* Positive network type number */
  499.     ttnet = modem;            /* save this */
  500.     fdflag = 0;            /* Stdio not redirected. */
  501.     netconn = 1;            /* And it's a network connection */
  502.     debug(F111,"ttopen net",ttname,modem);
  503. #ifdef NAMEFD
  504.     for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
  505.      if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
  506.         ttyfd = atoi(ttname);    /* Is there a way to test it's open? */
  507.         ttfdflg = 1;        /* We got an open file descriptor */
  508.         debug(F111,"ttopen got open network fd",ttname,ttyfd);
  509.         x = 1;            /* Return code is "good". */
  510.         if (telnetfd) {
  511.         ttnet = NET_TCPB;
  512.         ttnproto = NP_TELNET;
  513. #ifdef STRATUSX25
  514.         } else if (x25fd) {
  515.         ttnet = NET_VX25;
  516.         ttnproto = NP_NONE;
  517. #endif /* STRATUSX25 */
  518.         }
  519.     } else {            /* Host name or address given */
  520. #endif /* NAMEFD */
  521.         x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
  522.         if (x > -1) {
  523.         strncpy(ttnmsv,ttname,DEVNAMLEN);
  524.         } else netconn = 0;
  525. #ifdef NAMEFD
  526.     }
  527. #endif /* NAMEFD */
  528.  
  529.         chkalrm();
  530.  
  531.     xlocal = *lcl = 1;        /* Network connections are local. */
  532.     debug(F101,"ttopen net x","",x);
  533.  
  534. #ifdef TCPSOCKET
  535.     if (x > -1 && ttnet == NET_TCPB)
  536.       x = tn_ini();            /* Initialize TELNET protocol */
  537. #endif /* TCPSOCKET */
  538.     return(x);
  539.     } else {                /* Terminal device */
  540. #endif    /* NETCONN */
  541.  
  542. #ifdef NAMEFD
  543. /*
  544.   This code lets you give Kermit an open file descriptor for a serial
  545.   communication device, rather than a device name.  Kermit assumes that the
  546.   line is already open, locked, conditioned with the right parameters, etc.
  547. */
  548.     for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
  549.     if (*p == '\0') {
  550.         ttyfd = atoi(ttname);    /* Is there a way to test it's open? */
  551.         debug(F111,"ttopen got open fd",ttname,ttyfd);
  552.         strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
  553.         xlocal = *lcl = 1;        /* Assume it's local. */
  554.         netconn = 0;        /* Assume it's not a network. */
  555.         tvtflg = 0;            /* Might need to initialize modes. */
  556.         ttmdm = modem;        /* Remember modem type. */
  557.         fdflag = 0;            /* Stdio not redirected. */
  558.         ttfdflg = 1;        /* Flag we were opened this way. */
  559.  
  560.         return(0);            /* Return success */
  561.     }
  562. #endif /* NAMEFD */
  563. #ifdef NETCONN
  564.     }
  565. #endif /* NETCONN */
  566.  
  567. /* Here we have to open a serial device of the given name. */
  568.  
  569.     occt = signal(SIGINT, cctrap);    /* Set Control-C trap, save old one */
  570.  
  571.     tvtflg = 0;            /* Flag for use by ttvt(). */
  572.                 /* 0 = ttvt not called yet for this device */
  573.  
  574.     ttmdm = modem;                      /* Make this available to other fns */
  575.     xlocal = *lcl;                      /* Make this available to other fns */
  576.  
  577.     /* do_open need only handle TERMINAL/PRINTER/MODEM ports */
  578.  
  579.     if (0 > (temp = do_open(ttname))) {
  580.         debug(F111,"  do_open returned error",ttname,temp);
  581.         return(temp);
  582.     }
  583.  
  584.     chkalrm();
  585.  
  586.     /* Make sure it's a real tty. */
  587.     if (!vostty(ttyfd)) {
  588.     short ttyport = ttyfd;
  589.     short status;
  590.  
  591.     fprintf(stderr,"%s is not a tty!\n",ttname);
  592.     debug(F110,"ttopen not a tty",ttname,0);
  593.     s$close (&ttyport, &status);
  594.     s$detach_port (&ttyport, &status);
  595.     ttyfd = -1;
  596.     signal(SIGINT,occt);
  597.     return(-1);
  598.     }
  599.  
  600.     if (*lcl != 0) *lcl = xlocal;
  601.  
  602.     strcpy(cname,connam());
  603.     if (*lcl == -1) {
  604.     if (strcmp(cname, ttname) == 0) /* this is the controlling terminal */
  605.         *lcl = 0; /* that means remote mode */
  606.     else if (strcmp("(terminal_name)", ttname) == 0)
  607.         *lcl = 0;
  608.     else
  609.         *lcl = 1;
  610.     }
  611.  
  612.     /* Get current speed */
  613.  
  614.     ttspeed = ttgspd();
  615.     debug(F101,"ttopen ttspeed","",ttspeed);
  616.  
  617.     msleep (250);            /* give it a little bit */
  618.  
  619. #ifdef COMMENT
  620.     /* the modes have not been set yet, so don't do this */
  621.     ttflui ();                /* get rid of noise in tty buffer */
  622. #endif    
  623.  
  624.     /* Done, make entries in debug log, restore Ctrl-C trap, and return. */
  625.     debug(F101,"ttopen, ttyfd","",ttyfd);
  626.     debug(F101,"        lcl","",*lcl);
  627.     if (*lcl != -1)
  628.     xlocal = *lcl;
  629.     signal(SIGINT,occt);
  630.     chkalrm();
  631.     return(0);
  632. }
  633.  
  634.  
  635. /*  D O _ O P E N  --  Actually do an open for the tty. */
  636.  
  637. int
  638. do_open(ttname) char *ttname; {
  639.     CV(66) ttncv;
  640.     CV(66) expnam;
  641.     CV(32) portnam;
  642.     CV(32) index;
  643.     char buf[300];
  644.     short ttyport;
  645.     short status;
  646.     short lock;
  647.     short hold;
  648.     short io_type;
  649.     short access;
  650.     short reclen;
  651.     short org;
  652.     short opcode;
  653.     short maxlock;
  654.     short nbrlock;
  655.     long  pids[1];    /* one is enough */
  656.     TERMINAL_INFO tinfo;
  657.  
  658.     ttyfd = -1;
  659.  
  660.     if (0 == strcmp (ttname, "(terminal_name)"))
  661.     ttname = myttystr;
  662.  
  663.     if (strcmp (myttystr, ttname)) { /* not console */
  664.     strcpy (&ttncv, ttname);
  665.     s$expand_module_name (&ttncv, &expnam, &status);
  666.     debug(F111,"do_open s$expand_module_name status",ttname,status);
  667.     if (status)
  668.         return -1;
  669.  
  670.     strcpy (ttnmful, &expnam);    /* save this for later */
  671.     maxlock = 0;
  672.     nbrlock = 0;
  673.     pids[0] = 0;
  674.     lock = ANY_LOCK;
  675.     s$get_lockers ((CV(256) *) &expnam, &maxlock, &nbrlock,
  676.         pids, &lock, &status);
  677.  
  678.     if (status) {
  679.         debug(F111,"do_open s$get_lockers status",ttnmful,status);
  680.         return -1;        /* an error occurred */
  681.     }
  682.  
  683.     if (nbrlock) {
  684.         debug(F111,"do_open s$lockers in use",ttnmful,nbrlock);
  685.         return -5;        /* device is in use */
  686.         }
  687.  
  688.     strcpy (&portnam, "kermtty");
  689.     hold = DONT_HOLD;
  690.     s$attach_port (&portnam, (CV(256) *) &expnam,
  691.         &hold, &ttyport, &status);
  692.     if (status) {
  693.         debug(F111,"do_open s$attach_port status",ttnmful,status);
  694.         return -1;
  695.     }
  696.  
  697.     io_type = UPDATE_TYPE;
  698.     lock = IMPLICIT_LOCKING;
  699.     reclen = 2048;
  700.     access = SEQUENTIAL_MODE;
  701.     org = SEQUENTIAL_FILE;
  702.     strcpy (&index, "");
  703.     s$open (&ttyport, &org, &reclen, &io_type, &lock,
  704.          &access, &index, &status);
  705.     if (status) {
  706.         debug(F111,"do_open s$attach_port status",ttnmful,status);
  707.         s$detach_port(&ttyport, &status);    /* make sure it's detached */
  708.         return -1;
  709.     }
  710.  
  711.     ttyfd = ttyport;
  712.     }
  713.     else {
  714.     ttyfd = TERMINAL_PORT_ID;
  715.     }
  716.  
  717.     if (ttyfd == -1)
  718.     return(-1);
  719.  
  720.     debug(F100,"do_open getting modes","",0); /* Need to do it. */
  721.  
  722.     ttyport = ttyfd; /* make sure it is set here. */
  723.     opcode = GET_INFO_OPCODE;
  724.     tinfo.version = TERMINAL_INFO_VERSION_2;
  725.     s$control (&ttyport, &opcode, &tinfo, &status);
  726.     if (status) {
  727.     debug(F111,"do_open s$control get_info status",ttnmful,status);
  728.     s$close (&ttyport, &status);
  729.     s$detach_port (&ttyport, &status);
  730.     ttyfd = -1;
  731.     return -1;
  732.     }
  733.  
  734.     ttold = tinfo.modes;
  735.     ttcur = tinfo.modes;
  736.     ttraw = tinfo.modes;
  737.  
  738.     ttraw &= ~(OS_FUNCTION_KEY_INPUT | OS_BREAK_TABLE_RECORD
  739.     | OS_GENERIC_INPUT | OS_FORMS_INPUT);
  740.     ttraw |= OS_RAW_INPUT | OS_BULK_RAW_INPUT;
  741.  
  742.     tttvt = ttraw;
  743.  
  744.     debug(F111,"do_open return success, fd",ttnmful,ttyfd);
  745.  
  746.     return(0);
  747. }
  748.  
  749. /*  T T C L O S  --  Close the TTY, releasing any lock.  */
  750.  
  751. int
  752. ttclos(foo) int foo; {
  753.     short status;
  754.     short ttyport;
  755.  
  756.     debug(F110,"ttclos called",ttnmsv,0);
  757.     strcpy (ttnmsv, ""); /* nothing opened right now */
  758.     chkalrm();
  759.  
  760. #ifdef NETCONN
  761.     if (netconn)
  762.     return netclos();
  763. #endif
  764.  
  765.     ttyport = ttyfd;
  766.     ttyfd = -1;                    /* wipe it out here */
  767.  
  768.     /* don't close the console.  That would be bad. */
  769.  
  770.     if (ttyport >= 0 && ttyport != TERMINAL_PORT_ID) {
  771.     s$close (&ttyport, &status);
  772.     if (status) {
  773.         debug(F101,"ttclos s$close status","",status);
  774.         return (-1);
  775.     }
  776.     s$detach_port (&ttyport, &status);
  777.     if (status) {
  778.         debug(F101,"ttclos s$detach_port status","",status);
  779.         return (-1);
  780.     }
  781.     }
  782.  
  783.     chkalrm();
  784.     return(0);
  785. }
  786.  
  787. /*  T T H A N G  --  Hangup phone line or network connection.  */
  788. /*
  789.   Returns:
  790.   0 if it does nothing.
  791.   1 if it believes that it hung up successfully.
  792.  -1 if it believes that the hangup attempt failed.
  793. */
  794.  
  795. #define HUPTIME 500            /* Milliseconds for hangup */
  796.  
  797. int
  798. tthang() {
  799.     short ttyport;
  800.     short status;
  801.     short opcode;
  802.     short dummy;
  803.     char  oldtty[DEVNAMLEN+1];
  804.     int   rv;   /* return value */
  805.     long  oldspeed;
  806.     int   oldflow;
  807.  
  808.     if (ttyfd < 0)
  809.     return 0;     /* no action taken */
  810.  
  811.     chkalrm();
  812.  
  813. #ifdef NETCONN
  814.     if (netconn)
  815.         return((netclos() < 0) ? -1 : 1);    /* Just close it. */
  816. #endif
  817.  
  818.     ttyport = ttyfd;
  819.     if (ttyport == TERMINAL_PORT_ID)
  820.     return 0;    /* don't hang up console */
  821.  
  822.     if (ttfdflg) return(0);        /* Don't mess with terminal if */
  823.                     /* we got ttyfd from another process */
  824.  
  825.     opcode = ASYNC_HANGUP_OPCODE;
  826.     dummy = 0;
  827.     s$control (&ttyport, &opcode, &dummy, &status);
  828.     if (status) {
  829.     debug(F111,"tthang s$control ASYNC_HANGUP status",ttnmful,status);
  830.     return -1;
  831.     }
  832.  
  833.     msleep(HUPTIME);
  834.  
  835.     chkalrm();
  836.     rv = 1;
  837.  
  838. #ifdef CLSOPN
  839. /*
  840.  * This may be needed to re-arm the async port.
  841.  * This will REALLY hammer a vterm connection, though.
  842.  */
  843.     strcpy (oldtty, ttnmsv);
  844.     debug(F111,"tthang CLSOPN xlocal",oldtty,xlocal);
  845.     oldspeed = ttspeed;
  846.     oldflow = ttflow;
  847.     ttclos ();
  848.     sleep (2);    /* wait a little bit, to let modem figure it out */
  849.     rv = ttopen (oldtty, &xlocal, ttmdm, 5);
  850.     if (!rv)
  851.     rv = ttvt(oldspeed,oldflow);
  852. #endif
  853.  
  854.     return rv;        /* success */
  855. }
  856.  
  857. /*  T T R E S  --  Restore terminal to "normal" mode.  */
  858.  
  859. /* ske@pkmab.se: There are two choices for what this function should do.
  860.  * (1) Restore the tty to current "normal" mode, with carrier treatment
  861.  * according to ttcarr, to be used after every kermit command. (2) Restore
  862.  * the tty to the state it was in before kermit opened it. These choices
  863.  * conflict, since ttold can't hold both choices of tty parameters.  ttres()
  864.  * is currently being called as in choice (1), but ttold basically holds
  865.  * the initial parameters, as in (2), and the description at the beginning
  866.  * of this file says (2).
  867.  *
  868.  * I don't think restoring tty parameters after all kermit commands makes
  869.  * much of a difference.  Restoring them upon exit from kermit may be of
  870.  * some use in some cases (when the line is not restored automatically on
  871.  * close, by the operating system).
  872.  *
  873.  * I can't choose which one it should be, so I haven't changed it. It
  874.  * probably works as it is, too. It would probably even work even with
  875.  * ttres() entirely deleted...
  876.  *
  877.  * (from fdc: Actually, this function operates in remote mode too, so
  878.  * it restores the console (command) terminal to whatever mode it was
  879.  * in before packet operations began, so that commands work right again.)
  880.  */
  881. int
  882. ttres() {                               /* Restore the tty to normal. */
  883.     short ttyport;
  884.     short opcode;
  885.     short status;
  886.  
  887.     chkalrm();
  888.     if (ttyfd < 0) return(-1);          /* Not open. */
  889.  
  890.     if (ttfdflg) return(0);        /* Don't mess with terminal modes if */
  891.                     /* we got ttyfd from another process */
  892. #ifdef    NETCONN
  893.     if (netconn) return (0);        /* Network connection, do nothing */
  894. #endif    /* NETCONN */
  895.  
  896.     tvtflg = 0;                /* Invalidate terminal mode settings */
  897.  
  898.     ttyport = ttyfd;
  899.     opcode = SET_MODES_OPCODE;
  900.     s$control (&ttyport, &opcode, &ttold, &status);
  901.     if (status) {
  902.     debug(F111,"ttres s$control SET_MODES status",ttnmful,status);
  903.     return -1;
  904.     }
  905.  
  906.     ttcur = ttold;
  907.     ttyraw = 0;
  908.     chkalrm();
  909.     return(0);
  910. }
  911.  
  912. /*
  913.   T T H F L O W  --  Set hardware flow control.
  914. */
  915. static int
  916. tthflow(flow) int flow; {
  917.     int x = 0;                /* Return code */
  918.     chkalrm();
  919.  
  920.     return(x);
  921. }
  922.  
  923. /*  T T P K T  --  Condition the communication line for packets */
  924. /*                 or for modem dialing */
  925.  
  926. /*
  927.   If called with speed > -1, also set the speed.
  928.   Returns 0 on success, -1 on failure.
  929.  
  930.   NOTE: the "xflow" parameter is supposed to be the currently selected
  931.   type of flow control, but for historical reasons, this parameter is also
  932.   used to indicate that we are dialing.  Therefore, when the true flow
  933.   control setting is needed, we access the external variable "flow", rather
  934.   than trusting our "xflow" argument.
  935. */
  936. int
  937. #ifdef CK_ANSIC
  938. ttpkt(long speed, int xflow, int parity)
  939. #else
  940. ttpkt(speed,xflow,parity) long speed; int xflow, parity;
  941. #endif /* CK_ANSIC */
  942. /* ttpkt */ {
  943.     int s2;
  944.     int s = -1;
  945.     int x;
  946.     short status;
  947.     short ttyport;
  948.     short opcode;
  949.     term_configure config;
  950.  
  951.     extern int flow;            /* REAL flow-control setting */
  952.  
  953.     chkalrm();
  954.     if (ttyfd < 0) return(-1);          /* Not open. */
  955.  
  956.     debug(F101,"ttpkt parity","",parity);
  957.     debug(F101,"ttpkt xflow","",xflow);
  958.     debug(F101,"ttpkt speed","",(int) speed);
  959.  
  960. #ifdef NETCONN
  961.     if (netconn) {
  962.     chkalrm();
  963.     tvtflg = 1;            /* Network connections */
  964.     return(0);            /* require no special setup */
  965.     }
  966. #endif /* NETCONN */
  967.  
  968.     tvtflg = 0;
  969.  
  970.     ttprty = parity;                    /* Let other tt functions see these. */
  971.     ttpflg = 0;                /* Parity not sensed yet */
  972.     ttpmsk = ttprty ? 0177 : 0377;    /* Parity stripping mask */
  973.     ttspeed = speed;            /* Make global copy for this module */
  974.  
  975.     if (ttfdflg && !vostty(ttyfd)) return(0);    /* Don't change if not a tty */
  976.  
  977.     ttyport = ttyfd;
  978.     opcode = SET_MODES_OPCODE;
  979.     s$control (&ttyport, &opcode, &ttraw, &status);
  980.     if (status) {
  981.     debug(F111,"ttpkt s$control SET_MODES status",ttnmful,status);
  982.     return -1;
  983.     }
  984.  
  985.     chkalrm();
  986.     ttyraw = 1;        /* remember it's in raw mode */
  987.     ttcur = ttraw;
  988.  
  989.     opcode = TERM_GET_CONFIG_OPCODE;
  990.     s$control (&ttyport, &opcode, &config, &status);
  991.     if (status) {
  992.     debug(F111,"ttpkt s$control TERM_GET_CONFIG status",ttnmful,status);
  993.     return -1;
  994.     }
  995.  
  996.     if (ttspeed > -1 && xlocal) {
  997.     switch (ttspeed) {
  998.         case 50:    config.baud = OS_BAUD_50;    break;
  999.         case 75:    config.baud = OS_BAUD_75;    break;
  1000.         case 110:    config.baud = OS_BAUD_110;    break;
  1001.         case 150:    config.baud = OS_BAUD_150;    break;
  1002.         case 300:    config.baud = OS_BAUD_300;    break;
  1003.         case 600:    config.baud = OS_BAUD_600;    break;
  1004.         case 1200:    config.baud = OS_BAUD_1200;    break;
  1005.         case 2400:    config.baud = OS_BAUD_2400;    break;
  1006.         case 3600:    config.baud = OS_BAUD_3600;    break;
  1007.         case 4800:    config.baud = OS_BAUD_4800;    break;
  1008.         case 7200:    config.baud = OS_BAUD_7200;    break;
  1009.         case 9600:    config.baud = OS_BAUD_9600;    break;
  1010.         case 19200:    config.baud = OS_BAUD_19200;    break;
  1011.         case 38400:    config.baud = OS_BAUD_38400;    break;
  1012.         default:                    break;
  1013.     }
  1014.     }
  1015.     switch (ttprty) {
  1016.     case 0:        config.parity = OS_NO_PARITY;    break;
  1017.     case 'e':    config.parity = OS_EVEN_PARITY; break;
  1018.     case 'o':    config.parity = OS_ODD_PARITY;    break;
  1019.     case 'm':    config.parity = OS_MARK_PARITY;    break;
  1020.     case 's':    config.parity = OS_SPACE_PARITY;break;
  1021.     default:                    break;
  1022.     }
  1023.  
  1024.     opcode = TERM_CONFIGURE_OPCODE;
  1025.     s$control (&ttyport, &opcode, &config, &status);
  1026.     if (status) {
  1027.     debug(F111,"ttpkt s$control TERM_CONFIGURE status",ttnmful,status);
  1028.     /* DON'T RETURN FAILURE!  window_term's can't do this! */
  1029.     }
  1030.  
  1031.     /* we don't mess with the flow control */ /**/
  1032.     chkalrm();
  1033.  
  1034.     return (0);
  1035. }
  1036.  
  1037. /*  T T V T -- Condition communication line for use as virtual terminal  */
  1038.  
  1039. int
  1040. #ifdef CK_ANSIC
  1041. ttvt(long speed, int flow)
  1042. #else
  1043. ttvt(speed,flow) long speed; int flow;
  1044. #endif /* CK_ANSIC */
  1045. /* ttvt */ {
  1046.     int s, s2;
  1047.     short status;
  1048.     short ttyport;
  1049.     short opcode;
  1050.     term_configure config;
  1051.  
  1052.     debug(F101,"ttvt ttyfd","",ttyfd);
  1053.     debug(F101,"ttvt tvtflg","",tvtflg);
  1054.     debug(F101,"ttvt speed","",speed);
  1055.     chkalrm();
  1056.     if (ttyfd < 0) return(-1);          /* Not open. */
  1057.  
  1058. #ifdef NETCONN
  1059.     if (netconn) {
  1060.     tvtflg = 1;            /* Network connections */
  1061.     debug(F101,"ttvt netconn","",netconn);
  1062.     return(0);            /* require no special setup */
  1063.     }
  1064. #endif /* NETCONN */
  1065.  
  1066.     if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr)
  1067.       return(0);            /* Already been called. */
  1068.  
  1069.     if (ttfdflg && !vostty(ttyfd)) return(0);
  1070.  
  1071.     ttspeed = speed;
  1072.     ttflow = flow;
  1073.  
  1074.     chkalrm();
  1075.     if (xlocal) {            /* For external lines... */
  1076.     s2 = (int) (speed / 10L);
  1077.     s = ttsspd(s2);            /* Check/set the speed */
  1078.     carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
  1079.         && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
  1080.     } else s = s2 = -1;
  1081.  
  1082.     ttyport = ttyfd;
  1083.     opcode = SET_MODES_OPCODE;
  1084.     s$control (&ttyport, &opcode, &ttraw, &status);
  1085.     if (status) {
  1086.     debug(F111,"ttvt s$control SET_MODES status",ttnmful,status);
  1087.     return -1;
  1088.     }
  1089.  
  1090.     ttyraw = 1;        /* remember it's in raw mode */
  1091.     ttcur = ttraw;
  1092.     chkalrm();
  1093.  
  1094.     opcode = TERM_GET_CONFIG_OPCODE;
  1095.     s$control (&ttyport, &opcode, &config, &status);
  1096.     if (status)  {
  1097.     debug(F111,"ttvt s$control TERM_GET_CONFIG status",ttnmful,status);
  1098.     return -1;
  1099.     }
  1100.  
  1101.     if (ttspeed > -1 && xlocal) {
  1102.     switch (ttspeed) {
  1103.         case 50:    config.baud = OS_BAUD_50;    break;
  1104.         case 75:    config.baud = OS_BAUD_75;    break;
  1105.         case 110:    config.baud = OS_BAUD_110;    break;
  1106.         case 150:    config.baud = OS_BAUD_150;    break;
  1107.         case 300:    config.baud = OS_BAUD_300;    break;
  1108.         case 600:    config.baud = OS_BAUD_600;    break;
  1109.         case 1200:    config.baud = OS_BAUD_1200;    break;
  1110.         case 2400:    config.baud = OS_BAUD_2400;    break;
  1111.         case 3600:    config.baud = OS_BAUD_3600;    break;
  1112.         case 4800:    config.baud = OS_BAUD_4800;    break;
  1113.         case 7200:    config.baud = OS_BAUD_7200;    break;
  1114.         case 9600:    config.baud = OS_BAUD_9600;    break;
  1115.         case 19200:    config.baud = OS_BAUD_19200;    break;
  1116.         case 38400:    config.baud = OS_BAUD_38400;    break;
  1117.         default:                    break;
  1118.     }
  1119.     }
  1120.     switch (ttprty) {
  1121.     case 0:        config.parity = OS_NO_PARITY;    break;
  1122.     case 'e':    config.parity = OS_EVEN_PARITY; break;
  1123.     case 'o':    config.parity = OS_ODD_PARITY;    break;
  1124.     case 'm':    config.parity = OS_MARK_PARITY;    break;
  1125.     case 's':    config.parity = OS_SPACE_PARITY;break;
  1126.     default:                    break;
  1127.     }
  1128.  
  1129.     opcode = TERM_CONFIGURE_OPCODE;
  1130.     s$control (&ttyport, &opcode, &config, &status);
  1131.     if (status) {
  1132.     debug(F111,"ttvt s$control TERM_CONFIGURE status",ttnmful,status);
  1133.     /* DON'T RETURN FAILURE!  window_term's can't do this! */
  1134.     }
  1135.  
  1136.     /* we don't mess with the flow control */ /**/
  1137.  
  1138.     chkalrm();
  1139.     tvtflg = 1;
  1140.     debug(F101,"ttvt done, setting flag","",tvtflg);
  1141.  
  1142.     return(0);
  1143. }
  1144.  
  1145. /*  T T S S P D  --  Checks and sets transmission rate.  */
  1146.  
  1147. /*  Call with speed in characters (not bits!) per second. */
  1148. /*  Returns internal speed code if successful, -1 otherwise. */
  1149.  
  1150. int
  1151. ttsspd(cps) int cps; {
  1152.     int s, s2;
  1153.     short ttyport;
  1154.     short status;
  1155.     short opcode;
  1156.     term_configure config;
  1157.  
  1158.     debug(F101,"ttsspd","",cps);
  1159.     chkalrm();
  1160.  
  1161. #ifdef NETCONN
  1162.     if (netconn) return (0);    
  1163. #endif /* NETCONN */
  1164.  
  1165.     if (cps < 0) return(-1);
  1166.     s = s2 = -1;
  1167.  
  1168.     /* First check that the given speed is valid. */
  1169.     switch (cps)  {
  1170.     case 5:        s = OS_BAUD_50;        break;
  1171.     case 7:        s = OS_BAUD_75;        break;
  1172.     case 11:    s = OS_BAUD_110;    break;
  1173.     case 15:    s = OS_BAUD_150;    break;
  1174.     case 30:    s = OS_BAUD_300;    break;
  1175.     case 60:    s = OS_BAUD_600;    break;
  1176.     case 120:    s = OS_BAUD_1200;    break;
  1177.     case 240:    s = OS_BAUD_2400;    break;
  1178.     case 360:    s = OS_BAUD_3600;    break;
  1179.     case 480:    s = OS_BAUD_4800;    break;
  1180.     case 720:    s = OS_BAUD_7200;    break;
  1181.     case 960:    s = OS_BAUD_9600;    break;
  1182.     case 1920:    s = OS_BAUD_19200;    break;
  1183.     case 3840:    s = OS_BAUD_38400;    break;
  1184.       default:
  1185.     debug(F111,"ttsspd","INVALID SPEED",cps);
  1186.     return(-1);
  1187.     }
  1188.     /* Actually set the speed */
  1189.  
  1190.     chkalrm();
  1191.     if (ttyfd > -1 && s > -1 && xlocal != 0) {
  1192.     if (s2 == -1) s2 = s;
  1193.     ttyport = ttyfd;
  1194.     opcode = TERM_GET_CONFIG_OPCODE;
  1195.     s$control (&ttyport, &opcode, &config, &status);
  1196.     if (status) {
  1197.         debug(F101,"ttsspd s$control get config status","",status);
  1198.         return (-1);
  1199.     }
  1200.     config.baud = s;
  1201.     opcode = TERM_CONFIGURE_OPCODE;
  1202.     s$control (&ttyport, &opcode, &config, &status);
  1203.     if (status) {
  1204.         debug(F101,"ttsspd s$control term configure status","",status);
  1205.         return (-1);
  1206.         }
  1207.     }
  1208.     else {
  1209.     debug(F101,"ttsspd ignoring request, xlocal","",xlocal);
  1210.     }
  1211.  
  1212.     ttspeed = cps * 10;
  1213.  
  1214.     chkalrm();
  1215.     return(1);
  1216. }
  1217.  
  1218. /* T T G S P D  -  Get speed of currently selected tty line  */
  1219.  
  1220. /*
  1221.    This isn't always 100% accurate.  Some types of devices lie a lot about
  1222.    their speed (VTERMs are the worst about this).  If in local mode, it
  1223.    should call congspd() to find out either what VOS thinks the speed is,
  1224.    which may or may not be right, or what the user said the speed is, say
  1225.    if you are using a PAD or front-end that lies about the speed.
  1226. */
  1227. long
  1228. ttgspd() {                /* Get current tty speed */
  1229.     int s; long ss;
  1230.     short ttyport;
  1231.     short opcode;
  1232.     short status;
  1233.     term_configure config;
  1234.  
  1235.     chkalrm();
  1236.  
  1237. #ifdef NETCONN
  1238.     if (netconn) return(-1);        /* -1 if network connection */
  1239. #endif /* NETCONN */
  1240.  
  1241.     if (ttyfd < 0) {
  1242.         return (-1);
  1243.     }
  1244.  
  1245.     if (ttyfd > -1 && xlocal != 0) {
  1246.     ttyport = ttyfd;
  1247.     opcode = TERM_GET_CONFIG_OPCODE;
  1248.     s$control (&ttyport, &opcode, &config, &status);
  1249.     if (status)  {
  1250.         debug(F111,"ttgspd s$control TERM_GET_CONFIG status",
  1251.         ttnmful,status);
  1252.         return -1;
  1253.     }
  1254.  
  1255.     if (config.baud < 0 || config.baud >= NUMBAUDS)
  1256.         ttspeed = 0;
  1257.     else
  1258.         ttspeed = vosbaud[config.baud];
  1259.     }
  1260.  
  1261.     chkalrm();
  1262.  
  1263.     debug(F101,"ttgspd speed","",ttspeed);
  1264.     return(ttspeed);
  1265. }
  1266.  
  1267. long
  1268. congspd() {                /* Get current console speed */
  1269.     int s; long ss;
  1270.     short conport;
  1271.     short opcode;
  1272.     short status;
  1273.     term_configure config;
  1274.  
  1275.     chkalrm();
  1276.  
  1277.     if (comspd > 0) {
  1278.     debug(F101,"congspd returning saved speed","",comspd);
  1279.     return (comspd);
  1280.     }
  1281.  
  1282.     conport = TERMINAL_PORT_ID;        /* always ask about TERMINAL */
  1283.     opcode = TERM_GET_CONFIG_OPCODE;
  1284.     s$control (&conport, &opcode, &config, &status);
  1285.     if (status) {
  1286.     debug(F111,"congspd s$control TERM_GET_CONFIG status",ttnmful,status);
  1287.     return -1;
  1288.     }
  1289.  
  1290.     if (config.baud < 0 || config.baud >= NUMBAUDS)
  1291.     comspd = 0;
  1292.     else
  1293.     comspd = vosbaud[config.baud];
  1294.  
  1295.     chkalrm();
  1296.  
  1297.     debug(F101,"congspd speed","",comspd);
  1298.     return(comspd);
  1299. }
  1300.  
  1301. /*
  1302.   New buffered input scheme.
  1303. */
  1304. #define TTXBUFL 1024            /* Internal buffer size */
  1305.  
  1306. CHAR     ttxbuf[TTXBUFL+1];        /* The buffer */
  1307. int     ttxbp = 0, ttxbn = 0;        /* Buffer pointer and count */
  1308.  
  1309. #ifdef NETCONN
  1310. _PROTOTYP(int netbufr, (int timo));
  1311. #endif
  1312. /*
  1313.   T X B U F R
  1314.  
  1315.   Read bytes from communication device into internal buffer ttxbuf[].
  1316.   To be called only when input buffer is empty, i.e. when ttxbn == 0.
  1317.  
  1318.   Other comm-device reading routines, like ttinc, ttinl, ttxin, should check
  1319.   the internal buffer first, and call this routine for a refill if necessary.
  1320.  
  1321.   When data is read successfully, the first character is returned and
  1322.   the global buffer count, ttxbn, is set to the number of characters remaining
  1323.   in ttxbuf after it, and the global buffer offset, ttxbp, is set to 1.
  1324.  
  1325.   ttxbp points to the first character which has not yet been read.  ttxbn is
  1326.   the number of buffered characters that have not yet been read.
  1327.  
  1328.   When data is not read successfully, -1 is returned indicating a timeout,
  1329.   or -2 indicating disconnection.
  1330. */
  1331. int
  1332. txbufr(timo) int timo; {        /* TT Buffer Read */
  1333.     short ttyport;
  1334.     short status;
  1335.     short status2;
  1336.     short buflen;
  1337.     short readlen;
  1338.     long  timeout;
  1339.  
  1340. #ifdef COMMENT
  1341.     debug(F101,"txbufr entry, timo","",timo);
  1342. #endif
  1343.     if (ttxbn > 0) {            /* Should not be called */
  1344.     debug(F101,"txbufr called with ttxbn","",ttxbn); /* if ttxbn > 0! */
  1345.     ttxbn--;
  1346.     return(ttxbuf[ttxbp++] & 0xff);
  1347.     }
  1348.     ttxbp = ttxbn = 0;            /* Reset buffer pointer and count */
  1349.  
  1350.     if (timo < 0)            /* Be safe */
  1351.       timo = 0;
  1352.  
  1353. #ifdef NETCONN
  1354.     if(netconn)     { /* pass it over to the network version */
  1355.     buflen = netbufr(timo);
  1356.         if (buflen > 0) { /* netbufr set up ttxb* variables with new data */
  1357.         ttxbn--; /* count the one we're sending back */
  1358.         return(ttxbuf[ttxbp++] & 0xff);
  1359.     }
  1360.     else if (buflen < 0) /* an error */
  1361.         return (buflen); /* pass it back to caller */
  1362.         else /* didn't get anything */
  1363.         return (-1); /* no data available */
  1364.     }
  1365. #endif
  1366.  
  1367.     ttyport = ttyfd;
  1368.  
  1369.     if (timo > 0) {
  1370.     timeout = timo;        /* not in seconds anymore! no conversion */
  1371.     s$set_io_time_limit (&ttyport, &timeout, &status);
  1372.     if (status)
  1373.         return (-2); /* disconnect */
  1374.     }
  1375.  
  1376.     buflen = TTXBUFL;            /* Maximum characters to read */
  1377.     s$read_raw (&ttyport, &buflen, &readlen, ttxbuf, &status);
  1378.  
  1379.     if (timo > 0) {
  1380.     timeout = -1; /* clear I/O time limit */
  1381.     s$set_io_time_limit (&ttyport, &timeout, &status2);
  1382.     if (status2)
  1383.         return (-2);
  1384.     }
  1385.  
  1386.     /* Check for disconnection */
  1387.     if (status == e$line_hangup || status == e$vc_disconnected) {
  1388.     debug(F100,"txbufr 1 hangup status","",status);
  1389.     return(-2);
  1390.     }
  1391.  
  1392.     /* check for some codes returned as errors, but with good data */
  1393.     if (readlen > 0 && 
  1394.     (status == e$caller_must_wait || status == e$short_record))
  1395.     status = 0;
  1396.  
  1397.     if (status == e$timeout || status == e$caller_must_wait) {
  1398. #ifdef COMMENT
  1399.     debug(F101, "txbufr returning timeout", "", 0);
  1400. #endif
  1401.     return(-1);
  1402.     }
  1403.  
  1404.     if (status != 0) {
  1405.     debug(F101,"txbufr ignoring error, status","",status);
  1406.     status = 0;
  1407.     }
  1408.  
  1409. #ifdef COMMENT
  1410.     debug(F101,"txbufr readlen","",readlen);
  1411. #endif
  1412.  
  1413. /*
  1414.  * Did anything useful happen?
  1415.  */
  1416.     if(readlen > 0) {
  1417.     ttxbn = readlen;        /* Set buffer count. */
  1418.     ttxbn--;            /* Less one for the one we return */
  1419.     return(ttxbuf[ttxbp++]);    /* Return it, bump offset */
  1420.     }
  1421.  
  1422. /*
  1423.  * We didn't get data, a timeout, or an error... This is weird.
  1424.  */
  1425.  
  1426.     return (-2); /* call it an error */
  1427. }
  1428. /* define a macro to get chars from the buffer */
  1429. /* ttxgetc has timo in seconds, txbufr has it in ticks */
  1430. #define ttxgetc(timo) (ttxbn ? (ttxbn--, ttxbuf[ttxbp++]) : txbufr(timo<<10))
  1431.  
  1432. /*  T T F L U I  --  Flush tty input buffer */
  1433.  
  1434. int
  1435. ttflui() {
  1436.     int n;
  1437.     /* do flush of tty input buffer */
  1438. /*
  1439.   Network flush is done specially, in the network support module.
  1440. */
  1441.     chkalrm();
  1442.     if (netconn)
  1443.     return(netflui());
  1444.  
  1445.     debug(F101,"ttflui ttyfd","",ttyfd);
  1446.     if (ttyfd < 0)
  1447.      return(-1);
  1448.  
  1449.     /* kill what's in the ttxbuf */
  1450.     if (ttxbn) {
  1451.     ttxbn = 0;
  1452.     ttxbp = 0;
  1453.     }
  1454.  
  1455.     txbufr(10); /* give it a miniscule timeout, .01 second */
  1456.  
  1457.     /* kill what's been added to the ttxbuf */
  1458.     if (ttxbn) {
  1459.     ttxbn = 0;
  1460.     ttxbp = 0;
  1461.     }
  1462.  
  1463.     if ((n = ttchk()) > 0) {
  1464.     debug(F101,"ttflui reading","",n);
  1465.     while ((n--) && ttinc(0) > 1) ;
  1466.     }
  1467.     return(0);
  1468. }
  1469.  
  1470. int
  1471. ttfluo() {                /* Flush output buffer */
  1472.     chkalrm();
  1473.     return(0);                /* (dummy for now) */
  1474. }
  1475.  
  1476. /* Interrupt Functions */
  1477.  
  1478. /* Set up terminal interrupts on console terminal */
  1479.  
  1480. #ifndef STRATUS
  1481. /* we don't have sigquit.  This was set pretty much the same as SIGINT. */
  1482. SIGTYP
  1483. esctrp(foo) int foo; {            /* trap console escapes (^\) */
  1484.     signal(SIGQUIT,SIG_IGN);            /* ignore until trapped */
  1485.     conesc = 1;
  1486.     debug(F101,"esctrp caught SIGQUIT","",conesc);
  1487. }
  1488. #endif
  1489.  
  1490. /*  C O N B G T  --  Background Test  */
  1491.  
  1492. /*
  1493.   Call with flag == 1 to prevent signal test, which can not be expected
  1494.   to work during file transfer, when SIGINT probably *is* set to SIG_IGN.  
  1495.  
  1496.   Call with flag == 0 to use the signal test, but only if the process-group
  1497.   test fails, as it does on some UNIX systems, where getpgrp() is buggy,
  1498.   requires an argument when the man page says it doesn't, or vice versa.
  1499.  
  1500.   If flag == 0 and the process-group test fails, then we determine background
  1501.   status simply (but not necessarily reliably) from isatty().
  1502.  
  1503.   conbgt() sets the global backgrd = 1 if we appear to be in the background,
  1504.   and to 0 if we seem to be in the foreground.  conbgt() is highly prone to
  1505.   misbehavior.
  1506.  
  1507.   On VOS, we check the process info block.  If interactive mode bit is
  1508.   not set, then we are in the background.  (Aren't OLTP OS's fun?) If we
  1509.   are in the forground, we still don't want to use a prompt if input has
  1510.   been redirected to a command macro or something, so we check vostty as
  1511.   well.  The "Signal test" doesn't work anywhere close to the same on
  1512.   VOS, so we don't use it.
  1513.  
  1514. */
  1515. VOID
  1516. conbgt(flag) int flag; {
  1517.     int x = -1,                /* process group or SIGINT test */
  1518.         y = 0;                /* vostty() test */
  1519.     PROCESS_INFO pinfo;
  1520.     long pid;
  1521.     short status;
  1522.  
  1523. /*
  1524.   Check for background operation, even if not running on real tty, so that
  1525.   background flag can be set correctly.  If background status is detected,
  1526.   then Kermit will not issue its interactive prompt or most messages.
  1527.   If your prompt goes away, you can blame (and fix?) this function.
  1528. */
  1529.  
  1530. /* Use process-type test if possible. */
  1531.  
  1532.     chkalrm();
  1533.     s$get_process_id (&pid);
  1534.     pinfo.version = PROCESS_INFO_VERSION;
  1535.     s$get_process_info (&pid, &pinfo, &status);
  1536.     if ((pinfo.info.flags & INTERACTIVE) == 0)
  1537.     backgrd = 1;
  1538.     else
  1539.     {
  1540.     if (vostty(TERMINAL_PORT_ID)) /* do we have a tty terminal port ? */
  1541.         backgrd = 0;
  1542.     else
  1543.         backgrd = 1;
  1544.     }
  1545.  
  1546.     debug(F101,"conbgt backgrd","",backgrd);
  1547. }
  1548.  
  1549. /*  C O N I N T  --  Console Interrupt setter  */
  1550.  
  1551. /*
  1552.   First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
  1553.   Second arg is pointer to function to handle SIGTSTP (suspend).
  1554. */
  1555.  
  1556. VOID                    /* Set terminal interrupt traps. */
  1557. #ifdef CK_ANSIC
  1558. conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
  1559. #else
  1560. conint(f,s) SIGTYP (*f)(), (*s)();
  1561. #endif /* CK_ANSIC */
  1562. /* conint */ {
  1563.  
  1564.     chkalrm();
  1565.     conbgt(0);                /* Do background test. */
  1566.  
  1567. /* Set the desired handlers for hangup and software termination. */
  1568.  
  1569.     signal(SIGTERM,f);                  /* Software termination */
  1570.  
  1571. /* Now handle keyboard stop, quit, and interrupt signals. */
  1572. /* Check if invoked in background -- if so signals set to be ignored. */
  1573. /* However, if running under a job control shell, don't ignore them. */
  1574. /* We won't be getting any, as we aren't in the terminal's process group. */
  1575.  
  1576.     debug(F101,"conint backgrd","",backgrd);
  1577.  
  1578.     if (backgrd) {        /* In background, ignore signals */
  1579.     debug(F101,"conint background ignoring signals","",0);
  1580.  
  1581.         signal(SIGINT,SIG_IGN);         /* Keyboard interrupt */
  1582.     } else {                /* Else in foreground or suspended */
  1583.     debug(F101,"conint foreground catching signals, jc","",0);
  1584.         signal(SIGINT,f);               /* Catch terminal interrupt */
  1585.         if (conesc) conesc = 0;         /* Clear out pending escapes */
  1586.     }
  1587.     chkalrm();
  1588. }
  1589.  
  1590. /*  C O N N O I  --  Reset console terminal interrupts */
  1591.  
  1592. SIGTYP                    /* Dummy function to ignore signals */
  1593. #ifdef CK_ANSIC
  1594. sig_ign(int foo)
  1595. #else
  1596. sig_ign(foo) int foo;
  1597. #endif /* CK_ANSIC */
  1598. /* sig_IGN */ {                /* Just like the real one, but has  */
  1599. }                    /* different address. */
  1600.  
  1601. VOID
  1602. connoi() {                              /* Console-no-interrupts */
  1603.  
  1604.     debug(F100,"connoi","",0);
  1605.  
  1606.     /* Note the locally defined replacement for SIG_IGN that is used here */
  1607.     /* for the SIGINT setting.  This is done so that the Sys V background */
  1608.     /* test -- (signal(SIGINT,SIG_IGN) == SIG_IGN) -- can work.  If we use */
  1609.     /* the real SIG_IGN here, then conint will always decide that this */ 
  1610.     /* program is running in the background! */
  1611.  
  1612.     signal(SIGINT,sig_ign);        /* <--- note! */
  1613.  
  1614.     signal(SIGHUP,SIG_DFL);
  1615.     signal(SIGTERM,SIG_IGN);
  1616.     chkalrm();
  1617. }
  1618.  
  1619. initrawq(tty) int tty; {
  1620.     chkalrm();
  1621.     return(0);
  1622. }
  1623.  
  1624. static VOID
  1625. catch(foo) int foo; {
  1626.     longjmp(jjbuf, -1);
  1627. }
  1628.  
  1629. /*  G E N B R K  --  Simulate a modem break.  */
  1630.  
  1631. VOID
  1632. genbrk(fn,msec) int fn, msec; {
  1633.  
  1634.     short port = fn;
  1635.     short opcode = SEND_BREAK_OPCODE;
  1636.     short status;
  1637.     short dummy = 0;
  1638.  
  1639.     s$control (&port, &opcode, &dummy, &status);
  1640.     chkalrm();
  1641.  
  1642.     debug(F101,"genbrk status","",status);
  1643.     return;
  1644. }
  1645.  
  1646.  
  1647. /*  T T C H K  --  Tell how many characters are waiting in tty input buffer  */
  1648.  
  1649. /*  Some callers of this want to know whether there is something to read
  1650.  *  either in the system buffers or in our private buffers (and mostly don't
  1651.  *  care how many characters, just whether it's more than zero or not), while
  1652.  *  some others would be better off with the number of characters in our
  1653.  *  private buffers only.
  1654.  *
  1655.  *  Some systems can say how many characters there are in the system buffers.
  1656.  *  Others can not. For those that can't, the number in the private buffers
  1657.  *  will have to do (or should we put the tty into O_NDELAY-mode and try to
  1658.  *  read one character?). If the system can tell whether there is zero or
  1659.  *  more than zero characters, we can return 1 in the latter case even if the
  1660.  *  private buffer is empty. (That is good for sliding windows.)
  1661.  */
  1662. int
  1663. ttchk() {
  1664.     int n = 0;
  1665.  
  1666. #ifdef NETCONN
  1667.     if (netconn)
  1668.     return (nettchk());
  1669. #endif /* NETCONN */
  1670.  
  1671.     if (ttxbn > 0)
  1672.     n += ttxbn;
  1673.  
  1674.     chkalrm();
  1675.  
  1676.     debug(F101,"ttchk returns","",n);
  1677.     return(n);
  1678. }
  1679.  
  1680. /*  T T X I N  --  Get n characters from tty input buffer  */
  1681.  
  1682. /*  Returns number of characters actually gotten, or -1 on failure  */
  1683.  
  1684. /*  Intended for use only when it is known that n characters are actually */
  1685. /*  Available in the input buffer.  */
  1686.  
  1687. int
  1688. ttxin(n,buf) int n; CHAR *buf; {
  1689.     register int x, c;
  1690.   
  1691.     debug(F101,"ttxin n","",n);
  1692.     if (n < 1) return(0);
  1693.  
  1694. #ifdef COMMENT
  1695. #ifdef STRATUSX25
  1696.     if (netconn && (ttnet == NET_VX25))    /* X.25 connection */
  1697.       return(x25xin(n,buf));
  1698. #endif /* STRATUSX25 */
  1699. #endif /* COMMENT */
  1700.  
  1701.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Parity stripping mask. */
  1702.  
  1703.     if (ttxbn < n) {
  1704.         if (!netconn) {            /* All network connections do this. */
  1705.         debug(F101,"ttxin called w/ too few chars","",ttxbn);
  1706.     }
  1707.     n = ttxbn;
  1708.     }
  1709.  
  1710.     memmove (buf,&ttxbuf[ttxbp],n);
  1711.     ttxbp += n;
  1712.     ttxbn -= n;
  1713.     buf[n] = '\0';
  1714.  
  1715.     for (c = 0; c < n; c++)
  1716.     buf[c] &= ttpmsk;
  1717.  
  1718.     return(n);
  1719. }
  1720.  
  1721. /*  T T O L  --  Write string s, length n, to communication device.  */
  1722. /*
  1723.   Returns:
  1724.    >= 0 on success, number of characters actually written.
  1725.    -1 on failure.
  1726. */
  1727. #define TTOLMAXT    10
  1728. int
  1729. ttol(s,n) int n; CHAR *s; {
  1730.     short ttyport = (short) ttyfd;
  1731.     short status;
  1732.     short sys_len;
  1733.     int   x;
  1734.     int   tries;
  1735.     int   len;
  1736.  
  1737.     if (ttyfd < 0) return(-1);          /* Not open? */
  1738.     debug(F101,"ttol n","",n);
  1739.     debug(F110,"ttol s",s,0);
  1740.  
  1741.     tries = TTOLMAXT;            /* Allow up to this many tries */
  1742.     len = n;                /* Remember original length */
  1743.     while (n > 0 && tries-- > 0) {    /* Be persistent */
  1744.     debug(F101,"ttol try","",TTOLMAXT - tries);
  1745.  
  1746.         if (netconn) {
  1747.         x = nettol (s, n);
  1748.         }
  1749.         else {
  1750.         sys_len = n;
  1751.         s$write_raw (&ttyport, &sys_len, s, &status);
  1752.         if (status == 0 || status == e$caller_must_wait) {
  1753.         x = sys_len;
  1754.         status = 0;
  1755.         }
  1756.         else
  1757.         x = -1;
  1758.     }
  1759.  
  1760.     chkalrm();            /* check for alarms */
  1761.  
  1762.     if (x == n) {            /* Worked? */
  1763.         debug(F101,"ttol ok","",x);    /* OK */
  1764.         return(len);        /* Done */
  1765.     } else if (x < 0) {        /* No, got error? */
  1766.         debug(F101,"ttol failed","",errno);
  1767.  
  1768.         if (netconn && ttnet == NET_TCPB) {
  1769.         ttclos(0);        /* Close the connection. */
  1770.         }
  1771.         return(-1);
  1772.     } else {            /* No error, so partial success */
  1773.         debug(F101,"ttol partial","",x);
  1774.         s += x;            /* Point to part not written yet */
  1775.         n -= x;            /* Adjust length */
  1776.         if (x > 0) msleep(100);    /* Wait 100 msec */
  1777.     }                /* Go back and try again */
  1778.     }
  1779.     return(n < 1 ? len : -1);        /* Return the results */
  1780. }
  1781.  
  1782. /*  T T O C  --  Output a character to the communication line  */
  1783.  
  1784. /*
  1785.  This function should only be used for interactive, character-mode operations,
  1786.  like terminal connection, script execution, dialer i/o, where the overhead
  1787.  of the signals and alarms does not create a bottleneck.
  1788. */
  1789. int
  1790. #ifdef CK_ANSIC
  1791. ttoc(char c)
  1792. #else
  1793. ttoc(c) char c;
  1794. #endif /* CK_ANSIC */
  1795. /* ttoc */ {
  1796.     int xx;
  1797.     short ttyport = ttyfd;
  1798.     short len = 1;
  1799.     short status;
  1800.  
  1801.     c &= 0xff;
  1802.     /* debug(F101,"ttoc","",(CHAR) c); */
  1803.     chkalrm();
  1804.     if (ttyfd < 0) return(-1);          /* Check for not open. */
  1805.  
  1806.     if (netconn)
  1807.     return (nettoc(c));
  1808.  
  1809.     s$write_raw (&ttyport, &len, &c, &status);
  1810.     if (status != 0)
  1811.     return -1;
  1812.  
  1813.     return(0);                /* Return good code. */
  1814. }
  1815.  
  1816. /*  T T I N L  --  Read a record (up to break character) from comm line.  */
  1817. /*
  1818.   Reads up to "max" characters from the communication line, terminating on:
  1819.  
  1820.     (a) the packet length field if the "turn" argument is zero, or
  1821.     (b) on the packet-end character (eol) if the "turn" argument is nonzero
  1822.     (c) two Ctrl-C's in a row
  1823.  
  1824.   and returns the number of characters read upon success, or if "max" was
  1825.   exceeded or the timeout interval expired before (a) or (b), returns -1.
  1826.  
  1827.   The characters that were input are copied into "dest" with their parity bits
  1828.   stripped if parity was selected.  Returns the number of characters read.
  1829.   Characters after the eol are available upon the next call to this function.
  1830.  
  1831.   The idea is to minimize the number of system calls per packet, and also to
  1832.   minimize timeouts.  This function is the inner loop of the program and must
  1833.   be as efficient as possible.  The current strategy is to use myread().
  1834.  
  1835.   WARNING: this function calls parchk(), which is defined in another module.
  1836.   Normally, ckutio.c does not depend on code from any other module, but there
  1837.   is an exception in this case because all the other ck?tio.c modules also
  1838.   need to call parchk(), so it's better to have it defined in a common place.
  1839.  
  1840.   Since this function has grown to have its fingers so deeply into the 
  1841.   protocol, it is slated for removal: rpack() will take care of everything.
  1842. */
  1843. #ifdef CTRLC
  1844. #undef CTRLC
  1845. #endif /* CTRLC */
  1846. #define CTRLC '\03'
  1847. /*
  1848.   We have four different declarations here because:
  1849.   (a) to allow Kermit to be built without the automatic parity sensing feature
  1850.   (b) one of each type for ANSI C, one for non-ANSI.
  1851. */
  1852. int
  1853. #ifdef PARSENSE
  1854. #ifdef CK_ANSIC
  1855. ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
  1856. #else
  1857. ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
  1858. #endif /* CK_ANSIC */
  1859. #else /* not PARSENSE */
  1860. #ifdef CK_ANSIC
  1861. ttinl(CHAR *dest, int max,int timo, CHAR eol)
  1862. #else
  1863. ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  1864. #endif /* CK_ANSIC */
  1865. #endif /* PARSENSE */
  1866. /* ttinl */ {
  1867.  
  1868. #ifdef PARSENSE
  1869.     int pktlen = -1;
  1870.     int lplen = 0;
  1871.     int havelen = 0;
  1872.     int flag = 0;
  1873. #endif /* PARSENSE */
  1874.     register int i, m, n;        /* local variables */
  1875.     time_t tout, now;
  1876.     int ccn = 0;
  1877.  
  1878.     chkalrm();
  1879.     if (ttyfd < 0) return(-1);          /* Not open. */
  1880.  
  1881.     debug(F101,"ttinl max","",max);
  1882.     debug(F101,"ttinl timo","",timo);
  1883.  
  1884.     *dest = '\0';                       /* Clear destination buffer */
  1885.     if (timo < 0) timo = 0;        /* Safety */
  1886.  
  1887.     now = time(NULL);
  1888.     tout = now + timo;
  1889.  
  1890. #ifdef PARSENSE
  1891.     flag = 0;            /* Start of packet flag */
  1892. #endif /* PARSENSE */
  1893.  
  1894.     ttpmsk = m = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */
  1895.  
  1896. /* Now read into destination, stripping parity and looking for the */
  1897. /* the packet terminator, and also for transfer cancellation chars */
  1898.  
  1899.     i = 0;                /* Destination index */
  1900. #ifdef COMMENT
  1901.     debug(F101,"ttinl eol","",eol);
  1902. #endif
  1903.  
  1904.     while (i < max-1) {
  1905.         now = time(NULL);
  1906.     if(timo && (tout < now)) {   /* strictly less than */
  1907.         debug(F101,"ttinl timed out","",tout);
  1908.         return (-1); /* timed out */
  1909.     }
  1910.  
  1911.     n = ttinc(timo ? (tout-now) : 0);
  1912.  
  1913.         if (n < 0) {
  1914.         debug(F101,"ttinl ttinc error, char","",n);
  1915.         return (n); /* error */
  1916.         }
  1917. #ifdef COMMENT
  1918.     debug(F101,"ttinl char","", (n & ttpmsk));
  1919. #endif
  1920.  
  1921. #ifdef PARSENSE
  1922. /*
  1923. Figure out what the length is supposed to be in case the packet
  1924. has no terminator (as with Honeywell GCOS-8 Kermit).
  1925. */
  1926. #ifndef xunchar
  1927. #define xunchar(ch) (((ch) - 32 ) & 0xFF )    /* Character to number */
  1928. #endif /* xunchar */
  1929.     if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
  1930.     if (flag) dest[i++] = n & ttpmsk;
  1931. /*
  1932. If we have not been instructed to wait for a turnaround character, we
  1933. can go by the packet length field.  If turn != 0, we must wait for the
  1934. end of line (eol) character before returning.
  1935. */
  1936.     if (i == 2) {
  1937.         pktlen = xunchar(dest[1]);
  1938.         havelen = (pktlen > 1);
  1939.         debug(F101,"ttinl length","",pktlen);
  1940.     } else if (i == 5 && pktlen == 0) {
  1941.         lplen = xunchar(dest[4]);
  1942.     } else if (i == 6 && pktlen == 0) {
  1943.         pktlen = lplen * 95 + xunchar(dest[5]) + 5;
  1944.         havelen = 1;
  1945.         debug(F101,"ttinl length","",pktlen);
  1946.     }
  1947. #else
  1948.     dest[i++] = n & ttpmsk;
  1949. #endif /* PARSENSE */
  1950. /*
  1951.   Use parity mask, rather than always stripping parity, to check for
  1952.   cancellation.  Otherwise, runs like \x03\x83\x03 in packet could cancel
  1953.   the transfer when parity is NONE.
  1954. */
  1955.     /* Check cancellation */
  1956.     if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
  1957.         if (++ccn >= xfrnum) {    /* If xfrnum in a row, bail out. */
  1958.         if (timo) {        /* Clear timer. */
  1959.             debug(F100,"ttinl got ^C^C...","",0);
  1960.             ttimoff();
  1961.         }
  1962.         fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
  1963.         return(-2);
  1964.         }
  1965.     } else ccn = 0;        /* Not ^C, so reset ^C counter, */
  1966.  
  1967. #ifdef PARSENSE
  1968.     if (flag == 0) {
  1969.         debug(F101,"ttinl skipping","",n);
  1970.         continue;
  1971.     }
  1972. #endif /* PARSENSE */
  1973.  
  1974. /* Check for end of packet */
  1975.  
  1976.     if (((n & 0x7f) == eol)
  1977. #ifdef PARSENSE
  1978.         || (!turn && havelen && (i > pktlen+1))
  1979. #endif /* PARSENSE */
  1980.         ) {
  1981. #ifndef PARSENSE
  1982.         debug(F101,"ttinl got eol","",eol);
  1983.         dest[i] = '\0';    /* Yes, terminate the string, */
  1984.         debug(F101,"ttinl i","",i);
  1985. #else
  1986.         if ((n & 0x7f) != eol) {
  1987.         debug(F101,"ttinl EOP length","",pktlen);
  1988.         debug(F101,"ttinl i","",i);
  1989.         } else debug(F101,"ttinl got eol","",eol);
  1990.         dest[i] = '\0';        /* Terminate the string, */
  1991.         /* Parity checked yet? */
  1992.         if (ttpflg++ == 0 && ttprty == 0) {
  1993.         if ((ttprty = parchk(dest,start,i)) > 0) { /* No, check. */
  1994.             int j;
  1995.             debug(F101,"ttinl senses parity","",ttprty);
  1996.             debug(F110,"ttinl packet before",dest,0);
  1997.             ttpmsk = 0x7f;
  1998.             for (j = 0; j < i; j++)
  1999.               dest[j] &= 0x7f;    /* Strip parity from packet */
  2000.             debug(F110,"ttinl packet after ",dest,0);
  2001.         } else ttprty = 0;    /* restore if parchk error */
  2002.         }
  2003. #endif /* PARSENSE */
  2004.         if (timo) {            /* Turn off timer. */
  2005.         ttimoff();
  2006.         }
  2007.         debug(F111,"ttinl got", dest,i);
  2008.         return(i);
  2009.     }
  2010.     }                /* end of while() */
  2011.     debug(F101,"ttinl exited while loop, i","",i);
  2012.     ttimoff();
  2013.     chkalrm();
  2014.     return(-1);
  2015. }
  2016.  
  2017. /*  T T I N C --  Read a character from the communication line  */
  2018. /*
  2019.  On success, returns the character that was read, >= 0.
  2020.  On failure, returns -1 or other negative error code.
  2021. */
  2022. int
  2023. ttinc(timo) int timo; {
  2024.     int ch = 0;
  2025.  
  2026.     chkalrm();
  2027.     if (ttyfd < 0) return(-1);          /* Not open. */
  2028.  
  2029.     /* this can be used for ALL character input, including network io, */
  2030.     /* because ttxgetc will call txbufr, which is network aware.       */
  2031.  
  2032.     ch = ttxgetc(timo);
  2033.  
  2034.     return((ch >= 0) ? ch & ttpmsk : ch); /* return negative codes intact */
  2035. }
  2036.  
  2037. /*  S N D B R K  --  Send a BREAK signal of the given duration  */
  2038.  
  2039. static int
  2040. #ifdef CK_ANSIC
  2041. sndbrk(int msec) {            /* Argument is milliseconds */
  2042. #else
  2043. sndbrk(msec) int msec; {
  2044. #endif /* CK_ANSIC */
  2045. #ifndef POSIX
  2046.     int x, n;
  2047. #endif /* POSIX */
  2048.  
  2049.     debug(F101,"ttsndb ttyfd","",ttyfd);
  2050.     if (ttyfd < 0) return(-1);          /* Not open. */
  2051.  
  2052.     if (netconn)             /* Send network BREAK */
  2053.       return(netbreak());
  2054.  
  2055.     if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
  2056.  
  2057.     genbrk(ttyfd,250);            /* Simulate a BREAK */
  2058.     return(0);
  2059. }
  2060.  
  2061. /*  T T S N D B  --  Send a BREAK signal  */
  2062.  
  2063. int
  2064. ttsndb() {
  2065.     return(sndbrk(275));
  2066. }
  2067.  
  2068. /*  T T S N D L B  --  Send a Long BREAK signal  */
  2069.  
  2070. int
  2071. ttsndlb() {
  2072.     return(sndbrk(1500));
  2073. }
  2074.  
  2075. /*  M S L E E P  --  Millisecond version of sleep().  */
  2076.  
  2077. /*
  2078.   Call with number of milliseconds (thousandths of seconds) to sleep.
  2079.   Intended only for small intervals.  For big ones, just use sleep().
  2080.   Highly system-dependent.
  2081.   Returns 0 always, even if it didn't work.
  2082. */
  2083.  
  2084. int
  2085. msleep(m) int m; {
  2086.     short status;
  2087.  
  2088.     /* argument to s$sleep is really in 1024/s but, this is close enough */
  2089.     m += m / 40;    /* this gives 1025 per second */
  2090.     s$sleep (&m, &status);
  2091.     chkalrm();
  2092.  
  2093.     return(0);
  2094. }
  2095.  
  2096. /*  R T I M E R --  Reset elapsed time counter  */
  2097.  
  2098. VOID
  2099. rtimer() {
  2100.     tcount = time( (time_t *) 0 );
  2101.     debug(F101,"rtimer","",(long) tcount);
  2102.     chkalrm();
  2103. }
  2104.  
  2105.  
  2106. /*  G T I M E R --  Get current value of elapsed time counter in seconds  */
  2107.  
  2108. int
  2109. gtimer() {
  2110.     int x;
  2111.     x = (int) (time( (time_t *) 0 ) - tcount);
  2112.     debug(F101,"gtimer","",x);
  2113.     chkalrm();
  2114.     return( (x < 0) ? 0 : x );
  2115. }
  2116.  
  2117. #ifdef GFTIMER
  2118. /* I know this is different than the structure in the manual.  But
  2119.    since we know what it's really got in it, we can handle it this
  2120.    way.  We've just moved the radix point a little.  
  2121. */
  2122. struct jiffies {
  2123.     unsigned long high;
  2124.     unsigned long low;
  2125. };
  2126.  
  2127. static double dzero;
  2128.  
  2129. VOID
  2130. rftimer() {
  2131.     struct jiffies tzero;
  2132.     s$jiffy_date_time(&tzero);
  2133.  
  2134.     dzero = (tzero.high * (double)65536.0) + (tzero.low / (double)65536.0);
  2135. }
  2136.  
  2137. CKFLOAT
  2138. gftimer() {
  2139.     struct jiffies tnow;
  2140.     double dnow;
  2141.     double s;
  2142. #ifdef DEBUG
  2143.     char fpbuf[64];
  2144. #endif /* DEBUG */
  2145.     s$jiffy_date_time(&tnow);
  2146.  
  2147.     dnow = (tnow.high * (double)65536.0) + (tnow.low / (double)65536.0);
  2148.     s = dnow - dzero;
  2149.  
  2150.     if (s == 0.0) s = 0.000001;
  2151. #ifdef DEBUG
  2152.     if (deblog) {
  2153.     sprintf(fpbuf,"%f",s);
  2154.     debug(F110,"gftimer",fpbuf,0);
  2155.     }
  2156. #endif /* DEBUG */
  2157.     return((CKFLOAT)s);
  2158. }
  2159. #endif /* GFTIMER */
  2160.  
  2161.  
  2162. /*  Z T I M E  --  Return date/time string  */
  2163.  
  2164. VOID
  2165. ztime(s) char **s; {
  2166.  
  2167.     struct tm *tp;
  2168.     time_t xclock;
  2169.     time(&xclock);
  2170.     tp = localtime(&xclock);
  2171.     *s = asctime(tp);
  2172.     debug(F111,"ztime",*s,(long) xclock);
  2173.     chkalrm();
  2174. }
  2175.  
  2176. /*  C O N G M  --  Get console terminal modes.  */
  2177.  
  2178. /*
  2179.   Saves initial console mode, and establishes variables for switching
  2180.   between current (presumably normal) mode and other modes.
  2181.   Should be called when program starts, but only after establishing
  2182.   whether program is in the foreground or background.
  2183.   Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
  2184. */
  2185. int
  2186. congm() {
  2187.     TERMINAL_INFO    tinfo;
  2188.     short        opcode;
  2189.     short        conport = TERMINAL_PORT_ID;
  2190.     short        status;
  2191.  
  2192.     chkalrm();
  2193.     if (backgrd || !vostty(conport)) {    /* If in background. */
  2194.     cgmf = -1;            /* Don't bother, modes are garbage. */
  2195.     return(-1);
  2196.     }
  2197.  
  2198.     if (cgmf > 0) return(0);        /* Already did this. */
  2199.     debug(F100,"congm getting modes","",0); /* Need to do it. */
  2200.  
  2201.     opcode = GET_INFO_OPCODE;
  2202.     tinfo.version = TERMINAL_INFO_VERSION_2;
  2203.     s$control (&conport, &opcode, &tinfo, &status);
  2204.     if (status) {
  2205.     debug(F111,"congm s$control GET_INFO status",ttnmful,status);
  2206.     return -1;
  2207.     }
  2208.  
  2209.     ccold = tinfo.modes;
  2210.     cccbrk = tinfo.modes;
  2211.     if (0 == plines)
  2212.     plines = tinfo.pause_lines;
  2213.  
  2214.     cccbrk &= ~(OS_FUNCTION_KEY_INPUT | OS_BREAK_TABLE_RECORD
  2215.     | OS_GENERIC_INPUT | OS_FORMS_INPUT);
  2216.     cccbrk |= OS_RAW_INPUT | OS_BULK_RAW_INPUT;
  2217.     ccraw = cccbrk;
  2218.  
  2219.     chkalrm();
  2220.     cgmf = 1;                /* Flag that we got them. */
  2221.     return(1);
  2222. }
  2223.  
  2224. /*  C O N C B --  Put console in cbreak mode.  */
  2225.  
  2226. /*  Returns 0 if ok, -1 if not  */
  2227.  
  2228. int
  2229. #ifdef CK_ANSIC
  2230. concb(char esc)
  2231. #else
  2232. concb(esc) char esc;
  2233. #endif /* CK_ANSIC */
  2234. /* concb */ {
  2235.     short opcode = SET_MODES_OPCODE;
  2236.     short port = TERMINAL_PORT_ID;
  2237.     short status;
  2238.  
  2239.     chkalrm();
  2240.     if (cgmf < 1) return(0);        /* Console modes not available yet */
  2241.  
  2242.     debug(F101,"concb backgrd","",backgrd);
  2243.     if (backgrd) return(0);        /* Do nothing if in background. */
  2244.  
  2245.     if (!vostty(port)) return(0);       /* Only for real ttys */
  2246.     if (no_wait) cancio();        /* back to wait mode */
  2247.  
  2248.     s$control (&port, &opcode, &ccraw, &status);
  2249.     if (status) {
  2250.     debug(F101,"concb s$control[SET_MODES] status","",status);
  2251.     return (-1);
  2252.     }
  2253.  
  2254.     escchr = esc;                       /* Make this available to other fns */
  2255.     ckxech = 1;                         /* Program can echo characters */
  2256.     conraw = 1;
  2257.  
  2258.     chkalrm();
  2259.     return(0);
  2260. }
  2261.  
  2262. /*  C O N B I N  --  Put console in binary mode  */
  2263.  
  2264. /*  Returns 0 if ok, -1 if not  */
  2265.  
  2266. int
  2267. #ifdef CK_ANSIC
  2268. conbin(char esc)
  2269. #else
  2270. conbin(esc) char esc;
  2271. #endif /* CK_ANSIC */
  2272. /* conbin */  {
  2273.  
  2274.     short port = TERMINAL_PORT_ID;
  2275.     short opcode = SET_MODES_OPCODE;
  2276.     short status;
  2277.  
  2278.     chkalrm();
  2279.     debug(F101,"conbin esc","",esc);
  2280.     if (!vostty(port))            /* only for real ttys */
  2281.     return(0);
  2282.     congm();                /* Get modes if necessary. */
  2283.  
  2284.     s$control (&port, &opcode, &ccraw, &status);
  2285.     if (status)
  2286.     debug(F101,"conbin s$control SET_MODES status","",status);
  2287.  
  2288.     escchr = esc;                       /* Make this available to other fns */
  2289.     ckxech = 1;                         /* Program can echo characters */
  2290.     conraw = 2;
  2291.     chkalrm();
  2292.     return (0);
  2293. }
  2294.  
  2295. /*  C O N R E S  --  Restore the console terminal  */
  2296.  
  2297. int
  2298. conres() {
  2299.     short conport = TERMINAL_PORT_ID;
  2300.     short opcode = SET_MODES_OPCODE;
  2301.     short lines; 
  2302.     short status;
  2303.  
  2304.     debug(F101,"conres cgmf","",cgmf);
  2305.     if (no_wait) /* turn it off */
  2306.     cancio();
  2307.     chkalrm();
  2308.     if (cgmf < 1) return(0);        /* Do nothing if modes unchanged */
  2309.     if (!vostty(conport)) return(0);    /* only for real ttys */
  2310.  
  2311.     s$control (&conport, &opcode, &ccold, &status);
  2312.     if (status)
  2313.     debug(F101,"conres modes status","",status);    
  2314.  
  2315.     ckxech = 0;                         /* System should echo chars */
  2316.     conraw = 0;                /* not in raw mode any more */
  2317.     chkalrm();
  2318.     return (0);
  2319. }
  2320.  
  2321. /*  C O N O C  --  Output a character to the console terminal  */
  2322.  
  2323. int
  2324. #ifdef CK_ANSIC
  2325. conoc(char c)
  2326. #else
  2327. conoc(c) char c;
  2328. #endif /* CK_ANSIC */
  2329. /* conoc */ {
  2330.     int rv;
  2331.  
  2332.     if (c == '\n' && conraw == 1) /* don't translate in binary or non-raw */
  2333.     if (0 > (rv = conout("\r",1)))
  2334.         return rv;
  2335.  
  2336.     rv = conout(&c,1);
  2337.     return rv;
  2338. }
  2339.  
  2340. /*  C O N X O  --  Write x characters to the console terminal  */
  2341.  
  2342. int
  2343. conxo(x,s) int x; char *s; {
  2344.     /* this doesn't handle \n translations */
  2345.     return(conout(s,x));
  2346. }
  2347.  
  2348. /*  C O N O L  --  Write a line to the console terminal  */
  2349.  
  2350. int
  2351. conol(s) char *s; {
  2352.     int len;
  2353.     len = (int)strlen(s);
  2354.     return(vosprtf("%s",s));
  2355. }
  2356.  
  2357. /*  C O N O L A  --  Write an array of lines to the console terminal */
  2358.  
  2359. int
  2360. conola(s) char *s[]; {
  2361.     int i;
  2362.     for (i=0 ; *s[i] ; i++) if (conol(s[i]) < 0) return(-1);;
  2363.     return(0);
  2364. }
  2365.  
  2366. /*  C O N O L L  --  Output a string followed by CRLF  */
  2367.  
  2368. int
  2369. conoll(s) char *s; {
  2370.     conol(s);
  2371.     return(conoc('\n'));
  2372. }
  2373.  
  2374. /*  C O N O U T  --  Write to console device  */
  2375.  
  2376. static int
  2377. conout(s,n) char *s; int n; {
  2378.     short conport = TERMINAL_PORT_ID;
  2379.     short status;
  2380.     short slen = n;
  2381.  
  2382.     chkalrm();
  2383.     if (backgrd)
  2384.     return -1;
  2385.  
  2386.     if (conraw)
  2387.     s$write_raw (&conport, &slen, s, &status);
  2388.     else
  2389.     s$seq_write_partial (&conport, &slen, s, &status);
  2390.  
  2391.     chkalrm();
  2392.     if (status) {
  2393.         debug(F101,"conout s$write status","",status);
  2394.     return -1;
  2395.     }
  2396.  
  2397.     return slen;
  2398. }
  2399.  
  2400. /*  C O N C H K  --  Return how many characters available at console  */
  2401.  
  2402. int
  2403. conchk() {
  2404.     short status;
  2405.     short status2;
  2406.     short buflen;
  2407.     short reclen;
  2408.     long  ticks;
  2409.     short conport;
  2410.  
  2411.     if (backgrd || !vostty(TERMINAL_PORT_ID))
  2412.     return(0);
  2413.  
  2414.     chkalrm();
  2415.  
  2416.     if (cincnt)
  2417.     return cincnt;    /* just pass back the buffered number */
  2418.  
  2419.     conport = TERMINAL_PORT_ID;
  2420.     ticks = 25; /* this isn't called very often */
  2421.     s$set_io_time_limit (&conport, &ticks, &status);
  2422.     if (status) return (-1);
  2423.  
  2424.     buflen = sizeof cinbuff;
  2425.     s$read_raw (&conport, &buflen, &reclen, cinbuff, &status);
  2426.     if ((status == e$timeout) || (status == e$short_record))
  2427.     status = 0;
  2428.  
  2429.     ticks = -1; /* turn timer off */
  2430.     s$set_io_time_limit (&conport, &ticks, &status2);
  2431.  
  2432.     if (status || status2) {
  2433.     debug(F101,"conchk returning status","",status ? status : status2);
  2434.     return (-1);
  2435.     }
  2436.     cincnt = reclen;    /* how many did we get? */
  2437.     cinbp = 0;        /* point to first character */
  2438.  
  2439.     return (cincnt);
  2440. }
  2441.  
  2442. /*  C O N I N C  --  Get a character from the console  */
  2443. /*
  2444.   Call with timo > 0 to do a timed read, timo == 0 to do an untimed read.
  2445.   Upon success, returns the character.  Upon failure, returns -1.
  2446.   A timed read that does not complete within the timeout period returns -1.
  2447.   A no_wait timeout with nothing to read returns -2.
  2448. */
  2449. int
  2450. coninc(timo) int timo; {
  2451.     short conport = TERMINAL_PORT_ID;
  2452.     short status;
  2453.     short reclen;
  2454.     short buflen = sizeof cinbuff;
  2455.     long  ticks;
  2456.     short sstat;
  2457.  
  2458.     if (cincnt) {
  2459.     cincnt--;
  2460.     return (cinbuff[cinbp++]);
  2461.     }
  2462.  
  2463.     chkalrm();
  2464.  
  2465.     if (timo > 0 ) {                   /* set time limit */
  2466.     ticks = timo * 1024;
  2467.     s$set_io_time_limit (&conport, &ticks, &status);
  2468.     if (status) return (-1);
  2469.     }
  2470.  
  2471.     while (1) {            /* Keep trying till we get one. */
  2472.     if (conraw)
  2473.         s$read_raw (&conport, &buflen, &reclen, cinbuff, &status);
  2474.     else
  2475.         s$seq_read (&conport, &buflen, &reclen, cinbuff, &status);
  2476.  
  2477.     switch (status) {
  2478.         case e$caller_must_wait:
  2479.         case e$short_record:
  2480.         if (reclen)
  2481.             status = 0;
  2482.  
  2483.         /* NO BREAK HERE */
  2484.  
  2485.         case 0:
  2486.         cincnt = reclen;    /* how many did we get? */
  2487.         cinbp = 0;        /* reset buffer pointer */
  2488.         break;
  2489.  
  2490.         default:
  2491.         break;
  2492.     }
  2493.  
  2494.     if (status)
  2495.         break;
  2496.  
  2497.     if (reclen == 0) continue;    /* Shouldn't happen. */
  2498.     if (reclen > 0) {        /* If read was successful, */
  2499.         if (timo > 0 ) {
  2500.         ticks = -1; /* turn timer off */
  2501.         s$set_io_time_limit (&conport, &ticks, &status);
  2502.             chkalrm();
  2503.         if (status) return (-1);
  2504.         }
  2505.  
  2506.         chkalrm();
  2507.         if (cincnt) {
  2508.         cincnt--;
  2509.         return ((cinbuff[cinbp++]) & 0377); /* return the character. */
  2510.         }
  2511.         return(-1); /* shouldn't get here */
  2512.     }
  2513.     }
  2514.  
  2515.     /* Come here if read() returned an error. */
  2516.     sstat = status;
  2517.     if (timo > 0 ) {
  2518.     ticks = -1; /* turn timer off */
  2519.     s$set_io_time_limit (&conport, &ticks, &status);
  2520.         chkalrm();
  2521.     if (status) return (-1);
  2522.     }
  2523.  
  2524.     if (e$caller_must_wait == status)
  2525.     return (-2);
  2526.  
  2527.     debug(F101, "coninc(0) s$read status","",sstat); /* Log the error. */
  2528.  
  2529.     return(-1);
  2530. }
  2531.  
  2532. /*  C O N G K S  --  Console Get Keyboard Scancode  */
  2533.  
  2534. #ifndef congks
  2535. /*
  2536.   This function needs to be filled in with the various system-dependent
  2537.   system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
  2538.   keyboard scan code.  For now, it's a dummy.
  2539. */
  2540. int
  2541. congks(timo) int timo; {
  2542.     return(coninc(timo));
  2543. }
  2544. #endif /* congks */
  2545.  
  2546. /*
  2547.   contti()  is  used  by the conect() routine to handle the problem of getting
  2548.   input from both the console and the tty device at  the  same  time,  without
  2549.   hanging  on  one  waiting  on  the  other.  In  VOS, we set the devices into
  2550.   no_wait mode, read the event counts, and  try  to  read.  If  we  don't  get
  2551.   anything (actually, if we get e$caller_must_wait), then we call s$wait_event
  2552.   to do the waiting.
  2553. */
  2554. int
  2555. #ifdef CK_ANSIC
  2556. contti(int *c, int *src)
  2557. #else
  2558. contti(c, src) int *c; int *src
  2559. #endif
  2560. /* contti () */ {
  2561.     short ttyport;
  2562.     short conport;
  2563.     short status;
  2564.     short buflen;
  2565.     short reclen;
  2566.     short which;
  2567.     long timeout;
  2568.     short count;
  2569.     short eventstat;
  2570.     char  ch;
  2571.  
  2572.     *src = -1;
  2573.     *c = 0;
  2574.     ttyport = ttyfd;
  2575.     conport = TERMINAL_PORT_ID;
  2576.  
  2577.     chkalrm();
  2578.     if (0 == no_wait) {
  2579.         no_wait = 1;
  2580. #ifdef NETCONN
  2581.         if (netconn) {
  2582.         status = netwait (no_wait, ttyfd, &eventids[1], &eventcnts[1]);
  2583.         if (status) {
  2584.         debug(F101,"contti nowait net tty status","",status);
  2585.         return (-1);
  2586.         }
  2587.     }
  2588.     else { /* some sort of "terminal" */
  2589. #endif
  2590.         s$set_no_wait_mode (&ttyport, &eventids[1], &status);
  2591.         if (status) {
  2592.         debug(F101,"contti nowait tty status","",status);
  2593.         return (-1);
  2594.         }
  2595. #ifdef NETCONN
  2596.     }
  2597. #endif
  2598.     s$set_no_wait_mode (&conport, &eventids[0], &status);
  2599.     if (status) {
  2600.         debug(F101,"contti nowait con status","",status);
  2601.         return (-1);
  2602.     }
  2603.     }
  2604.  
  2605.     if (ttxbn) {    /* return buffered tty character */
  2606.     *src = 1;
  2607.     *c = ttxgetc(0);
  2608.     return 0;
  2609.     }
  2610.  
  2611.     if (cincnt) {     /* return buffered console character */
  2612.     *src = 0;
  2613.     *c = coninc(0);
  2614.     return 0;
  2615.     }
  2616.  
  2617.  
  2618. #ifdef NETCONN
  2619.     if (netconn == 0) { /* Don't use read_event with socket events... */
  2620. #endif
  2621.     s$read_event (&eventids[1], &eventcnts[1], &eventstat, &status);
  2622.     if (status) {
  2623.         debug(F101,"contti read event tty status","",status);
  2624.         return (-1);
  2625.     }
  2626. #ifdef NETCONN
  2627.     }
  2628. #endif
  2629.  
  2630.     do {
  2631.         *c = ttxgetc(0);        /* ttxgetc knows about net* io */
  2632.     if (*c >= 0) {            /* got one */
  2633.         *src = 1;
  2634.         return 0;
  2635.     }
  2636.  
  2637.     if (*c == -2) {            /* -1 is e$cmw, -2 hangup */
  2638.         debug(F101,"contti read tty ch","",*c);
  2639.         return (-2);
  2640.     }
  2641.  
  2642.     s$read_event (&eventids[0], &eventcnts[0], &eventstat, &status);
  2643.     if (status) {
  2644.         debug(F101,"contti read event console status","",status);
  2645.         return (-1);
  2646.     }
  2647.  
  2648.     do {
  2649.         *c = coninc(0);
  2650.  
  2651.         if (*c >= 0) { /* read a character successfully */
  2652.         *src = 0;
  2653.         return 0;
  2654.         }
  2655.  
  2656.         if (*c == -1) { /* error */
  2657.         debug(F101,"contti coninc returns","",*c);
  2658.         return (-1);
  2659.         }
  2660.  
  2661.         timeout = -1;
  2662.         which = 1; /* must be initialized */
  2663.         count = 2;
  2664.         s$wait_event (&count, eventids, eventcnts, &timeout,
  2665.         &which, &status);
  2666.         if (status) {
  2667.         debug(F101,"contti wait event status","",status);
  2668.         return (-1);
  2669.             chkalrm();
  2670.         }
  2671.     }
  2672.     while (which == 1);    /* console */
  2673.     }
  2674.     while (which == 2);        /* tty */
  2675.  
  2676.     debug(F101,"contti cannot get here, which","",which);
  2677.     return (-1);
  2678. }
  2679.  
  2680. /* C O N R E S N E    -- restore console to normal attributes, just like
  2681.             conres, but with system echo turned off.  Used for 
  2682.             escape processing during CONNECT. Actually, it wants
  2683.             concb without echo, but the description says conres.
  2684. */
  2685. VOID conresne(void) {
  2686.     short conport = TERMINAL_PORT_ID;
  2687.     short status;
  2688.     short opcode = DISPLAY_OFF_OPCODE;
  2689.     short dummy = 0;
  2690.  
  2691.     concb(escchr);
  2692.     s$control (&conport, &opcode, &dummy, &status);
  2693.     debug(F101,"conresne s$control DISPLAY_OFF status","",status);
  2694.     ckxech = 1;                         /* Program can echo characters */
  2695.     chkalrm();
  2696. }
  2697.  
  2698. /* C A N C I O    -- Finished with CONNECT, cancel no_wait and pending I/O */
  2699. VOID cancio (void) {
  2700.     short conport;
  2701.     short ttyport;
  2702.     short status;
  2703.     short opcode;
  2704.     short dummy = 0;
  2705.  
  2706.     chkalrm();
  2707.  
  2708.     if (no_wait) {
  2709.     ttyport = ttyfd;
  2710.     conport = TERMINAL_PORT_ID;
  2711.     if (no_wait) {
  2712.         no_wait = 0;
  2713. #ifdef NETCONN
  2714.         if (netconn)
  2715.         status = netwait (no_wait, ttyfd, NULL, NULL);
  2716.         else
  2717. #endif /* NETCONN */
  2718.         s$set_wait_mode (&ttyport, &status);
  2719.  
  2720.         if (status)
  2721.         debug(F101,"cancio s$set_wait_mode tty status","",status);
  2722.  
  2723.         s$set_wait_mode (&conport, &status);
  2724.         if (status)
  2725.         debug(F101,"cancio s$set_wait_mode con status","",status);
  2726.     }
  2727.     }
  2728.  
  2729. #ifdef COMMENT
  2730.     /* we only do this for the console */
  2731.     opcode = DISCARD_INPUT_OPCODE;
  2732.     s$control (&conport, &opcode, &dummy, &status);
  2733.     if (status)
  2734.     debug(F101,"cancio s$control DISCARD_INPUT status","",status);
  2735.  
  2736.     opcode = DISCARD_OUTPUT_OPCODE;
  2737.     s$control (&conport, &opcode, &dummy, &status);
  2738.     if (status)
  2739.     debug(F101,"cancio s$control DISCARD_OUTPUT status","",status);
  2740. #endif
  2741. }
  2742.  
  2743. /*  T T S C A R R  --  Set ttcarr variable, controlling carrier handling.
  2744.  *
  2745.  *  0 = Off: Always ignore carrier. E.g. you can connect without carrier.
  2746.  *  1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
  2747.  *  2 = Auto: For "modem direct": The same as "Off".
  2748.  *            For real modem types: Heed carrier during connect, but ignore
  2749.  *                it anytime else.  Compatible with pre-5A C-Kermit versions.
  2750.  *
  2751.  * Of course, nothing of this applies to remote mode (xlocal = 0).
  2752.  *
  2753.  */
  2754. int
  2755. ttscarr(carrier) int carrier; {
  2756.     ttcarr = carrier;
  2757.     debug(F101, "ttscarr","",ttcarr);
  2758.     chkalrm();
  2759.     return(ttcarr);
  2760. }
  2761.  
  2762. /* C A R R C T L  --  Set tty modes for carrier treatment.
  2763.  *
  2764.  * Sets the appropriate bits in a termio or sgttyb struct for carrier control
  2765.  * (actually, there are no bits in sgttyb for that), or performs any other
  2766.  * operations needed to control this on the current system.  The function does
  2767.  * not do the actual TCSETA or stty, since often we want to set other bits too
  2768.  * first.  Don't call this function when xlocal is 0, or the tty is not opened.
  2769.  *
  2770.  * We don't know how to do anything like carrier control on non-ATTSV systems,
  2771.  * except, apparently, ultrix.  See above.  It is also known that this doesn't
  2772.  * have much effect on a Xenix system.  For Xenix, one should switch back and
  2773.  * forth between the upper and lower case device files.  Maybe later. 
  2774.  * Presently, Xenix will stick to the mode it was opened with.
  2775.  *
  2776.  * carrier: 0 = ignore carrier, 1 = require carrier.
  2777.  * The current state is saved in curcarr, and checked to save labour.
  2778.  */
  2779.  
  2780. int
  2781. #ifdef CK_ANSIC
  2782. carrctl(long *ttpar, int carrier) {
  2783. #else
  2784. carrctl(ttpar, carrier) long *ttpar; int carrier; {
  2785. #endif
  2786.     int temp = 0;
  2787.     int modem_status;
  2788.     debug(F101, "carrctl","",carrier);
  2789.     chkalrm();
  2790.     if (carrier == curcarr)
  2791.       return(0);
  2792.     curcarr = carrier;
  2793.  
  2794.     return(0);
  2795. }
  2796.  
  2797.  
  2798. /*  T T G M D M  --  Get modem signals  */
  2799. /*
  2800.  Looks for RS-232 modem signals, and returns those that are on in as its
  2801.  return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
  2802.  Returns: 
  2803.  -3 Not implemented
  2804.  -2 if the communication device does not have modem control (e.g. telnet)
  2805.  -1 on error.
  2806.  >= 0 on success, with a bit mask containing the modem signals that are on.
  2807. */
  2808.  
  2809. int
  2810. ttgmdm() {
  2811.     short status;
  2812.     DATA_SET_STATUS_INFO dssi;
  2813.     CV(66) data_set_name;
  2814.     int x, y, z;
  2815.  
  2816.     chkalrm();
  2817. #ifdef NETCONN
  2818.     if (netconn) return(-2);        /* Network, no modem signals. */
  2819. #endif
  2820.  
  2821.     strcpy (&data_set_name, ttnmful);
  2822.     dssi.version = 1;
  2823.     dssi.flags = 0;
  2824.     s$get_data_set_status (&data_set_name, &dssi, &status);
  2825.     debug(F101,"ttgmdm",ttnmful,(long)dssi.flags);
  2826.     if (status) {
  2827.     debug(F101,"ttgmdm s$get_data_set_status status","",status);
  2828.     return (status == e$device_not_local) ? (-2) : (-1);
  2829.     }
  2830.  
  2831.     y = 0;
  2832.     if (dssi.flags & DSSI_DATA_SET_READY)
  2833.     y |= BM_DSR;
  2834.  
  2835.     if (dssi.flags & DSSI_CARRIER_DETECT)
  2836.     y |= BM_DCD;
  2837.  
  2838.     if (dssi.flags & DSSI_CLEAR_TO_SEND)
  2839.     y |= BM_CTS;
  2840.  
  2841.     return y;
  2842. }
  2843.  
  2844. /*  P S U S P E N D  --  Put this process in the background.  */
  2845.  
  2846. /*
  2847.   Call with flag nonzero if suspending is allowed, zero if not allowed.
  2848.   Returns 0 on apparent success, -1 on failure (flag was zero, or
  2849.   kill() returned an error code.  VOS doesn't support this.
  2850. */
  2851. int
  2852. psuspend(flag) int flag; {
  2853.  
  2854.     if (flag == 0) return(-1);
  2855.     chkalrm();
  2856.  
  2857.     return(-1);        /* Didn't work. Never works. */
  2858. }
  2859.  
  2860.  
  2861. /* Variables for user and group IDs. */
  2862.  
  2863. static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
  2864. static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
  2865.  
  2866.  
  2867. /* P R I V _ I N I  --  Initialize privileges package  */
  2868.  
  2869. /* Called as early as possible in a set-uid or set-gid program to store the
  2870.  * set-to uid and/or gid and step down to the users real uid and gid. The
  2871.  * stored id's can be temporarily restored (allowed in System V) during
  2872.  * operations that require the privilege.  Most of the time, the program
  2873.  * should execute in unpriviliged state, to not impose any security threat.
  2874.  *
  2875.  * Note: Don't forget that access() always uses the real id:s to determine
  2876.  * file access, even with privileges restored.
  2877.  *
  2878.  * Returns an error mask, with error values or:ed together:
  2879.  *   1 if setuid() fails,
  2880.  *   2 if setgid() fails, and
  2881.  *   4 if the program is set-user-id to "root", which can't be handled.
  2882.  *
  2883.  * Only the return value 0 indicates real success. In case of failure,
  2884.  * those privileges that could be reduced have been, at least, but the
  2885.  * program should be aborted none-the-less.
  2886.  *
  2887.  * Also note that these functions do not expect the uid or gid to change
  2888.  * without their knowing. It may work if it is only done temporarily, but
  2889.  * you're on your own.
  2890.  *
  2891.  * VOS does support suid programs (Called "owner access"), but not changing
  2892.  * these things around.  It also only applies to file access permissions.
  2893.  */
  2894. int
  2895. priv_ini() {
  2896.     int err = 0;
  2897.  
  2898.     return(err); /* always say it's okay */
  2899. }
  2900.  
  2901. /* P R I V _ O N  --  Turn on the setuid and/or setgid */
  2902.  
  2903. /* Go to the privileged uid (gid) that the program is set-user-id
  2904.  * (set-group-id) to, unless the program is running unprivileged.
  2905.  * If setuid() fails, return value will be 1. If getuid() fails it
  2906.  * will be 2.  Return immediately after first failure, and the function
  2907.  * tries to restore any partial work done.  Returns 0 on success.
  2908.  * Group id is changed first, since it is less serious than user id.
  2909.  */
  2910. int
  2911. priv_on() {
  2912.     return(0); /* always say it's okay */
  2913. }
  2914.  
  2915. /* P R I V _ O F F  --  Turn on the real uid and gid */
  2916.  
  2917. /* Return to the unprivileged uid (gid) after an temporary visit to
  2918.  * privileged status, unless the program is running without set-user-id
  2919.  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
  2920.  * in setgid() or:ed together. The functions tries to return both uid
  2921.  * and gid to unprivileged state, regardless of errors. Returns 0 on
  2922.  * success.
  2923.  */
  2924. int
  2925. priv_off() {
  2926.     int err = 0;
  2927.  
  2928.     return(err); /* always say it's okay */
  2929. }
  2930.  
  2931. /* Turn off privilege permanently.  No going back.  This is necessary before
  2932.  * a fork() on BSD43 machines that don't save the setUID or setGID, because
  2933.  * we swap the real and effective ids, and we don't want to let the forked
  2934.  * process swap them again and get the privilege back. It will work on other
  2935.  * machines too, such that you can rely on its effect always being the same,
  2936.  * for instance, even when you're in priv_on() state when this is called.
  2937.  * (Well, that part about "permanent" is on System V only true if you follow
  2938.  * this with a call to exec(), but that's what we want it for anyway.)
  2939.  * Added by Dean Long -- dlong@midgard.ucsc.edu
  2940.  */
  2941. int
  2942. priv_can() {
  2943.     return(priv_off()); 
  2944. }
  2945.  
  2946. /* P R I V _ O P N  --  For opening protected files or devices. */
  2947.  
  2948. int
  2949. priv_opn(name, modes) char *name; int modes; {
  2950.  
  2951.     /* Return Failure, since we can't do an open with these parameters */
  2952.     return(-1);
  2953. }
  2954.  
  2955. /*  P R I V _ C H K  --  Check privileges.  */
  2956.  
  2957. /*  Try to turn them off.  If turning them off did not succeed, cancel them */
  2958.  
  2959. int
  2960. priv_chk() {
  2961.     int x;
  2962.     x = priv_off();            /* Turn off privs. */
  2963.     return(0); /* always say it's okay */
  2964. }
  2965.  
  2966. UID_T
  2967. real_uid() {
  2968.     return(realuid);
  2969. }
  2970.  
  2971. VOID
  2972. ttimoff() {                /* Turn off any timer interrupts */
  2973.     short ttyport;
  2974.     short status;
  2975.     long  timo = -1; /* turn it off */
  2976.  
  2977.     if (ttyfd < 0)  return;
  2978.  
  2979.     ttyport = ttyfd;
  2980.     s$set_io_time_limit (&ttyport, &timo, &status);
  2981.     debug(F101,"ttimoff status","",status);
  2982.     chkalrm();
  2983.     return;
  2984. }
  2985.  
  2986.  
  2987. int vostty (int iport)
  2988. {
  2989.   short port = (short) iport;
  2990.   short status;
  2991.   get_port_info info;
  2992.   int i;
  2993.  
  2994.   info.version = GET_PORT_INFO_VERSION_1;
  2995.   s$get_port_info (&port, &info, &status);
  2996.   if (status)
  2997.   {
  2998.     errno = status;
  2999.     return -1;
  3000.   }
  3001.   i = s$is_file_type_a_terminal (&info.type);
  3002.  
  3003.   return i;
  3004. }
  3005.  
  3006. static char *connam (void)
  3007. {
  3008.   short port = TERMINAL_PORT_ID;
  3009.   short status;
  3010.   get_port_info info;
  3011.   static char tname[DEVNAMLEN+1];
  3012.  
  3013.   info.version = GET_PORT_INFO_VERSION_1;
  3014.   s$get_port_info (&port, &info, &status);
  3015.   if (status)
  3016.   {
  3017.     errno = status;
  3018.     return "";
  3019.   }
  3020.  
  3021.   strncpy (tname, &info.path_name, DEVNAMLEN);
  3022.   tname[DEVNAMLEN] = '\0';
  3023.   return tname;
  3024. }
  3025.  
  3026. int vosprtf (char *fmt, ... )
  3027. {
  3028.     char buff[1024]; /* hope this is big enough */
  3029.     va_list args;
  3030.     int rv;
  3031.     int diff;
  3032.     char *cp;
  3033.     char *lcp;
  3034.  
  3035.     va_start (args, fmt);
  3036.     if (backgrd)            /* in background, printf is okay */
  3037.     rv = vprintf (fmt, args);
  3038.     else                /* in foreground, it is not */
  3039.     {
  3040.     rv = vsprintf (buff, fmt, args);
  3041.  
  3042.     if (rv > sizeof buff) /* we're doomed... */
  3043.         return (-1);
  3044.  
  3045.     /* loop, adding CR's to all the LF's */
  3046.  
  3047.         lcp = buff;
  3048.     cp = strchr (lcp, '\n');
  3049.     while (cp && *cp)
  3050.     {
  3051.         diff = cp - lcp;
  3052.         if (0 > conout (lcp, diff)) return (-1);
  3053.         if (0 > conout ("\r", 1)) return (-1);
  3054.         lcp = cp;
  3055.         cp = strchr (lcp+1, '\n');
  3056.     }
  3057.     if (0 > conout (lcp, strlen (lcp))) return (-1);
  3058.     }
  3059.  
  3060.     va_end (args);
  3061.  
  3062.     return (rv);
  3063. }
  3064.  
  3065. /*
  3066.  * We fudge getenv here.  VOS doesn't have an "environment," hence, no
  3067.  * environment variables.  We find the ones that get asked for, and find a
  3068.  * way to get the requested value, and return it to the caller. The c-runtime
  3069.  * version always returns the empty string, so that's our default.
  3070.  */
  3071. char *
  3072. #ifdef CK_ANSIC
  3073. getenv(const char *str)
  3074. #else
  3075. getenv(str) char *str;
  3076. #endif 
  3077. /* getenv */ {
  3078.     static char envbuf[256];
  3079.     short status;
  3080.     short opcode;
  3081.     short port;
  3082.     TERMINAL_INFO tinfo;
  3083.     int len;
  3084.     CV(66) dummy;
  3085.     CV(66) modname;
  3086.     CV(256) envpath;
  3087.     char buff[300];
  3088.     short io_type;
  3089.     short envport = 0;
  3090.     short bufflen;
  3091.     short reclen;
  3092.  
  3093.     debug(F110,"GETENV called",str,0);
  3094.     strcpy (envbuf, "");  /* make sure it's empty first */
  3095.  
  3096.     chkalrm();
  3097.  
  3098.     s$get_home_dir (&envpath);
  3099.  
  3100.     strcat (&envpath, ">ckermit.env");
  3101.     io_type = INPUT_TYPE;
  3102.     s$seq_open (&envpath, &io_type, &envport, &status);
  3103.     strcpy (buff, &envpath);
  3104.     debug(F111,"       s$seq_open status",buff,status);
  3105.  
  3106.     len = strlen (str);
  3107.  
  3108.     while ('\0' == envbuf[0] && 0 == status) {
  3109.      bufflen = sizeof buff;
  3110.     s$seq_read (&envport, &bufflen, &reclen, buff, &status);
  3111.         if (0 == status) {
  3112.         buff[reclen] = '\0';
  3113.         if (reclen > len && 0 == strncmp (str, buff, len)) {
  3114.         if ('=' == buff[len])
  3115.             strcpy (envbuf, &buff[len+1]);
  3116.         }
  3117.     }
  3118.     }
  3119.  
  3120.     if (envport > 0) {
  3121.     s$close (&envport, &status);
  3122.     s$detach_port (&envport, &status);
  3123.     }
  3124.  
  3125.     if ('\0' == envbuf[0]) { /* haven't found it */
  3126.     if(0 == strcmp(str, "TERM")) { /* console terminal type */
  3127.         port = TERMINAL_PORT_ID;
  3128.         opcode = GET_INFO_OPCODE;
  3129.         tinfo.version = TERMINAL_INFO_VERSION_2; /* why is this 1? */
  3130.         s$control (&port, &opcode, &tinfo, &status);
  3131.         if (status)
  3132.         debug(F101,"getenv getting term info status","",status);
  3133.         else
  3134.         strcpy(envbuf, &tinfo.terminal_type_name);
  3135.     }
  3136.  
  3137.     else if (0 == strcmp (str, "HOST")) { /* host name */
  3138. #ifdef TCPSOCKET
  3139.         /* we have the BSD sockets library from OS TCP/IP, */
  3140.         /* so get the real hostname, if it is set. */
  3141.         len = sizeof (envbuf);
  3142.         if (gethostname(envbuf,len) < 0) 
  3143.         strcpy (envbuf, "");
  3144.  
  3145. #endif /* TCPSOCKET */
  3146.         /* if that did not work or if we don't have sockets, get the */
  3147.         /* system name from the name of the current module.  Format  */
  3148.         /* is "%systemname#modulename".  We return the whole thing.  */
  3149.  
  3150.         if (0 == strlen (envbuf)) {
  3151.         /* if 1st arg is empty string, returns current module name */
  3152.         strcpy (&dummy, "");
  3153.         s$expand_module_name (&dummy, &modname, &status);
  3154.         if (status)
  3155.             debug(F101,"getenv exp_mod_name status","",status);
  3156.         else
  3157.             strcpy (envbuf, &modname);
  3158.         }
  3159.     }
  3160.     /* add new ones here */
  3161.     else {
  3162.         debug(F100,"GETENV returns NULL","",0);
  3163.         return NULL;
  3164.     }
  3165.     }
  3166.     debug(F110,"GETENV returns",envbuf,0);
  3167.     return envbuf;
  3168. }
  3169.  
  3170. #undef signal
  3171. #undef alarm
  3172.  
  3173. /* do we really need to know about all the signals? */
  3174.  
  3175. static char *signames[] = {
  3176.     /*  0 */    "SIG-0",    "SIGABRT",    "SIGFPE",    "SIGILL",
  3177.     /*  4 */    "SIGINT",    "SIGSEGV",    "SIGTERM",    "SIGUSR1",
  3178.     /*  8 */    "SIGUSR2",    "SIGIO/POLL",    "SIGHUP",    "SIGURG",
  3179.     /* 12 */    "SIGALRM"
  3180. };
  3181.  
  3182. SIGTYP (*
  3183. #ifdef CK_ANSIC
  3184. vsignal(int type, SIGTYP (*func)(int)))(int){
  3185. #else
  3186. vsignal(type, func))() int type, SIGTYP (*func)(){
  3187. #endif
  3188.     char *cp;
  3189.     cp = (type <= _SIG_MAX && type >= 1) ? signames[type] : "UNKNOWN SIGNAL";
  3190.  
  3191.     debug(F111,"VSIGNAL called",cp,(long) func);
  3192.     return (signal(type,func));
  3193. }
  3194.  
  3195. int 
  3196. #ifdef CK_ANSIC
  3197. valarm(interval) int interval; {
  3198. #else
  3199. valarm(int interval) {
  3200. #endif
  3201.     time_t now;
  3202.     int rv;
  3203.  
  3204.     debug(F101,"VALARM called","",interval);
  3205.     time(&now);
  3206.  
  3207.     /* figure out how much was left.  If there is time left, say
  3208.      * it's at least one second, even if it comes out to zero; this
  3209.      * prevents confusion about what a zero return value means.
  3210.      */
  3211.  
  3212.     if (deadline) {
  3213.     rv = deadline - now;
  3214.     if (rv <= 0) /* may also have missed the deadline */
  3215.         rv = 1;
  3216.     }
  3217.     else
  3218.     rv = 0; /* it wasn't set */
  3219.  
  3220.     /* set the new deadline */
  3221.  
  3222.     if (0 >= interval) /* uh... negative interval (space-like?) */
  3223.     deadline = 0;
  3224.     else
  3225.     deadline = now + interval;
  3226.  
  3227.     return rv;
  3228. }
  3229.  
  3230. int
  3231. chkalarm(void) {
  3232.     time_t now;
  3233.  
  3234.     if (0 == deadline) return 0; /* don't bail out */
  3235.     time(&now);
  3236.     if (now < deadline) return 0; /* strictly less than */
  3237.  
  3238.     /* it's time! */
  3239.     debug(F101,"chkalarm timer expired, age","",now-deadline);
  3240.     kill (0, SIGALRM); /* We don't have raise(), either. */
  3241.  
  3242.     /* most of the alarm handlers longjmp, so we may not get here */
  3243.     return -1;
  3244. }
  3245.