[comp.sources.misc] v08i015: comsat and biff for System V with a FIFO

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/25/89)

Posting-number: Volume 8, Issue 15
Submitted-by: edf@ROCKY2.ROCKEFELLER.EDU (David MacKenzie)
Archive-name: comsat.s5

This is a port of the free comsat program from the 4.3BSD-tahoe release
to System V, with a FIFO (named pipe) replacing sockets.

When a new mail message is delivered, the local mail delivery agent
writes a message to a FIFO, which the comsat daemon reads.  If the
recipient of the mail is logged in and `biff y' (similar to mesg y but a
different bit of the tty is used), a message is printed on the user's
screen summarizing the new mail.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README comsat.c biff.c lmail.diffs mailwrap.c
# Wrapped by dave@edfdc on Wed Aug 23 01:34:53 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1518 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is a port of the free comsat program from the 4.3BSD-tahoe release
Xto System V, with a FIFO (named pipe) replacing sockets.
X
XWhen a new mail message is delivered, the local mail delivery agent
Xwrites a message (for the format, see the comment at the top of
Xcomsat.c) to a FIFO, which the comsat daemon reads.  If the recipient
Xof the mail is logged in and `biff y' (similar to mesg y but a
Xdifferent bit of the tty is used), a message is printed on the user's
Xscreen summarizing the new mail.
X
XFiles included in this package:
X
XREADME		This file.
Xcomsat.c	Daemon that prints the biff messages.
Xbiff.c		Allow/prevent receipt of biff messages.
Xlmail.diffs	Diffs to lmail from comp.sources.misc volume 4, a local
X		mail delivery program for smail 2.5, to make it write a
X		message to the comsat FIFO when new mail is delivered.
Xmailwrap.c	An alternative approach to using lmail; a program to
X		write a message to the comsat FIFO, then run your old,
X		renamed local mail delivery program.
X		Written by Jim Mattson <mattson%cs@ucsd.edu>.
X
XFollowing is a list of the main portability issues I encountered while
Xporting comsat from 4.3BSD to System V.  In addition to these, I added
Xmore comments and gave some identifiers more descriptive names, and ran
Xthe file through GNU indent.
X
Xsignals
Xsockets vs. FIFO
Xinvocation and exit
Xerror logging
Xindex vs. strchr
Xsgtty vs. termio
Xgethostname vs. uname
Xfailure of interrupted system calls (fgets seems to handle this correctly)
X
XDavid MacKenzie
X<edf@rocky2.rockefeller.edu>
END_OF_FILE
if test 1518 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'comsat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'comsat.c'\"
else
echo shar: Extracting \"'comsat.c'\" \(11659 characters\)
sed "s/^X//" >'comsat.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1980 Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X/* comsat - daemon to notify registered users of new mail
X   Usage: comsat 2> /tmp/comsat.errors
X
X   Receives one line messages of the form
X   user@mailbox-offset\n
X   on a named pipe, and if the user is logged on and "biff y" (owner
X   execute bit of tty is turned on), prints a message summarizing the new
X   mail on the user's screen.
X
X   Converted for System V with FIFO
X   by David MacKenzie <edf@rocky2.rockefeller.edu>
X   with additional changes
X   by Jim Mattson <mattson%cs@ucsd.edu>
X
X   Latest revision: 08/23/89 */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <utmp.h>
X#include <signal.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <termio.h>
X#include <string.h>
X#include <varargs.h>
X#include <sys/utsname.h>
X
X/* BSD-compatible constants for lseek. */
X#define L_SET 0
X#define L_INCR 1
X#define L_XTND 2
X
X/* The directory where system mailboxes are located. */
X#define SYSMAILDIR "/usr/mail"
X
X/* Path of the named pipe used to send messages to this program. */
X#define FIFO "/etc/comsat.fifo"
X
X/* The number of seconds between checks of the utmp. */
X#define ALARM_INTERVAL 15
X
X/* If this is defined, no blank line will be printed between the
X   header lines (e.g., "Subject:") and the head of the message text.
X   The blank line is present in the 4.3BSD comsat but absent in the
X   4.3BSD-tahoe comsat from which this version is derived. */
X/* #define JOIN_HEADER_AND_TEXT */
X
Xchar *malloc ();
Xchar *realloc ();
Xoff_t atol ();
Xoff_t fseek ();
Xoff_t lseek ();
Xtime_t time ();
X
Xchar *xmalloc ();
Xchar *xrealloc ();
Xint read_utmp ();
Xint note_alarm ();
Xvoid mail_for ();
Xvoid msg_perror_fatal ();
Xvoid notify ();
Xvoid summarize_new_mail ();
X
X/* This machine's host name, used in the notification message. */
Xchar hostname[10];
X
X/* Contents of the utmp. */
Xstruct utmp *utmp;
X
X/* If nonzero, the alarm rang while sending a biff message. */
Xint alarm_rang;
X
X/* Number of entries in `utmp'. */
Xint nutmp;
X
X/* File descriptor for reading the utmp. */
Xint utfd;
X
X/* The name this program was run with, for error messages. */
Xchar *program_name;
X
X/* ARGSUSED */
Xint
Xmain (argc, argv)
X     int argc;
X     char **argv;
X{
X  FILE *fifp;
X  char msgbuf[100];
X
X  program_name = argv[0];
X
X  signal (SIGINT, SIG_IGN);
X  signal (SIGHUP, SIG_IGN);
X
X  /* Don't tie up a filesystem. */
X  if (chdir ("/") == -1)
X    msg_perror_fatal ("Cannot chdir to /");
X
X  if (daemon_running (FIFO))
X    {
X      fprintf (stderr, "%s: Daemon is already running\n", program_name);
X      exit (1);
X    }
X  switch (fork ())
X    {
X    case -1:
X      msg_perror_fatal ("Cannot fork");
X    case 0:			/* Child. */
X      break;
X    default:			/* Parent. */
X      _exit (0);
X    }
X
X  fclose (stdin);		/* Don't need these anymore. */
X  fclose (stdout);
X  setpgrp ();			/* Detach from parent's process group. */
X
X  fifp = fdopen (open_fifo (FIFO), "r");
X  if (fifp == NULL)
X    msg_perror_fatal ("Cannot fdopen FIFO %s", FIFO);
X
X  utfd = open (UTMP_FILE, O_RDONLY);
X  if (utfd == -1)
X    msg_perror_fatal ("Cannot read %s", UTMP_FILE);
X
X  utmp = NULL;
X  nutmp = 0;
X  gethostname (hostname, sizeof (hostname));
X  signal (SIGCLD, SIG_IGN);	/* Prevent zombie process creation. */
X
X  read_utmp ();
X
X  while (1)
X    {
X      while (fgets (msgbuf, sizeof msgbuf, fifp) == NULL)
X	sleep (1);
X      if (nutmp == 0)
X	continue;		/* No one has logged in yet. */
X      /* Don't let automatic utmp updating corrupt the in-core copy while
X         we're using it. */
X      alarm_rang = 0;
X      signal (SIGALRM, note_alarm);
X      mail_for (msgbuf);
X      /* If we missed a utmp update while biffing the user, do the
X         update manually and set the alarm again. */
X      if (alarm_rang)
X	read_utmp ();
X      else
X	signal (SIGALRM, read_utmp);
X    }
X  /* NOTREACHED */
X}
X
X/* SIGALRM handler for while mail_for is running. */
X
Xint
Xnote_alarm ()
X{
X  alarm_rang = 1;
X}
X
X/* Normal SIGALRM handler.  Every ALARM_INTERVAL seconds, read a current
X   copy of the utmp into `utmp'. */
X
Xint
Xread_utmp ()
X{
X  static unsigned utmp_size = 0;/* Bytes allocated for `utmp'. */
X  static unsigned utmp_mtime = 0;	/* Last modification time of utmp. */
X  struct stat stats;
X
X  if (fstat (utfd, &stats) == -1)
X    msg_perror_fatal ("Cannot fstat utmp");
X  if (stats.st_mtime > utmp_mtime)
X    {
X      utmp_mtime = stats.st_mtime;
X      if (stats.st_size > utmp_size)
X	{
X	  utmp_size = stats.st_size + 10 * sizeof (struct utmp);
X	  utmp = (struct utmp *) xrealloc ((char *) utmp, utmp_size);
X	}
X      if (lseek (utfd, 0L, L_SET) < 0)
X	msg_perror_fatal ("Cannot seek to beginning of utmp");
X      nutmp = read (utfd, utmp, (unsigned) stats.st_size);
X      if (nutmp == -1)
X	msg_perror_fatal ("Cannot read utmp");
X      nutmp /= sizeof (struct utmp);
X    }
X  alarm ((unsigned) ALARM_INTERVAL);
X  signal (SIGALRM, read_utmp);
X}
X
X/* `name' has the form "user@mailbox-offset\n".  Check whether "user" is
X   logged on; if so, try to notify them of the new mail. */
X
Xvoid
Xmail_for (name)
X     char *name;
X{
X  struct utmp *utp;
X  char *cp;
X  off_t offset;
X
X  cp = strchr (name, '@');
X  if (cp == NULL)
X    {
X      fprintf (stderr, "%s: Invalid message: %s\n", program_name, name);
X      return;
X    }
X  *cp++ = '\0';
X  offset = atol (cp);
X  utp = &utmp[nutmp];
X  while (--utp >= utmp)
X    {
X      if (!strncmp (utp->ut_user, name, sizeof (utmp[0].ut_user)))
X	notify (utp, offset);
X    }
X}
X
X/* The carriage return character needed for the terminal being notified;
X   it will be the null string if the terminal driver or the terminal
X   is supplying a carriage return automatically with each newline. */
Xstatic char *cr;
X
X/* If the user described in `utp' is logged on and "biff y", notify them
X   of the new mail in their system mailbox at offset `offset'. */
X
Xvoid
Xnotify (utp, offset)
X     struct utmp *utp;
X     off_t offset;
X{
X  static char tty[20] = "/dev/";
X  struct termio termio;
X  FILE *tp;
X  char name[sizeof (utmp[0].ut_user) + 1];
X  struct stat stats;
X  int i;
X
X  strncpy (tty + 5, utp->ut_line, sizeof (utp->ut_line));
X  while ((i = stat (tty, &stats)) == -1 && errno == EINTR)
X    /* Do nothing. */ ;
X  if (i == -1 || !(stats.st_mode & S_IEXEC))
X    return;
X  switch (fork ())
X    {
X    case -1:
X      msg_perror_fatal ("Cannot fork");
X    case 0:			/* Child. */
X      break;
X    default:			/* Parent. */
X      return;
X    }
X  signal (SIGALRM, SIG_DFL);
X  alarm ((unsigned) 30);
X  tp = fopen (tty, "w");
X  if (tp == NULL)
X    _exit (1);
X  ioctl (fileno (tp), TCGETA, &termio);
X  cr = (termio.c_oflag & OPOST) && (termio.c_oflag & ONLCR)
X    || (termio.c_oflag & ONLRET) ? "" : "\r";
X  strncpy (name, utp->ut_user, sizeof (utp->ut_user));
X  name[sizeof (name) - 1] = '\0';
X  fprintf (tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n----%s\n",
X	   cr, name, sizeof (hostname), hostname, cr, cr);
X  summarize_new_mail (tp, name, offset);
X  fclose (tp);
X  _exit (0);
X}
X
X/* Print the first 7 lines or 560 characters (whichever comes first) of
X   the new mail message that starts at byte `offset' in the system
X   mailbox for user `name' to stream `tp'.  Skip header lines other than
X   From, Subject, [To, and Date]. */
X
Xvoid
Xsummarize_new_mail (tp, name, offset)
X     FILE *tp;
X     char *name;
X     off_t offset;
X{
X  char *cp;
X  FILE *fi;
X  int linecnt;
X  int charcnt;
X  int inheader;
X  char line[BUFSIZ];
X
X  cp = xmalloc (sizeof (SYSMAILDIR) + strlen (name) + 2);
X  sprintf (cp, "%s/%s", SYSMAILDIR, name);
X  fi = fopen (cp, "r");
X  free (cp);
X  if (fi == NULL)
X    return;
X  if (fseek (fi, offset, L_SET))
X    return;
X  linecnt = 7;
X  charcnt = 560;
X  inheader = 1;
X
X  while (fgets (line, sizeof (line), fi) != NULL)
X    {
X      if (inheader)
X	{
X	  if (line[0] == '\n')
X	    {
X	      inheader = 0;
X#ifdef JOIN_HEADER_AND_TEXT
X	      continue;
X#endif
X	    }
X	  else if (line[0] == ' ' || line[0] == '\t'
X		   || strncmp (line, "From:", 5)
X		   && strncmp (line, "Subject:", 8))
X	    /* Skip header continuation lines and non-essential header lines. */
X	    continue;
X	}
X      if (linecnt <= 0 || charcnt <= 0)
X	{
X	  fprintf (tp, "...more...%s\n", cr);
X	  return;
X	}
X      cp = strchr (line, '\n');
X      if (cp)
X	*cp = '\0';
X      fprintf (tp, "%s%s\n", line, cr);
X      charcnt -= strlen (line);
X      linecnt--;
X    }
X  fprintf (tp, "----%s\n", cr);
X}
X
X/* Simulate the BSD gethostname(2) system call on System V.  */
X
Xint
Xgethostname (name, length)
X     char *name;
X     int length;
X{
X  struct utsname uts;
X
X  if (uname (&uts) < 0)
X    return -1;
X  strncpy (name, uts.nodename, length);
X  return 0;
X}
X
Xstatic void
Xmemory_out ()
X{
X  fprintf (stderr, "%s: Virtual memory exhausted\n", program_name);
X  exit (1);
X}
X
X/* Allocate `n' bytes of memory dynamically, with error checking.  */
X
Xchar *
Xxmalloc (n)
X     unsigned n;
X{
X  char *p;
X
X  p = malloc (n);
X  if (p == 0)
X    memory_out ();
X  return p;
X}
X
X/* Change the size of an allocated block of memory `p' to `n' bytes,
X   with error checking.
X   If `p' is NULL, run xmalloc.
X   If `n' is 0, run free and return NULL.  */
X
Xchar *
Xxrealloc (p, n)
X     char *p;
X     unsigned n;
X{
X  if (p == 0)
X    return xmalloc (n);
X  if (n == 0)
X    {
X      free (p);
X      return 0;
X    }
X  p = realloc (p, n);
X  if (p == 0)
X    memory_out ();
X  return p;
X}
X
X/* ANSI C function. */
X
Xchar *
Xstrerror (n)
X     int n;
X{
X  extern char *sys_errlist[];
X  extern int sys_nerr;
X
X  return n >= 0 && n < sys_nerr ? sys_errlist[n] : "Unknown error";
X}
X
X/* Print "program_name: str_and_optional_args: perror_message" on stderr,
X   then exit with error status. */
X/* VARARGS */
Xvoid
Xmsg_perror_fatal (str, va_alist)
X     char *str;
X     va_dcl
X{
X  va_list args;
X  extern int errno;
X  int save_errno;
X
X  save_errno = errno;
X  fprintf (stderr, "%s: ", program_name);
X  va_start (args);
X  vfprintf (stderr, str, args);
X  va_end (args);
X  fprintf (stderr, ": %s\n", strerror (save_errno));
X  exit (1);
X}
X
X/* Open `path' for reading as a mode 0600 FIFO, creating it if necessary.
X   Return the file descriptor. */
X
Xint
Xopen_fifo (path)
X     char *path;
X{
X  int fifd;
X
X  if (mknod (path, 010600, 0) == -1 && errno != EEXIST)
X    msg_perror_fatal ("Cannot create FIFO %s", path);
X  if (chmod (path, 0600))
X    msg_perror_fatal ("Cannot change mode of FIFO %s", path);
X  while ((fifd = open (path, O_RDONLY | O_TRUNC)) == -1 && errno == EINTR)
X     /* Do nothing. */ ;
X  if (fifd == -1)
X    msg_perror_fatal ("Cannot open FIFO %s for reading", path);
X  return fifd;
X}
X
X/* Return nonzero if there is another process already reading `fifo'.
X   If there isn't, open will fail with EPIPE (write on broken pipe). */
X
Xint
Xdaemon_running (fifo)
X     char *fifo;
X{
X  int fifd;
X
X  fifd = open (fifo, O_WRONLY | O_NDELAY);
X  if (fifd == -1)
X    return 0;
X  else
X    {
X      close (fifd);
X      return 1;
X    }
X}
END_OF_FILE
if test 11659 -ne `wc -c <'comsat.c'`; then
    echo shar: \"'comsat.c'\" unpacked with wrong size!
