home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / c-client / os_ptx.c < prev    next >
C/C++ Source or Header  |  1994-01-09  |  23KB  |  847 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- PTX version
  3.  *
  4.  * Author:    Donn Cave/Mark Crispin
  5.  *        University Computing Services, JE-30
  6.  *        University of Washington
  7.  *        Seattle, WA 98195
  8.  *        Internet: donn@cac.washington.edu
  9.  *
  10.  * Date:    11 May 1989
  11.  * Last Edited:    11 November 1993
  12.  *
  13.  * Copyright 1993 by the University of Washington
  14.  *
  15.  *  Permission to use, copy, modify, and distribute this software and its
  16.  * documentation for any purpose and without fee is hereby granted, provided
  17.  * that the above copyright notice appears in all copies and that both the
  18.  * above copyright notice and this permission notice appear in supporting
  19.  * documentation, and that the name of the University of Washington not be
  20.  * used in advertising or publicity pertaining to distribution of the software
  21.  * without specific, written prior permission.  This software is made
  22.  * available "as is", and
  23.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  24.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  25.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  26.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  27.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  28.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  29.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  30.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  31.  *
  32.  */
  33.  
  34. /* TCP input buffer */
  35.  
  36. #define BUFLEN 8192
  37.  
  38.  
  39. /* TCP I/O stream (must be before osdep.h is included) */
  40.  
  41. #define TCPSTREAM struct tcp_stream
  42. TCPSTREAM {
  43.   char *host;            /* host name */
  44.   char *localhost;        /* local host name */
  45.   int tcpsi;            /* input socket */
  46.   int tcpso;            /* output socket */
  47.   int ictr;            /* input counter */
  48.   char *iptr;            /* input pointer */
  49.   char ibuf[BUFLEN];        /* input buffer */
  50. };
  51.  
  52.  
  53. #include "osdep.h"
  54. #include <ctype.h>
  55. #include <sys/time.h>
  56. #include <sys/tiuser.h>
  57. #include <stropts.h>
  58. #include <poll.h>
  59. #include <sys/select.h>
  60. #include <netinet/in.h>
  61. #include <netdb.h>
  62. #include <ctype.h>
  63. #include <regexpr.h>
  64. #include <errno.h>
  65. #include <pwd.h>
  66. #include <shadow.h>
  67. #include <syslog.h>
  68. #include <sys/file.h>
  69. #include <sys/stat.h>
  70. #include "mail.h"
  71. #include "misc.h"
  72.  
  73. extern int sys_nerr;
  74. extern char *sys_errlist[];
  75.  
  76. #define toint(c)    ((c)-'0')
  77. #define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  78.  
  79. /* Write current time in RFC 822 format
  80.  * Accepts: destination string
  81.  */
  82.  
  83. char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  84.  
  85. char may_need_server_init = T;
  86.  
  87. void rfc822_date (date)
  88.     char *date;
  89. {
  90.   int zone,dstnow;
  91.   time_t time_sec = time (0);
  92.   struct tm *t = localtime (&time_sec);
  93.   tzset ();            /* initialize timezone/daylight variables */
  94.                 /* see if it is DST now */
  95.   dstnow = daylight && t->tm_isdst;
  96.                 /* get timezone value */
  97.   zone = - (dstnow ? altzone : timezone) / 60;
  98.                 /* and output it */
  99.   sprintf (date,"%s, %d %s %d %02d:%02d:%02d %+03d%02d (%s)",
  100.        days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  101.        t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60,
  102.        tzname[dstnow]);
  103.   if (may_need_server_init) {    /* maybe need to do server init cruft? */
  104.     may_need_server_init = NIL;    /* not any more we don't */
  105.     if (getuid () <= 0) {    /* if root, we're most likely a server */
  106.       t_sync (0);        /* PTX inetd is stupid, stupid, stupid */
  107.       ioctl (0,I_PUSH,"tirdwr");/*  it needs this cruft, else servers won't */
  108.       dup2 (0,1);        /*  work.  How obnoxious!!! */
  109.     }
  110.   }
  111. }
  112.  
  113. /* Get a block of free storage
  114.  * Accepts: size of desired block
  115.  * Returns: free storage block
  116.  */
  117.  
  118. void *fs_get (size)
  119.     size_t size;
  120. {
  121.   void *block = malloc (size);
  122.   if (!block) fatal ("Out of free storage");
  123.   return (block);
  124. }
  125.  
  126.  
  127. /* Resize a block of free storage
  128.  * Accepts: ** pointer to current block
  129.  *        new size
  130.  */
  131.  
  132. void fs_resize (block,size)
  133.     void **block;
  134.     size_t size;
  135. {
  136.   if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
  137. }
  138.  
  139.  
  140. /* Return a block of free storage
  141.  * Accepts: ** pointer to free storage block
  142.  */
  143.  
  144. void fs_give (block)
  145.     void **block;
  146. {
  147.   free (*block);
  148.   *block = NIL;
  149. }
  150.  
  151.  
  152. /* Report a fatal error
  153.  * Accepts: string to output
  154.  */
  155.  
  156. void fatal (string)
  157.     char *string;
  158. {
  159.   mm_fatal (string);        /* output the string */
  160.   syslog (LOG_ALERT,"IMAP C-Client crash: %s",string);
  161.   abort ();            /* die horribly */
  162. }
  163.  
  164. /* Copy string with CRLF newlines
  165.  * Accepts: destination string
  166.  *        pointer to size of destination string
  167.  *        source string
  168.  *        length of source string
  169.  * Returns: length of copied string
  170.  */
  171.  
  172. unsigned long strcrlfcpy (dst,dstl,src,srcl)
  173.     char **dst;
  174.     unsigned long *dstl;
  175.     char *src;
  176.     unsigned long srcl;
  177. {
  178.   long i,j;
  179.   char *d = src;
  180.                 /* count number of LF's in source string(s) */
  181.   for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
  182.   if (i > *dstl) {        /* resize if not enough space */
  183.     fs_give ((void **) dst);    /* fs_resize does an unnecessary copy */
  184.     *dst = (char *) fs_get ((*dstl = i) + 1);
  185.   }
  186.   d = *dst;            /* destination string */
  187.                 /* copy strings, inserting CR's before LF's */
  188.   while (srcl--) switch (*src) {
  189.   case '\015':            /* unlikely carriage return */
  190.     *d++ = *src++;        /* copy it and any succeeding linefeed */
  191.     if (srcl && *src == '\012') {
  192.       *d++ = *src++;
  193.       srcl--;
  194.     }
  195.     break;
  196.   case '\012':            /* line feed? */
  197.     *d++ ='\015';        /* yes, prepend a CR, drop into default case */
  198.   default:            /* ordinary chararacter */
  199.     *d++ = *src++;        /* just copy character */
  200.     break;
  201.   }
  202.   *d = '\0';            /* tie off destination */
  203.   return d - *dst;        /* return length */
  204. }
  205.  
  206.  
  207. /* Length of string after strcrlfcpy applied
  208.  * Accepts: source string
  209.  * Returns: length of string
  210.  */
  211.  
  212. unsigned long strcrlflen (s)
  213.     STRING *s;
  214. {
  215.   unsigned long pos = GETPOS (s);
  216.   unsigned long i = SIZE (s);
  217.   unsigned long j = i;
  218.   while (j--) switch (SNX (s)) {/* search for newlines */
  219.   case '\015':            /* unlikely carriage return */
  220.     if (j && (CHR (s) == '\012')) {
  221.       SNX (s);            /* eat the line feed */
  222.       j--;
  223.     }
  224.     break;
  225.   case '\012':            /* line feed? */
  226.     i++;
  227.   default:            /* ordinary chararacter */
  228.     break;
  229.   }
  230.   SETPOS (s,pos);        /* restore old position */
  231.   return i;
  232. }
  233.  
  234. /* Server log in
  235.  * Accepts: user name string
  236.  *        password string
  237.  *        optional place to return home directory
  238.  * Returns: T if password validated, NIL otherwise
  239.  */
  240.  
  241. long server_login (user,pass,home,argc,argv)
  242.     char *user;
  243.     char *pass;
  244.     char **home;
  245.     int argc;
  246.     char *argv[];
  247. {
  248.   struct passwd *pw = getpwnam (lcase (user));
  249.   struct spwd *sp;
  250.                 /* no entry for this user or root */
  251.   if (!(pw && pw->pw_uid)) return NIL;
  252.                 /* validate password and password aging */
  253.   sp = getspnam (pw->pw_name);
  254.   if (strcmp (sp->sp_pwdp, (char *) crypt (pass,sp->sp_pwdp))) return NIL;
  255.   else if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
  256.        ((sp->sp_lstchg + sp->sp_max) < (time (0) / (60*60*24))))
  257.     return NIL;
  258.   setgid (pw->pw_gid);        /* all OK, login in as that user */
  259.   initgroups (user);        /* initialize groups */
  260.   setuid (pw->pw_uid);
  261.                 /* note home directory */
  262.   if (home) *home = cpystr (pw->pw_dir);
  263.   return T;
  264. }
  265.  
  266. /* Return my user name
  267.  * Returns: my user name
  268.  */
  269.  
  270. char *uname = NIL;
  271.  
  272. char *myusername ()
  273. {
  274.   return uname ? uname : (uname = cpystr (getpwuid (geteuid ())->pw_name));
  275. }
  276.  
  277.  
  278. /* Return my home directory name
  279.  * Returns: my home directory name
  280.  */
  281.  
  282. char *hdname = NIL;
  283.  
  284. char *myhomedir ()
  285. {
  286.   return hdname ? hdname : (hdname = cpystr (getpwuid (geteuid ())->pw_dir));
  287. }
  288.  
  289.  
  290. /* Build status lock file name
  291.  * Accepts: scratch buffer
  292.  *        file name
  293.  * Returns: name of file to lock
  294.  */
  295.  
  296. char *lockname (tmp,fname)
  297.     char *tmp;
  298.     char *fname;
  299. {
  300.   int i;
  301.   sprintf (tmp,"/tmp/.%s",fname);
  302.   for (i = 6; i < strlen (tmp); ++i) if (tmp[i] == '/') tmp[i] = '\\';
  303.   return tmp;            /* note name for later */
  304. }
  305.  
  306. /* TCP/IP open
  307.  * Accepts: host name
  308.  *        contact port number
  309.  * Returns: TCP/IP stream if success else NIL
  310.  */
  311.  
  312. TCPSTREAM *tcp_open (host,port)
  313.     char *host;
  314.     int port;
  315. {
  316.   TCPSTREAM *stream = NIL;
  317.   int sock;
  318.   char *s;
  319.   struct sockaddr_in sin;
  320.   struct hostent *host_name;
  321.   char hostname[MAILTMPLEN];
  322.   char tmp[MAILTMPLEN];
  323.     extern int t_errno;
  324.     extern char *t_errlist[];
  325.     struct t_call *sndcall;
  326.  
  327.   /* The domain literal form is used (rather than simply the dotted decimal
  328.      as with other Unix programs) because it has to be a valid "host name"
  329.      in mailsystem terminology. */
  330.                 /* look like domain literal? */
  331.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  332.     strcpy (hostname,host+1);    /* yes, copy number part */
  333.     hostname[(strlen (hostname))-1] = '\0';
  334.     if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
  335.       sin.sin_family = AF_INET;    /* family is always Internet */
  336.       strcpy (hostname,host);    /* hostname is user's argument */
  337.     }
  338.     else {
  339.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  340.       mm_log (tmp,ERROR);
  341.       return NIL;
  342.     }
  343.   }
  344.  
  345.   else {            /* lookup host name, note that brain-dead Unix
  346.                    requires lowercase! */
  347.     strcpy (hostname,host);    /* in case host is in write-protected memory */
  348.     if ((host_name = gethostbyname (lcase (hostname)))) {
  349.                 /* copy address type */
  350.       sin.sin_family = host_name->h_addrtype;
  351.                 /* copy host name */
  352.       strcpy (hostname,host_name->h_name);
  353.                 /* copy host addresses */
  354.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  355.     }
  356.     else {
  357.       sprintf (tmp,"No such host as %.80s",host);
  358.       mm_log (tmp,ERROR);
  359.       return NIL;
  360.     }
  361.   }
  362.  
  363.                 /* copy port number in network format */
  364.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  365.  
  366.                 /* get a TCP stream */
  367.   t_errno = 0;
  368.   if (((sock = t_open (TLI_TCP, O_RDWR, 0)) < 0) ||
  369.       (t_bind (sock, 0, 0) < 0) ||
  370.       ((sndcall = (struct t_call *) t_alloc (sock, T_CALL, T_ADDR)) == 0))
  371.   {
  372.     sprintf (tmp,"Unable to create TCP socket: %s",t_errlist[t_errno]);
  373.     mm_log (tmp,ERROR);
  374.     return NIL;
  375.   }
  376.                 /* connect to address. */
  377.   sndcall->addr.len = sndcall->addr.maxlen = sizeof (sin);
  378.   sndcall->addr.buf = (char *) &sin;
  379.   sndcall->opt.len = 0;
  380.   sndcall->udata.len = 0;
  381.   if (t_connect (sock, sndcall, 0) < 0) {
  382.     sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
  383.          t_errlist[t_errno]);
  384.     mm_log (tmp,ERROR);
  385.     return NIL;
  386.   }
  387.                 /* push streams module for read()/write(). */
  388.   if (ioctl (sock, I_PUSH, "tirdwr") < 0) {
  389.     sprintf (tmp,"Unable to create TCP socket: %s",t_errlist[t_errno]);
  390.     mm_log (tmp,ERROR);
  391.     return NIL;
  392.   }
  393.                 /* create TCP/IP stream */
  394.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  395.                 /* copy official host name */
  396.   stream->host = cpystr (hostname);
  397.                 /* get local name */
  398.   gethostname (tmp,MAILTMPLEN-1);
  399.   stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
  400.                   host_name->h_name : tmp);
  401.                 /* init sockets */
  402.   stream->tcpsi = stream->tcpso = sock;
  403.   stream->ictr = 0;        /* init input counter */
  404.   return stream;        /* return success */
  405. }
  406.  
  407. /* TCP/IP authenticated open
  408.  * Accepts: host name
  409.  *        service name
  410.  * Returns: TCP/IP stream if success else NIL
  411.  */
  412.  
  413. TCPSTREAM *tcp_aopen (host,service)
  414.     char *host;
  415.     char *service;
  416. {
  417.   TCPSTREAM *stream = NIL;
  418.   struct hostent *host_name;
  419.   char hostname[MAILTMPLEN];
  420.   int i;
  421.   int pipei[2],pipeo[2];
  422.   /* The domain literal form is used (rather than simply the dotted decimal
  423.      as with other Unix programs) because it has to be a valid "host name"
  424.      in mailsystem terminology. */
  425.                 /* look like domain literal? */
  426.   if (host[0] == '[' && host[i = (strlen (host))-1] == ']') {
  427.     strcpy (hostname,host+1);    /* yes, copy without brackets */
  428.     hostname[i-1] = '\0';
  429.   }
  430.                 /* note that Unix requires lowercase! */
  431.   else if (host_name = gethostbyname (lcase (strcpy (hostname,host))))
  432.     strcpy (hostname,host_name->h_name);
  433.                 /* make command pipes */
  434.   if (pipe (pipei) < 0) return NIL;
  435.   if (pipe (pipeo) < 0) {
  436.     close (pipei[0]); close (pipei[1]);
  437.     return NIL;
  438.   }
  439.   if ((i = fork ()) < 0) {    /* make inferior process */
  440.     close (pipei[0]); close (pipei[1]);
  441.     close (pipeo[0]); close (pipeo[1]);
  442.     return NIL;
  443.   }
  444.   if (i) {            /* parent? */
  445.     close (pipei[1]);        /* close child's side of the pipes */
  446.     close (pipeo[0]);
  447.   }
  448.   else {            /* child */
  449.     dup2 (pipei[1],1);        /* parent's input is my output */
  450.     dup2 (pipei[1],2);        /* parent's input is my error output too */
  451.     close (pipei[0]); close (pipei[1]);
  452.     dup2 (pipeo[0],0);        /* parent's output is my input */
  453.     close (pipeo[0]); close (pipeo[1]);
  454.                 /* now run it */
  455.     execl (RSHPATH,RSH,hostname,"exec",service,0);
  456.     _exit (1);            /* spazzed */
  457.   }
  458.  
  459.                 /* create TCP/IP stream */
  460.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  461.                 /* copy official host name */
  462.   stream->host = cpystr (hostname);
  463.                 /* get local name */
  464.   gethostname (hostname,MAILTMPLEN-1);
  465.   stream->localhost = cpystr ((host_name = gethostbyname (hostname)) ?
  466.                   host_name->h_name : hostname);
  467.   stream->tcpsi = pipei[0];    /* init sockets */
  468.   stream->tcpso = pipeo[1];
  469.   stream->ictr = 0;        /* init input counter */
  470.   return stream;        /* return success */
  471. }
  472.  
  473. /* TCP/IP receive line
  474.  * Accepts: TCP/IP stream
  475.  * Returns: text line string or NIL if failure
  476.  */
  477.  
  478. char *tcp_getline (stream)
  479.     TCPSTREAM *stream;
  480. {
  481.   int n,m;
  482.   char *st,*ret,*stp;
  483.   char c = '\0';
  484.   char d;
  485.                 /* make sure have data */
  486.   if (!tcp_getdata (stream)) return NIL;
  487.   st = stream->iptr;        /* save start of string */
  488.   n = 0;            /* init string count */
  489.   while (stream->ictr--) {    /* look for end of line */
  490.     d = *stream->iptr++;    /* slurp another character */
  491.     if ((c == '\015') && (d == '\012')) {
  492.       ret = (char *) fs_get (n--);
  493.       memcpy (ret,st,n);    /* copy into a free storage string */
  494.       ret[n] = '\0';        /* tie off string with null */
  495.       return ret;
  496.     }
  497.     n++;            /* count another character searched */
  498.     c = d;            /* remember previous character */
  499.   }
  500.                 /* copy partial string from buffer */
  501.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  502.                 /* get more data from the net */
  503.   if (!tcp_getdata (stream)) return NIL;
  504.                 /* special case of newline broken by buffer */
  505.   if ((c == '\015') && (*stream->iptr == '\012')) {
  506.     stream->iptr++;        /* eat the line feed */
  507.     stream->ictr--;
  508.     ret[n - 1] = '\0';        /* tie off string with null */
  509.   }
  510.                 /* else recurse to get remainder */
  511.   else if (st = tcp_getline (stream)) {
  512.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  513.     memcpy (ret,stp,n);        /* copy first part */
  514.     memcpy (ret + n,st,m);    /* and second part */
  515.     fs_give ((void **) &stp);    /* flush first part */
  516.     fs_give ((void **) &st);    /* flush second part */
  517.     ret[n + m] = '\0';        /* tie off string with null */
  518.   }
  519.   return ret;
  520. }
  521.  
  522. /* TCP/IP receive buffer
  523.  * Accepts: TCP/IP stream
  524.  *        size in bytes
  525.  *        buffer to read into
  526.  * Returns: T if success, NIL otherwise
  527.  */
  528.  
  529. long tcp_getbuffer (stream,size,buffer)
  530.     TCPSTREAM *stream;
  531.     unsigned long size;
  532.     char *buffer;
  533. {
  534.   unsigned long n;
  535.   char *bufptr = buffer;
  536.   while (size > 0) {        /* until request satisfied */
  537.     if (!tcp_getdata (stream)) return NIL;
  538.     n = min (size,stream->ictr);/* number of bytes to transfer */
  539.                 /* do the copy */
  540.     memcpy (bufptr,stream->iptr,n);
  541.     bufptr += n;        /* update pointer */
  542.     stream->iptr +=n;
  543.     size -= n;            /* update # of bytes to do */
  544.     stream->ictr -=n;
  545.   }
  546.   bufptr[0] = '\0';        /* tie off string */
  547.   return T;
  548. }
  549.  
  550.  
  551.  
  552. long tcp_abort ();
  553.  
  554. /* TCP/IP receive data
  555.  * Accepts: TCP/IP stream
  556.  * Returns: T if success, NIL otherwise
  557.  */
  558.  
  559. long tcp_getdata (stream)
  560.     TCPSTREAM *stream;
  561. {
  562.   int i;
  563.   fd_set fds;
  564.   FD_ZERO (&fds);        /* initialize selection vector */
  565.   if (stream->tcpsi < 0) return NIL;
  566.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  567.     FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
  568.     errno = NIL;        /* block and read */
  569.     while (((i = select (stream->tcpsi+1,&fds,0,0,0)) < 0) &&
  570.        (errno == EINTR));
  571.     if (i < 0) return tcp_abort (stream);
  572.     while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1) &&
  573.        (errno == EINTR));
  574.     if (i < 1) return tcp_abort (stream);
  575.     stream->ictr = i;        /* set new byte count */
  576.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  577.   }
  578.   return T;
  579. }
  580.  
  581. /* TCP/IP send string as record
  582.  * Accepts: TCP/IP stream
  583.  *        string pointer
  584.  * Returns: T if success else NIL
  585.  */
  586.  
  587. long tcp_soutr (stream,string)
  588.     TCPSTREAM *stream;
  589.     char *string;
  590. {
  591.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  592. }
  593.  
  594.  
  595. /* TCP/IP send string
  596.  * Accepts: TCP/IP stream
  597.  *        string pointer
  598.  *        byte count
  599.  * Returns: T if success else NIL
  600.  */
  601.  
  602. long tcp_sout (stream,string,size)
  603.     TCPSTREAM *stream;
  604.     char *string;
  605.     unsigned long size;
  606. {
  607.   int i;
  608.   fd_set fds;
  609.   FD_ZERO (&fds);        /* initialize selection vector */
  610.   if (stream->tcpso < 0) return NIL;
  611.   while (size > 0) {        /* until request satisfied */
  612.     FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
  613.     errno = NIL;        /* block and wrtie */
  614.     while (((i = select (stream->tcpso+1,0,&fds,0,0)) < 0) &&
  615.        (errno == EINTR));
  616.     if (i < 0) return tcp_abort (stream);
  617.     while (((i = write (stream->tcpso,string,size)) < 0) &&
  618.        (errno == EINTR));
  619.     if (i < 0) return tcp_abort (stream);
  620.     size -= i;            /* how much we sent */
  621.     string += i;
  622.   }
  623.   return T;            /* all done */
  624. }
  625.  
  626. /* TCP/IP close
  627.  * Accepts: TCP/IP stream
  628.  */
  629.  
  630. void tcp_close (stream)
  631.     TCPSTREAM *stream;
  632. {
  633.   tcp_abort (stream);        /* nuke the stream */
  634.                 /* flush host names */
  635.   fs_give ((void **) &stream->host);
  636.   fs_give ((void **) &stream->localhost);
  637.   fs_give ((void **) &stream);    /* flush the stream */
  638. }
  639.  
  640.  
  641. /* TCP/IP abort stream
  642.  * Accepts: TCP/IP stream
  643.  * Returns: NIL always
  644.  */
  645.  
  646. long tcp_abort (stream)
  647.      TCPSTREAM *stream;
  648. {
  649.   if (stream->tcpsi >= 0) {    /* no-op if no socket */
  650.     close (stream->tcpsi);    /* nuke the socket */
  651.     if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  652.     stream->tcpsi = stream->tcpso = -1;
  653.   }
  654.   return NIL;
  655. }
  656.  
  657. /* TCP/IP get host name
  658.  * Accepts: TCP/IP stream
  659.  * Returns: host name for this stream
  660.  */
  661.  
  662. char *tcp_host (stream)
  663.     TCPSTREAM *stream;
  664. {
  665.   return stream->host;        /* return host name */
  666. }
  667.  
  668.  
  669. /* TCP/IP get local host name
  670.  * Accepts: TCP/IP stream
  671.  * Returns: local host name
  672.  */
  673.  
  674. char *tcp_localhost (stream)
  675.     TCPSTREAM *stream;
  676. {
  677.   return stream->localhost;    /* return local host name */
  678. }
  679.  
  680. /* Emulator for BSD gethostid() call
  681.  * Returns: unique identifier for this machine
  682.  */
  683.  
  684. long gethostid ()
  685. {
  686.   struct sockaddr_in sin;
  687.   int inet = t_open (TLI_TCP, O_RDWR, 0);
  688.   if (inet < 0) return 0;
  689.   getmyinaddr (inet,&sin,sizeof (sin));
  690.   close (inet);
  691.   return sin.sin_addr.s_addr;
  692. }
  693.  
  694.  
  695. /* Emulator for BSD random() call
  696.  * Returns: long random number
  697.  */
  698.  
  699. long random ()
  700. {
  701.   static int beenhere = 0;
  702.   if (!beenhere) {
  703.     beenhere = 1;
  704.     srand48 (getpid ());
  705.   }
  706.   return lrand48 ();
  707. }
  708.  
  709.  
  710. /* Copy memory block
  711.  * Accepts: destination pointer
  712.  *        source pointer
  713.  *        length
  714.  * Returns: destination pointer
  715.  */
  716.  
  717. void *memmove (s,ct,n)
  718.     void *s;
  719.     void *ct;
  720.     int n;
  721. {
  722.   char *dp, *sp;
  723.   int i;
  724.   unsigned long dest = (unsigned long) s;
  725.   unsigned long src = (unsigned long) ct;
  726.   if (((dest < src) && ((dest + n) < src)) ||
  727.       ((dest > src) && ((src + n) < dest))) return memcpy (s, ct, n);
  728.   dp = s;
  729.   sp = ct;
  730.   if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
  731.   else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
  732.   return s;
  733. }
  734.  
  735. /* Emulator for BSD scandir() call
  736.  * Accepts: directory name
  737.  *        destination pointer of names array
  738.  *        selection function
  739.  *        comparison function
  740.  * Returns: number of elements in the array or -1 if error
  741.  */
  742.  
  743. #define DIRSIZ(d) d->d_reclen
  744.  
  745. int scandir (dirname,namelist,select,compar)
  746.     char *dirname;
  747.     struct dirent ***namelist;
  748.     int (*select) ();
  749.     int (*compar) ();
  750. {
  751.   struct dirent *p,*d,**names;
  752.   int nitems;
  753.   struct stat stb;
  754.   long nlmax;
  755.   DIR *dirp = opendir (dirname);/* open directory and get status poop */
  756.   if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
  757.   nlmax = stb.st_size / 24;    /* guesstimate at number of files */
  758.   names = (struct dirent **) fs_get (nlmax * sizeof (struct dirent *));
  759.   nitems = 0;            /* initially none found */
  760.   while (d = readdir (dirp)) {    /* read directory item */
  761.                 /* matches select criterion? */
  762.     if (select && !(*select) (d)) continue;
  763.                 /* get size of dirent record for this file */
  764.     p = (struct dirent *) fs_get (DIRSIZ (d));
  765.     p->d_ino = d->d_ino;    /* copy the poop */
  766.     p->d_off = d->d_off;
  767.     p->d_reclen = d->d_reclen;
  768.     strcpy (p->d_name,d->d_name);
  769.     if (++nitems >= nlmax) {    /* if out of space, try bigger guesstimate */
  770.       nlmax *= 2;        /* double it */
  771.       fs_resize ((void **) names,nlmax * sizeof (struct dirent *));
  772.     }
  773.     names[nitems - 1] = p;    /* store this file there */
  774.   }
  775.   closedir (dirp);        /* done with directory */
  776.                 /* sort if necessary */
  777.   if (nitems && compar) qsort (names,nitems,sizeof (struct dirent *),compar);
  778.   *namelist = names;        /* return directory */
  779.   return nitems;        /* and size */
  780. }
  781.  
  782. /* Emulator for BSD flock() call
  783.  * Accepts: file descriptor
  784.  *        operation bitmask
  785.  * Returns: 0 if successful, -1 if failure
  786.  * Note: this emulator does not handle shared locks
  787.  */
  788.  
  789. int flock (fd, operation)
  790.     int fd;
  791.     int operation;
  792. {
  793.   int func;
  794.   off_t offset = lseek (fd,0,L_INCR);
  795.   switch (operation & ~LOCK_NB){/* translate to lockf() operation */
  796.   case LOCK_EX:            /* exclusive */
  797.   case LOCK_SH:            /* shared */
  798.     func = (operation & LOCK_NB) ? F_TLOCK : F_LOCK;
  799.     break;
  800.   case LOCK_UN:            /* unlock */
  801.     func = F_ULOCK;
  802.     break;
  803.   default:            /* default */
  804.     errno = EINVAL;
  805.     return -1;
  806.   }
  807.   lseek (fd,0,L_SET);        /* position to start of the file */
  808.   func = lockf (fd,func,0);    /* do the lockf() */
  809.   lseek (fd,offset,L_SET);    /* restore prior position */
  810.   return func;
  811. }
  812.  
  813.  
  814. /* Emulator for BSD gettimeofday() call
  815.  * Accepts: address where to write timeval information
  816.  *        address where to write timezone information
  817.  * Returns: 0 if successful, -1 if failure
  818.  */
  819.  
  820. int gettimeofday (tp,tzp)
  821.     struct timeval *tp;
  822.     struct timezone *tzp;
  823. {
  824.   tp->tv_sec = time (0);    /* time since 1-Jan-70 00:00:00 GMT in secs */
  825.                 /* others aren't used in current code */
  826.   if (tzp) tzp->tz_minuteswest = tzp->tz_dsttime = 0;
  827.   tp->tv_usec = 0;
  828.   return 0;
  829. }
  830.  
  831.  
  832. /* Emulator for BSD utimes() call
  833.  * Accepts: file name
  834.  *        timeval vector for access and updated time
  835.  * Returns: 0 if successful, -1 if failure
  836.  */
  837.  
  838. int utimes (file,tvp)
  839.     char *file;
  840.     struct timeval tvp[2];
  841. {
  842.   struct utimbuf tb;
  843.   tb.actime = tvp[0].tv_sec;    /* accessed time */
  844.   tb.modtime = tvp[1].tv_sec;    /* updated time */
  845.   return utime (file,&tb);
  846. }
  847.