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