home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckltio.c < prev    next >
C/C++ Source or Header  |  1994-10-28  |  90KB  |  3,162 lines

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