fi
# end of 'comsat.c'
fi
if test -f 'biff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'biff.c'\"
else
echo shar: Extracting \"'biff.c'\" \(2171 characters\)
sed "s/^X//" >'biff.c' <<'END_OF_FILE'
X/* biff - accept or refuse new mail messages from comsat
X
X   Usage: biff [yn]
X
X   David MacKenzie
X   public domain
X   Latest revision: 08/19/89 */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <varargs.h>
X
Xchar *ttyname ();
X
Xchar *any_ttyname ();
Xvoid msg_perror_fatal ();
Xvoid usage ();
X
Xchar *program_name;
X
Xint
Xmain (argc, argv)
X     int argc;
X     char **argv;
X{
X  struct stat stats;
X  char *tty;
X
X  program_name = argv[0];
X  tty = any_ttyname ();
X  if (tty == NULL)
X    {
X      fprintf (stderr, "%s: Not connected to a terminal\n", argv[0]);
X      exit (1);
X    }
X  if (stat (tty, &stats) == -1)
X    msg_perror_fatal ("Cannot stat %s", tty);
X  switch (argc)
X    {
X    case 1:
X      printf ("is %c\n", (stats.st_mode & S_IEXEC) ? 'y' : 'n');
X      break;
X    case 2:
X      if (*argv[1] == '-')
X	++argv[1];		/* Allow '-y' or 'y'. */
X      switch (*argv[1])
X	{
X	case 'y':
X	  if (chmod (tty, stats.st_mode | S_IEXEC) == -1)
X	    msg_perror_fatal ("Cannot change mode of %s", tty);
X	  break;
X	case 'n':
X	  if (chmod (tty, stats.st_mode & ~S_IEXEC) == -1)
X	    msg_perror_fatal ("Cannot change mode of %s", tty);
X	  break;
X	default:
X	  usage ();
X	}
X      break;
X    default:
X      usage ();
X    }
X  exit (0);
X  /* NOTREACHED */
X}
X
Xchar *
Xany_ttyname ()
X{
X  char *tty;
X
X  tty = ttyname (2);
X  if (tty)
X    return tty;
X  tty = ttyname (1);
X  if (tty)
X    return tty;
X  tty = ttyname (0);
X  if (tty)
X    return tty;
X  return NULL;
X}
X
X/* ANSI C function. */
X
Xchar *
Xstrerror (n)
X     int n;
X{
X  extern char *sys_errlist[];
X  extern int sys_nerr;
X
X  return n >= 0 && n < sys_nerr ? sys_errlist[n] : "Unknown error";
X}
X
X/* Print "program_name: str_and_optional_args: perror_message" on stderr,
X   then exit with error status. */
X/* VARARGS */
Xvoid
Xmsg_perror_fatal (str, va_alist)
X     char *str;
X     va_dcl
X{
X  va_list args;
X  extern int errno;
X  int save_errno;
X
X  save_errno = errno;
X  fprintf (stderr, "%s: ", program_name);
X  va_start (args);
X  vfprintf (stderr, str, args);
X  va_end (args);
X  fprintf (stderr, ": %s\n", strerror (save_errno));
X  exit (1);
X}
X
Xvoid
Xusage ()
X{
X  fprintf (stderr, "Usage: %s [yn]\n", program_name);
X  exit (1);
X}
END_OF_FILE
if test 2171 -ne `wc -c <'biff.c'`; then
    echo shar: \"'biff.c'\" unpacked with wrong size!
fi
# end of 'biff.c'
fi
if test -f 'lmail.diffs' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lmail.diffs'\"
else
echo shar: Extracting \"'lmail.diffs'\" \(1782 characters\)
sed "s/^X//" >'lmail.diffs' <<'END_OF_FILE'
X*** lmail.c.dist	Tue Aug 15 03:34:47 1989
X--- lmail.c	Wed Aug 16 02:30:06 1989
X***************
X*** 527,532 ****
X--- 527,533 ----
X  						return(8);
X  					}
X  				} else {
X+ 					long where = -1, ftell ();
X  					setgid(MAILGID);
X  					setuid(pwd_mailman->pw_uid);	/* give up root uid */
X  					sprintf(temp, "%s%s", MAIL_DIR, dest);
X***************
X*** 535,542 ****
X  					if ((outfile = fopen(temp, "a")) == NULL) {
X  						(void) fprintf(stderr, "** Can't open user mail file %s\n", temp);
X  						status = 5;
X! 					} else
X  						copy(outfile, in_fd, author);
X  					chown(temp, (int)pwd->pw_uid, MAILGID);
X  					if (fclose(outfile)) {
X  						(void) fprintf(stderr, "** Could not close mail file %s\n", temp);
X--- 536,545 ----
X  					if ((outfile = fopen(temp, "a")) == NULL) {
X  						(void) fprintf(stderr, "** Can't open user mail file %s\n", temp);
X  						status = 5;
X! 					} else {
X! 						where = ftell(outfile);
X  						copy(outfile, in_fd, author);
X+ 					}
X  					chown(temp, (int)pwd->pw_uid, MAILGID);
X  					if (fclose(outfile)) {
X  						(void) fprintf(stderr, "** Could not close mail file %s\n", temp);
X***************
X*** 543,548 ****
X--- 546,553 ----
X  						status = 7;
X  					}
X  					unlock(temp);
X+ 					if (where != -1)
X+ 						biff(dest, where);
X  					_exit(status);
X  				}
X  			}
X***************
X*** 626,629 ****
X--- 631,651 ----
X  	return;
X  }
X  
X+ #include <fcntl.h>
X+ 
X+ /* Do our best to biff the recipient.  Errors don't bother us. */
X  
X+ biff (user, offset)
X+      char *user;
X+      long offset;
X+ {
X+   int fd;
X+   char biffbuf[30];
X+ 
X+   fd = open ("/etc/comsat.fifo", O_WRONLY | O_NDELAY);
X+   if (fd == -1)
X+     return;
X+   sprintf (biffbuf, "%s@%ld\n", user, offset);
X+   write (fd, biffbuf, strlen (biffbuf));
X+   close (fd);
X+ }
END_OF_FILE
if test 1782 -ne `wc -c <'lmail.diffs'`; then
    echo shar: \"'lmail.diffs'\" unpacked with wrong size!
fi
# end of 'lmail.diffs'
fi
if test -f 'mailwrap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mailwrap.c'\"
else
echo shar: Extracting \"'mailwrap.c'\" \(1624 characters\)
sed "s/^X//" >'mailwrap.c' <<'END_OF_FILE'
X/* Local Mail Interceptor to handle interface to comsat */
X/* Args for local mail are  [ -r sender ] parties ... */
X/* Jim Mattson <mattson%cs@ucsd.edu> */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <stdio.h>
X
X#define FIFO "/usr/tmp/comsat.fifo"
X#define MAILDIR "/usr/spool/mail"
X#define MAILER "/usr/lib/mail/mail.orig"
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	off_t *offsets;		/* Mailbox offsets before delivery */
X	struct stat stbuf;	/* For stat'ing mailboxes */
X	char **av = argv;	/* Old argv */
X	int fd;			/* file descriptor for FIFO */
X	FILE *fp;		/* File pointer for FIFO */
X	int rc;			/* Return Code from local mailer */
X	int i;
X
X	/* Get rid of program name and [ -r sender ] */
X	argc--;
X	argv++;
X	if(!strcmp(argv[0], "-r")) {
X		argc -= 2;
X		argv += 2;
X	}
X	if(argc == 0)
X		exit(0);
X
X	if((offsets = (off_t *)malloc(sizeof(off_t) * argc)) == NULL)
X		bailout(av);
X
X	/* Get mailbox offsets */
X	if(chdir(MAILDIR) < 0)
X		bailout(av);
X	for(i = 0; i < argc; i++) {
X		if(stat(argv[i], &stbuf) < 0)
X			offsets[i] = 0;
X		else
X			offsets[i] = stbuf.st_size;
X	}
X
X	/* Send mail and wait for exit code */
X	switch(fork()) {
X	case -1:
X	case 0:
X		bailout(av);	/* No return */
X	default:
X		wait(&rc);
X	}
X	/* Send messages to comsat if it's listening */
X	if((fd = open(FIFO, O_WRONLY | O_NDELAY)) >= 0) {
X		if((fp = fdopen(fd, "w")) != NULL) {
X			for(i = 0; i < argc; i++)
X				fprintf(fp, "%s@%d\n", argv[i], offsets[i]);
X			fclose(fp);
X		}
X		close(fd);
X	}
X	/* Exit with local mailer's return code */
X	exit(rc >> 8);
X}
X
Xbailout(argv)
Xchar **argv;
X{
X	argv[0] = MAILER;
X	execv(MAILER, argv);
X	_exit(0);
X}
END_OF_FILE
if test 1624 -ne `wc -c <'mailwrap.c'`; then
    echo shar: \"'mailwrap.c'\" unpacked with wrong size!
fi
# end of 'mailwrap.c'
fi
echo shar: End of shell archive.
exit 0