[comp.os.minix] Mail

ast@cs.vu.nl (Andy Tanenbaum) (12/04/88)

I get a LOT of mail.  That probably surprises no one.  Nevertheless, I am
very conscientious about answering all mail in which people ask specific
questions.  A certain fraction of this mail bounces, and I don't
know what to do.  If you send me mail asking a specific question and don't
have an answer within, say, a week (unless I have announced that I am going
to be away), you can assume I was unable to reply.  In that case, please
resend the mail along with your exact path from uunet or mcvax, included
in the text of the message.

Andy Tanenbaum (ast@cs.vu.nl)

parke@jfcl.dec.com (Bill Parke) (12/06/88)

From article <1753@ast.cs.vu.nl>, by ast@cs.vu.nl (Andy Tanenbaum):
> 
...
>                                                   In that case, please
> resend the mail along with your exact path from uunet or mcvax, included
> in the text of the message.
> 
> Andy Tanenbaum (ast@cs.vu.nl)


Andy,

Would you please post an anternate to your cs.vu.nl mailing address as I have
been getting bounced when I use it to send you mail.

		Thanks,
			Bill Parke
			...!decwrl!jfcl!parke

			or parke@jfcl.dec.com

ast@cs.vu.nl (Andy Tanenbaum) (12/08/88)

In article <421@jfcl.dec.com> parke@jfcl.dec.com (Bill Parke) writes:
>Would you please post an anternate to your cs.vu.nl mailing address

The "bang" path is" ...uunet!mcvax!vu.cs!ast

Andy Tanenbaum (ast@cs.vu.nl)

ast@cs.vu.nl (Andy Tanenbaum) (10/23/89)

Fred van Kempen of the MINIX Users Group Holland has written a mail
system.  He sent it to me for posting and I did so.  Little did I
realize that he sent me raw binary files (not uuencoded).  I will have
a little talk with him.  In any event, this posting and the next two
contain the files in ASCII as shar files.

Please direct comments to him as he gets email, but not news (yet).

Andy Tanenbaum (ast@cs.vu.nl)


: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'README'
sed 's/^X//' > 'README' << '+ END-OF-FILE ''README'
X		W-MAIL Local Mail Agent (MINIX)
X
X		     MicroWalt W-MAIL V2.5
X		     =====================
X
XThis archive contains the sources of the W-MAIL program;
Xwhich is a MINIX version of the MAILX program available
Xon most UNIXes.
X
XIt does not need the presence of UUCP in order to run.
XHowever, for non-local mail delivery a remote mailer
X(like MicroWalt UMAIL) is required to be present.
X
XEnjoy!
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X| MINIX User Group (Holland)   UUCP: hp4nl!kyber!minixug!waltje	|
X| c/o Fred van Kempen,		 or: minixug!waltje@kyber.UUCP	|
X| Hoefbladhof  27						|
X| 2215 DV  VOORHOUT						|
X| The Netherlands	"A good programmer knows his Sources"	|
X+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
X
+ END-OF-FILE README
chmod 'u=rw,g=r,o=r' 'README'
set `wc -c 'README'`
count=$1
case $count in
756)	:;;
*)	echo 'Bad character count in ''README' >&2
		echo 'Count should be 756' >&2
esac
echo Extracting 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X#
X#     Makefile for W-MAIL Local Mail Agent (MINIX)
X#
X#   Makefile @(#)1.3        MicroWalt W-MAIL V2.5
X#
X# Define UMAILER if your remote mailer understands the
X# "-i datafile" option. Otherwise "< datafile" will be used.
X#
X# Define V7MAIL if you do not want the "To:"-line to be
X# included in the message header.
X#
XPROG	=	/usr/lib/uucp
XBIN	=	/usr/bin
X
XOPTS	=	-DUMAILER
XOPSYS   =	MINIX
X
XCFLAGS	=	-D$(OPSYS) -DUWALT -S $(OPTS)
XLDFLAGS =	-i
X
XOBJS	=	wmmain.s wmread.s wmcreate.s wminteract.s \
X		wmdeliver.s wmtime.s
XSRCS	=	wmmain.c wmread.c wmcreate.c wminteract.c \
X		wmdeliver.c wmtime.c
XOTHERS	=	README wmail.doc
X
X
Xwmail:		$(OBJS)
X		cc $(LDFLAGS) -o wmail $(OBJS)
X		@chmem =20000 wmail >/dev/null
X
Xinstall:	wmail
X		@echo 'Copying files...'
X		@rm -f $(BIN)/wmail $(BIN)/lmail $(BIN)/Mail \
X			$(BIN)/mailx $(BIN)/mail
X		@cp wmail $(BIN)
X		@echo 'Setting up links...'
X		@ln $(BIN)/wmail $(BIN)/lmail
X		@ln $(BIN)/wmail $(BIN)/mail
X		@ln $(BIN)/wmail $(BIN)/Mail
X		@ln $(BIN)/wmail $(BIN)/mailx
X		@echo 'Setting up permissions...'
X		chown root.root $(BIN)/wmail
X		chmod 6555 $(BIN)/wmail
X
Xshar:		wmail
X		@rm -f wmail.shar
X		@shar -v -o wmail.shar $(OTHERS) wmail Makefile $(SRCS)
X
Xtar:		wmail
X		@rm -f wmail.tar
X		@tar c wmail.tar $(OTHERS) wmail Makefile $(SRCS)
X
Xwmmain.s:	wmail.h wmmain.c
X		cc $(CFLAGS) wmmain.c
X
Xwmread.s:	wmail.h wmread.c
X		cc $(CFLAGS) wmread.c
X
Xwmcreate.s:	wmail.h wmcreate.c
X		cc $(CFLAGS) wmcreate.c
X
Xwminteract.s:	wmail.h wminteract.c
X		cc $(CFLAGS) wminteract.c
X
Xwmdeliver.s:	wmail.h wmdeliver.c
X		cc $(CFLAGS) wmdeliver.c
X
Xwmtime.s:	wmtime.c
X		cc $(CFLAGS) wmtime.c
X
+ END-OF-FILE Makefile
chmod 'u=rw,g=r,o=r' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
1595)	:;;
*)	echo 'Bad character count in ''Makefile' >&2
		echo 'Count should be 1595' >&2
esac
echo Extracting 'wmail.doc'
sed 's/^X//' > 'wmail.doc' << '+ END-OF-FILE ''wmail.doc'
XWMAIL(1)             MINIX User's Manual               WMAIL(1)
X
X
XNAME     
X     wmail - read or send electronic mail.
X
XSYNOPSIS     
X     wmail [-epqrv] [-f mailbox]
X     wmail [-dvt] [-i inputfile] [-s subject] <user> ...
X     lmail [-v] [-i inputfile] <user> ...
X
XDESCRIPTION     
X     Wmail is  used  to read  or create messages. Wmail  only
X     knows  about  local  users; messages to  non-local users
X     will be handed to the Remote Mailer of the system.
X
X     Wmail actually consists  of two  parts; namely  the user
X     agent (the part that reads or creates a message) and the
X     local  delivery  agent, which takes care of delivering a
X     message to the mailbox of a local user.
X
X     When  Wmail  is  called  without the 'user' argument, it
X     will read  the  contents  of  the  users's  mailbox  and
X     display a summary of messages. This summary contains one
X     line for each message indicating message number, sender,
X     date of creation and the subject of the message.
X     Wmail will  then display a prompt (containing the number
X     of the  current message), and waits for the user to type
X     a command. A  list  of this commands can be requested by
X     typing the '?' command.
X
X     When  the program is called with the 'user' argument, it
X     is assumed that the calling user wants to send a message
X     to that  user. Depending  on the name by which Wmail was
X     called ('lmail' or something else), the message  will be
X     generated and then delivered to the user.
X     If  the program  name is  'lmail', then the program only
X     delivers  the  message  to  the indicated  user. This is
X     used by intelligent mail routing programs that cannot do
X     local message delivery themselves.
X
X     Otherwise, if  the  name was not 'lmail', the message is
X     prepended with  a message  header,  which  contains  the
X     following lines:
X
X	From <user> <date>
X	To: <adressee>
X	Subject: <subject of message>
X	<empty line>
X
X     The 'To:' and 'Subject:' lines  are  optional, but often
X     they  are  present  in  the  message. After this message
X     header, there is the message itself.
X
X     After the message has been completed (by typing a '.' on     
X     an  empty  line or by typing an EOT (CTRL-D) character),
X     Wmail checks if a  signature file exists. This is a file
X     which  contains a standard  end-of-letter  text for that
X     user. Wmail  checks  the user's HOME  directory  for the
X     presence of a '.signature' file. If that file exists, it
X     is appended to the message.
X
X				-- 1 --
X
X
X
XWMAIL(1)             MINIX User's Manual               WMAIL(1)
X
X
X     If that file does not exist, Wmail checks if there is an
X     environment variable called 'SIGNATURE'. If that exists,
X     its value is assumed to be the path name of a  signature
X     file which will be appended to the message if it exists.
X
X     Finally,  the message is delivered to the adressed user.
X     Note, that  if  the adressee  is  not  a local user, the
X     message  will be passed on to the 'rmail' program, which
X     handles all remote-mail requests.
X     If the adressee  is just a local user, Wmail will do the
X     work  itself. If  any  errors  occur  during  the  local
X     delivery, the message is stored  in a file called in the
X     user's  HOME  directory with the name 'dead.letter', and
X     some diagnostics  will be printed on theterminal screen.
X
XOPTIONS
X     Some  command-line  options  are available to alter  the
X     "standard" behaviour  of the program. While  functioning
X     as a mail reader, the following options areavailable:
X
X	-e		Only check for the presence of mail.
X			When  this  option  is  given,  Wmail
X			checks the user's mailbox and returns
X			to the command level with  one of the
X			following exit values:
X
X				0  There is mail.
X				1  No mail.
X				2  Error.
X			
X			This  feature  can  be  used  in  the
X			system profile to warn the user if he
X			or she has mail.
X
X	-f filename	Use 'filename' as the mailbox instead
X			of the standard system mailbox.
X
X	-p		Print  the messages;  no  interactive
X			selection is needed.
X
X	-q		Quit after an interrupt occurs.
X			Usually Wmail catches all  interrupt;
X			this option may be  given to override
X			the interrupt catching mechanism.
X
X	-r		Print mail in Reverse order.
X			This option  is recognized for compa-
X			tibility with older programs only. It
X                        does not do anything, as the messages
X                        are usually selected by the user.
X
X    When  used  as a  message  creating  agent, the following
X    options are available:
X
X	-d		Deliver; call  the  message  delivery
X			software  immediately  after queueing
X			the message. This  is only valid  for
X			mail  that  needs to  be delivered by
X
X				-- 2 --
X
X
X
XWMAIL(1)             MINIX User's Manual               WMAIL(1)
X
X
X			some other mailer, e.g. Remote Mail.
X
X	-i infile	Input; use file 'infile' as  the mes-
X			sage file instead of  standard input.
X
X
X	-t		Include  all  adressees  in the 'To:'
X			line of the message header; not only
X			the first adressed user.
X
X	-s subject	Use 'subject'  as  the  value of  the
X			'Subject:' line of the message header
X			and do not ask for it later.  When an
X			empty subject (only NEWLINE) is typed
X			no 'Subject:'  line  will be inserted
X			in the message header.
X
X	-v		Verbose; generate some useful  output
X			while processing mail.
X
X     The  'user'  argument  identifies  the  user to send the
X     message to. If it  contains any  '!' or  '@' characters,
X     the  adressee is assumed  to be on  a remote system, and
X     the message will  be  handed  over to the remote mailer.
X     Otherwise it  is assumed  to be  an existing local user,
X     and  the  '/etc/passwd'  file  will  be checked  for the
X     existence  of that  user. If the  user is  non-existant,
X     a  diagnostic  message is  printed  and the  message  is
X     saved in the 'dead.letter' file.
X
XAUTHOR     
X     Peter S. Housel (first draft of mail program)
X     Fred van Kempen, waltje@kyber.UUCP
X
XFILES     
X     /etc/passwd		check existence of users
X     /usr/spool/mail/user   	maildrop file
X     /usr/spool/mail/user.lock  lock for maildrop files
X     /tmp/wm*      		temporary file
X     $HOME/dead.letter		message after delivery error
X
XSEE ALSO    
X     umail.doc, "MINIX/UUCP Reference Manual"
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X				-- 3 --
X
+ END-OF-FILE wmail.doc
chmod 'u=rw,g=r,o=r' 'wmail.doc'
set `wc -c 'wmail.doc'`
count=$1
case $count in
6366)	:;;
*)	echo 'Bad character count in ''wmail.doc' >&2
		echo 'Count should be 6366' >&2
esac
echo Extracting 'wmcreate.c'
sed 's/^X//' > 'wmcreate.c' << '+ END-OF-FILE ''wmcreate.c'
X/*
X * WMAIL -	MicroWalt Extended Mail Agent.
X *		This is the MicroWalt Mail Agent; which is derived
X *		from  the  "Mini-Mail" written by Peter S. Housel.
X *		This version  has a better  user-interface, and it
X *		also "knows" about things like forwarding, replies
X *		etc. Overall, it looks like the Mail (uppercase M)
X *		on our local DYNIX(tm) (==BSD) system...
X *		The paging-code (for paging letters on the screen)
X *		was taken from "more.c", by Brandon Allbery.
X *
X *		M A I L    G E N E R A T I O N    M O D U L E
X *
X * Author:	Fred van Kempen, MicroWalt Corporation
X */
X#include <stdio.h>
X#include <string.h>
X#include <pwd.h>
X#include "wmail.h"
X
X
X/*
X * Create a message, including the Mail-header and the final signature.
X * If this is a link to LMAIL and/or if the message is read from a file
X * leave out the signature.
X * This routine copies lines of text from 'stdin' to 'tempfp', until an
X * EOF is typed, or a line containing only a '.'.
X * We complicate things by not setting a line limit.
X * Define V7MAIL to skip the "To:"-field.
X */
XFILE *edit_mail(void)
X{
X  register FILE *tempfp, *sigfp;	/* temp file used for copy */
X  register char *sp, *bp;
X  register int c;
X  char cpbuff[1024];			/* copy buffer */
X  char tmp[PATHLEN];
X  int state, done;
X
X  if ((tempfp = fopen(msg_temp, "w")) == (FILE *)NULL) {
X	fprintf(stderr, "%s: cannot create temp file \"%s\"\n",
X							progname, msg_temp);
X	return((FILE *)NULL);
X  }
X
X  /* 
X   * Create the header. This has the form:
X   *
X   *  From <user> <date>
X   *  Subject: <text>	(if -s on command line or stdin)
X   *  To: <userlist>	(all recipients)
X   */
X  if (loclink == FALSE) {	/* only create header if not LMAIL! */
X	fprintf(tempfp, "From %s %s\n", sender, xtime());
X	if (subject[0]=='\0') {
X		if (isatty(fileno(infp))) {
X			fprintf(stderr, "Subject: ");
X			gets(subject);
X       			sp = strrchr(subject, '\n');
X			if (sp != NIL) *sp = '\0';
X			fprintf(stderr, "\n");
X       		}
X	}
X#ifndef V7MAIL
X	fprintf(tempfp, "To: %s\n", recipients);
X#endif
X	if (subject[0] != '\0') fprintf(tempfp, "Subject: %s\n", subject);
X
X	fputc('\n', tempfp);
X	done = state = 0;
X	do {
X      	    if ((c = fgetc(infp)) != EOF) {	
X		if (c=='.' && state==1) {
X			done = 1;
X		} else {
X			if (c == '\n') {
X				state = 1;
X		    	} else state = 0;
X		  }
X    		if (done == 0) fputc(c, tempfp);
X      	    } else done = 1;
X  	} while (done == 0);
X
X	/*
X	 * Add a .signature file after the message
X	 * Skip this if infp is a file.
X	 */
X	if (isatty(fileno(infp))) {
X		sp = getenv("SIGNATURE");
X		if (sp == NIL) {
X			sp = getenv("HOME");
X	      		if (sp != NIL) {
X                		strcpy(tmp, sp);
X                		if (strlen(tmp) > 1) strcat(tmp, "/");
X               		} else strcpy(tmp, "");
X              		strcat(tmp, SIGNATURE);
X	 	} else strcpy(tmp, sp);
X
X		if ((sigfp = fopen(tmp, "r")) != (FILE *)NULL) {
X			while ((c = fgetc(sigfp)) != EOF) fputc(c, tempfp);
X	        	fclose(sigfp);
X		}
X  	}
X  } else {	/* fast file copy for local delivery */
X	  /* copy temp. file to mailbox */
X	  while (TRUE) {
X		if (fgets(cpbuff, sizeof(cpbuff), infp) == (char *)NULL)
X								      break;
X		fwrite(cpbuff, sizeof(char), strlen(cpbuff), tempfp);
X	  }
X    }
X
X  if (ferror(tempfp) || fclose(tempfp)) {
X	fprintf(stderr, "%s: could not copy letter to temporary file\n",
X								progname);
X      	return((FILE *)NULL);
X  }
X
X  fclose(tempfp);
X  tempfp = fopen(msg_temp, "r");
X  return(tempfp);
X}
X
+ END-OF-FILE wmcreate.c
chmod 'u=rw,g=r,o=r' 'wmcreate.c'
set `wc -c 'wmcreate.c'`
count=$1
case $count in
3417)	:;;
*)	echo 'Bad character count in ''wmcreate.c' >&2
		echo 'Count should be 3417' >&2
esac
echo Extracting 'wmdeliver.c'
sed 's/^X//' > 'wmdeliver.c' << '+ END-OF-FILE ''wmdeliver.c'
X/*
X * WMAIL -	MicroWalt Extended Mail Agent.
X *		This is the MicroWalt Mail Agent; which is derived
X *		from  the  "Mini-Mail" written by Peter S. Housel.
X *		This version  has a better  user-interface, and it
X *		also "knows" about things like forwarding, replies
X *		etc. Overall, it looks like the Mail (uppercase M)
X *		on our local DYNIX(tm) (==BSD) system...
X *		The paging-code (for paging letters on the screen)
X *		was taken from "more.c", by Brandon Allbery.
X *
X *		L O C A L    D E L I V E R Y    M O D U L E
X *
X * Author:	Fred van Kempen, MicroWalt Corporation
X *
X * To Do:
X *		- Aliases.
X */
X#include <sys/stat.h>
X#include <stdio.h>
X#include <string.h>
X#include <signal.h>
X#include <errno.h>
X#include <pwd.h>
X#include "wmail.h"
X
X
Xextern int errno;
X
X
X/*
X * Update the mail-box file.
X */
Xvoid updatebox(void)
X{
X  char cpbuff[1024];		/* copy buffer */
X  FILE *copyfp;			/* fp for tempfile */
X  char lockname[PATHLEN];	/* maildrop lock */
X  char copytemp[PATHLEN];	/* temporary copy file */
X  int locktries = 0;		/* tries when box is locked */
X  LETTER *let;			/* current letter */
X  int c;
X
X  strcpy(copytemp, COPYTEMP);
X  mktemp(copytemp);
X
X  sprintf(lockname, LOCKNAME, sender);
X  
X  /* create a new mailbox-file */
X  if ((copyfp = fopen(copytemp, "w")) == (FILE *)NULL) {
X	fprintf(stderr, "%s: cannot create temp file \"%s\"\n",
X						progname, copytemp);
X	return;
X  }
X    
X  /* copy letters from old file to new file */
X  for (let = firstlet; let != NIL_LET; let = let->next) {
X	if (let->status != DELETED) printlet(let, copyfp);
X  }
X
X  if ((copyfp = freopen(copytemp, "r", copyfp)) == (FILE *)NULL) {
X	sprintf(cpbuff, "%s: temporary file write error", progname);
X	perror(cpbuff);
X	if (usedrop) unlink(copytemp); 
X	return;
X  }
X
X  /* shut off signals during the update */
X  signal(SIGINT, SIG_IGN);
X  signal(SIGHUP, SIG_IGN);
X  signal(SIGQUIT, SIG_IGN);
X
X  if (usedrop) while(link(mailbox, lockname) != 0) {
X	if (++locktries >= LOCKTRIES) {
X		fprintf(stderr, "%s: could not lock maildrop for update\n",
X								progname);
X		return;
X	}
X	sleep(LOCKWAIT);
X  }
X
X  if ((boxfp = freopen(mailbox, "w", boxfp)) == (FILE *)NULL) {
X	sprintf(cpbuff, "%s: could not reopen maildrop", progname);
X       	fprintf(stderr, "%s\nMail may have been lost; look in %s\n",
X							cpbuff, copytemp);
X       	unlink(lockname);
X       	return;
X  }
X
X  /* copy temp. file to mailbox */
X  while (TRUE) {
X	if (fgets(cpbuff, sizeof(cpbuff), copyfp) == (char *)NULL) break;
X	fwrite(cpbuff, sizeof(char), strlen(cpbuff), boxfp);
X  }
X  fflush(copyfp); fflush(boxfp);
X  fclose(boxfp); fclose(copyfp);
X  unlink(copytemp); 
X
X  if (usedrop) unlink(lockname);
X}
X
X
X/*
X * Send a message to a remote user.
X * Define UMAILER if your mailer knows about the "-i datafile" option.
X */
Xvoid send_remote(name)
Xchar *name;
X{
X  char cmdbuff[128];
X
X#ifdef UMAILER		/* faster than redirecting! */
X  sprintf(cmdbuff, "exec %s -i%s %s %s %s >/dev/null", RMAIL, msg_temp,
X#else
X  sprintf(cmdbuff, "exec %s <%s %s %s %s >/dev/null", RMAIL, msg_temp,
X#endif UMAILER
X	immediate ? "-n" : "", verbose ? "-v" : "", adressee);
X  system(cmdbuff);				/* call the mailer! */
X}
X
X
X/*
X * Deliver a message to a user.
X * First of all, check if we can use a more intelligent mailer
X * for this job. If not, deliver it !
X */
Xint deliver(count, vec)
Xint count; char *vec[];
X{
X  char cpbuff[1024];			/* copy buffer */
X  register int i, c;
X  int errs = 0;				/* count of errors */
X  int dropfd;				/* file descriptor for user's drop */
X  int created = 0;			/* true if we created the maildrop */
X  FILE *mailfp;				/* fp for mail */
X  struct stat stb;			/* for checking drop modes, owners */
X  int (*sigint)(), (*sighup)(), (*sigquit)();	/* saving signal state */
X  char lockname[PATHLEN];		/* maildrop lock */
X  int locktries;			/* tries when box is locked */
X  struct passwd *pw;			/* sender and recipent */
X
X  if (count > MAXRCPT) {
X	fprintf(stderr, "%s: too many recipients\n", progname);
X	return(-1);
X  }
X
X  strcpy(recipients, "");
X  if (sayall) {
X	for (i=0; i<count; i++) {
X		strcat(recipients, vec[i]);
X		/* RFC-822: separate with comma */
X		strcat(recipients, ",");
X  	}
X  	recipients[strlen(recipients)-1] = '\0';  /* kill last comma */
X  } else strcat(recipients, vec[0]);     
X
X  mailfp = edit_mail();	/* input the message */
X
X  /* shut off signals during the delivery */
X  sigint = signal(SIGINT, SIG_IGN);
X  sighup = signal(SIGHUP, SIG_IGN);
X  sigquit = signal(SIGQUIT, SIG_IGN);
X
X  /*
X   * We have the message, now deliver it to all recipients!
X   * Do this on a per-user basis!
X   */
X  for (i = 0; i < count; ++i) {
X	if (count > 1) rewind(mailfp);		/* rewind data-file */
X	strcpy(adressee, vec[i]); 		/* get name of adressee */
X	forward[0] = '\0';			/* Clear 'Forward' flag */
X
X      	/* OK, 'adressee' is the recipient. Check if local. */
X      	if (strchr(adressee, '!') || strchr(adressee, '@')) {
X		remote = 1;		/* the guy is remote... */
X        	send_remote(adressee);	/* call RMAIL or SMAIL for this... */
X		continue;
X       	}
X
X	/* Hmm, it is a local user. Do we know him? */
X      	if ((pw = getpwnam(adressee)) == (struct passwd *)NULL) {
X		fprintf(stderr, "%s: user %s unknown\n", progname, adressee);
X		++errs;
X		dead_letter();
X		continue;
X       	} else {
X	   	sprintf(mailbox, DROPNAME, adressee);
X 	       	sprintf(lockname, LOCKNAME, adressee);
X	  }
X
X	/* OK, we know him. Check if we have to forward his mail. */
X      	if (chk_box() == 1) {		/* forward messages to 'forward' */
X		strcpy(adressee, forward);
X
X        	/* We now have the final adressee.
X		 * Check for remote users again.
X		 */
X		if (strchr(adressee, '!') || strchr(adressee, '@')) {
X			remote = 1;
X          		send_remote(adressee);	/* No, call RMAIL/SMAIL. */
X	  		continue;
X         	} else {	/* Check if this guy is known. */
X		       	if ((pw = getpwnam(adressee)) ==
X						(struct passwd *)NULL) {
X		   		fprintf(stderr,
X					"%s: forward-user %s unknown\n",
X							progname, adressee);
X		   		++errs;
X				dead_letter();
X		   		continue;
X	          	} else {
X		         	sprintf(mailbox, DROPNAME, adressee);
X	 	          	sprintf(lockname, LOCKNAME, adressee);
X		          }
X		  }
X	}
X
X      	/*
X       	 * We now have a local user 'adressee' who exists.
X         * Lock the maildrop while we're messing with it. Races are possible
X         * (though not very likely) when we have to create the maildrop, but
X         * not otherwise. If the box is already locked, wait awhile and try
X         * again.
X         */
X      	locktries = created = 0;
Xtrylock:
X      	if (link(mailbox, lockname) != 0) {
X		if (errno == ENOENT) {	/* user doesn't have a drop yet */
X			if ((dropfd = creat(mailbox, 0600)) < 0) {
X				fprintf(stderr,
X				 "%s: could not create maildrop for %s\n",
X		      					  progname, vec[i]);
X				++errs;
X				dead_letter();
X				continue;
X          		}
X	  		++created;
X	  		goto trylock;
X         	} else {   /* somebody else has it locked, it seems - wait */
X	  	 	if (++locktries >= LOCKTRIES) {	
X				fprintf(stderr,
X				  "%s: could not lock maildrop for %s\n",
X		      					progname, vec[i]);
X				++errs;
X				dead_letter();
X	      	   		continue;
X	     	  	}
X	   	 	sleep(LOCKWAIT);
X	   	 	goto trylock;
X	  	  }
X	}
X
X      	if (created) {
X        	chown(mailbox, pw->pw_uid, pw->pw_gid);
X        	boxfp = fdopen(dropfd, "a");
X       	} else boxfp = fopen(mailbox, "a");
X
X      	if (boxfp==(FILE *)NULL || stat(mailbox, &stb) < 0) {
X		fprintf(stderr, "%s: serious maildrop problems for %s\n",
X							progname, vec[i]);
X        	unlink(lockname);
X        	++errs;
X		dead_letter();
X        	continue;
X       	}
X
X      	if (stb.st_uid != pw->pw_uid || (stb.st_mode & S_IFMT) != S_IFREG) {
X		fprintf(stderr, "%s: mailbox for user %s is illegal\n",
X							progname, vec[i]);
X		unlink(lockname);
X		++errs;
X		dead_letter();
X		continue;
X       	}
X
X	/* copy temp. file to mailbox */
X	while (TRUE) {
X		if (fgets(cpbuff, sizeof(cpbuff), mailfp) == (char *)NULL)
X								      break;
X		fwrite(cpbuff, sizeof(char), strlen(cpbuff), boxfp);
X	}
X
X	/* to make sure! */
X	fputc('\n', boxfp);
X      	if (ferror(boxfp) || fclose(boxfp) != 0) {
X		fprintf(stderr, "%s: error delivering to user %s",
X							progname, vec[i]);
X		perror("");
X		dead_letter();
X		++errs;
X       	}
X
X      	unlink(lockname);
X  }
X
X  fclose(mailfp);
X
X  /* put signals back the way they were */
X  signal(SIGINT, sigint);
X  signal(SIGHUP, sighup);
X  signal(SIGQUIT, sigquit);
X
X  return (errs == 0) ? 0 : -1;
X}
X
X
X/* 
X * Save the current message to file 'dead.letter'.
X * This is sometimes needed (when delivery fails!).
X */
Xvoid dead_letter(void)
X{
X  char cpbuff[1024];
X  char fname[PATHLEN];
X  char *sp;
X  register FILE *inf, *outf;
X
X  fname[0] = '\0';
X  inf = fopen(msg_temp, "r");
X  if ((sp = getenv("HOME")) != NULL) {
X	strcpy(fname, sp);
X	if (strlen(sp) > 1)
X		strcat(fname, "/");
X  }
X  strcat(fname, DEADLETTER);
X
X  inf = fopen(msg_temp, "r");
X  if (inf == (FILE *)NULL) {
X	fprintf(stderr, "%s: cannot open \"%s\"\n", progname, msg_temp);
X	return;
X  }
X
X  outf = fopen(fname, "w");
X  if (outf == (FILE *)NULL) {
X	fprintf(stderr, "%s: cannot create \"%s\"\n", progname, fname);
X	return;
X  }
X
X  /* copy temp. file to dead.letter */
X  while (TRUE) {
X	if (fgets(cpbuff, sizeof(cpbuff), inf) == (char *)NULL) break;
X	fwrite(cpbuff, sizeof(char), strlen(cpbuff), outf);
X  }
X
X  fclose(inf);
X  fclose(outf);
X
X  chown(fname, old_uid, old_gid);
X  fprintf(stderr, "%s: dumped message on file \"%s\"\n", progname, fname);
X}
+ END-OF-FILE wmdeliver.c
chmod 'u=rw,g=r,o=r' 'wmdeliver.c'
set `wc -c 'wmdeliver.c'`
count=$1
case $count in
9423)	:;;
*)	echo 'Bad character count in ''wmdeliver.c' >&2
		echo 'Count should be 9423' >&2
esac
echo Extracting 'wminteract.c'
sed 's/^X//' > 'wminteract.c' << '+ END-OF-FILE ''wminteract.c'
X/*
X * WMAIL -	MicroWalt Extended Mail Agent.
X *		This is the MicroWalt Mail Agent; which is derived
X *		from  the  "Mini-Mail" written by Peter S. Housel.
X *		This version  has a better  user-interface, and it
X *		also "knows" about things like forwarding, replies
X *		etc. Overall, it looks like the Mail (uppercase M)
X *		on our local DYNIX(tm) (==BSD) system...
X *		The paging-code (for paging letters on the screen)
X *		was taken from "more.c", by Brandon Allbery.
X *
X *		I N T E R A C T I O N    M O D U L E
X *
X * Author:	Fred van Kempen, MicroWalt Corporation
X *
X * To Do:
X *		- Builtin escapes (~i and friends)
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <signal.h>
X#include "wmail.h"
X
X
X/*
X * Send a reply to a message.
X */
Xstatic int do_reply(let)
XLETTER *let;
X{
X  char repuser[512];
X  char *who[2];
X
X  strcpy(repuser, let->sender);
X  who[0] = &repuser[0];
X  who[1] = (char *)NULL;
X  sprintf(subject, "Re: %s", let->subject);
X
X  printf("\n*** From: %s %-24.24s\n", sender, xtime());
X  printf("*** To: %s\n", who[0]);
X  printf("*** Subject: %s\n\n", subject);
X
X  deliver(1, who);
X}
X
X
X/*
X * Execute a shell (or a command only)
X */
Xstatic void do_shell(command)
Xchar *command;
X{
X  int waitstat, pid;
X  char *shell;
X
X  if ((shell = getenv("SHELL")) == NIL) shell = SHELL;
X
X  if ((pid = fork()) < 0) {
X	fprintf(stderr, "%s: could not fork", progname);
X       	return;
X  } else if (pid != 0) {		/* parent */
X		wait(&waitstat);
X        	return;
X    }
X
X  /* child */
X  setgid(old_gid);	/* UUCP or USER */
X  setuid(old_uid);	/* UUCP or USER */
X  umask(oldmask);
X
X  execl(shell, shell, "-c", command, NIL);
X  fprintf(stderr, "%s: cannot exec shell", progname);
X  exit(127);
X}
X
X
X/*
X * Goto a specific letter.
X */
Xstatic LETTER *goto_letter(num)
Xint num;
X{
X  LETTER *let;
X
X  let = firstlet;
X  while (let != NIL_LET) {
X	if (let->seqno == num) return(let);
X	let = let->next;
X  }
X  return(NIL_LET);
X}
X
X
X/*
X * Skip the header of message 'let'.
X * Do this by just updating the 'boxfp' pointer...
X */
Xoff_t skiphead(let)
XLETTER *let;
X{
X  char xbuf[1024];
X  off_t count;
X
X  count = (off_t) 0;
X  while (fgets(xbuf, sizeof(xbuf), boxfp) != NIL) {
X	count += (off_t) strlen(xbuf);
X      	if (xbuf[0] == '\n') break;  /* end of header */
X  }
X  return(count);
X}
X
X
X/*
X * Save the current letter to a disk-file.
X */
Xvoid savelet(let, savefile, withhead)
XLETTER *let;
Xchar *savefile;
Xint withhead;
X{
X  int c;
X  off_t curr, limit, oldpos;
X  register char *bp;
X  FILE *savefp;
X
X  bp = savefile;
X  while (*bp && *bp!='\n') bp++;
X  *bp = '\0';
X
X  if ((savefp = fopen(savefile, "a")) == (FILE *)NULL) {
X	fprintf(stderr, "%s: cannot append to savefile \"%s\"\n",
X							progname, savefile);
X	return;
X  }
X
X  oldpos = ftell(boxfp);
X  fseek(boxfp, (curr = let->location), 0);
X  limit = (let->next != NIL_LET) ? let->next->location : -1L;
X
X  if (withhead == 0) curr += skiphead(let);	/* skip the message header */
X  while(curr != limit && (c = fgetc(boxfp)) != EOF) {
X	fputc(c, savefp);
X      	++curr;
X  }
X  fflush(savefp);
X  fseek(boxfp, oldpos, 0);
X
X  if ((ferror(savefp) != 0) | (fclose(savefp) != 0)) {
X	fprintf(stderr, "%s: savefile write error:", progname);
X  }
X
X  chown(savefile, old_uid, old_gid);
X}
X
X
X/*
X * Give a list of possible Interact Commands.
X */
Xstatic void do_help(void)
X{
X  printf("\n   ** W-MAIL Commands **\n\n");
X  printf("?\tThis help\n");
X  printf("!\tShell Command Escape\n");
X  printf("-\tPrevious letter\n");
X  printf("+\tNext letter\n");
X  printf("<ENTER>\tNext letter\n");
X  printf("d\tDelete current letter\n");
X  printf("i\tDisplay a summary of letters\n");
X  printf("p\tPrint a letter again\n");
X  printf("q\tQuit, update mailbox\n");
X  printf("r\tReply to the current letter\n");
X  printf("s\tSave current letter\n");
X  printf("t\tType a letter, no paging\n");
X  printf("w\tSave letter without header\n");
X  printf("x\tExit, do not update mailbox\n");
X  printf("\n");
X}
X
X
X/*
X * Give a summary of letters./
X */
Xstatic void summary(void)
X{
X  register LETTER *let;
X  register int i;
X  register char *sp;
X
X  let = firstlet;
X  printf(" No.  Sender           Date            Subject\n");
X  printf(" ----------------------------------------------");
X  printf("--------------------------------\n");
X
X  for (i=0; i<numlet; i++) {
X	sp = let->date;
X	if (strchr(sp, ',')) sp += 5;	/* new-style ctime() */
X	  else sp += 4;
X	printf("%c%c %-3.3d  %-8.8s  %-15.15s  \"%.40s\"\n",
X		(nextlet == let->seqno) ? '>': ' ',
X		(let->status == DELETED) ? '*': ' ',
X 		let->seqno, basepath(let->sender), sp, let->subject);
X        let = let->next;
X  }
X
X  printf("\n");
X}
X
X
X/*
X * Interactively read the mail-box.
X */
Xvoid interact(void)
X{
X  char input[512];	/* user input line */
X  char *p;
X  LETTER *let, dummy;	/* current and next letter */
X  LETTER *templet;
X  int interrupted = 0;	/* SIGINT hit during letter print */
X  char *savefile;		/* filename to save into */
X  int i, temp;
X
X  if (firstlet == NIL_LET) {
X	printf("No mail for %s.\n", sender);
X      	return;
X  }
X
X  printf("W-MAIL %s.  Type ? for Help.\n", Version);
X  printf("\"%s\": %d message(s)\n\n", mailbox, numlet);
X
X  nextlet = 1;
X  dummy.seqno = nextlet;
X  dummy.next = firstlet;
X  let = &dummy;
X
X  summary();
X
X  while(1) {
X	nextlet = let->seqno;
X
X       	if (!quitmode) {
X		interrupted = setjmp(printjump);
X		signal(SIGINT, onint);
X       	}
X
X      	if (interrupted) printf("\n");
X      	printf(PROMPT, let->seqno);
X      	fflush(stdout);
X
X      	if (fgets(input, sizeof(input), stdin) == NIL) break;
X
X      	if (!quitmode) signal(SIGINT, SIG_IGN);
X
X      	switch(input[0]) {
X		case '!':
X			do_shell(input + 1);
X			continue;
X		case '?':	
X			do_help();
X			continue;
X		case '-':
X			if (let->prev != NIL_LET) let = let->prev;
X			  else printf("Top of mailbox\n");
X			continue;
X		case '+':
X		case '\n':
X			if (let->next != NIL_LET) {
X				let = let->next;
X				if (!interrupted) {
X		            		if (let->status != DELETED)
X							let->status = READ;
X			    		printlet(let, stdout);
X		           	}
X			} else printf("At EOF\n");
X			continue;
X		case 'd':
X			let->status = DELETED;
X			if (let->next != NIL_LET) let = let->next;
X			needupdate = 1;
X			continue;
X		case 'i':
X			summary();
X			continue;
X		case 'p':
X			if (!interrupted) printlet(let, stdout);
X			continue;
X		case 'q':
X			return;
X		case 'r':
X			do_reply(let);
X			break;
X		case 's':
X			savefile = &input[1];
X			if (*savefile != '\0') {
X			  	while (*savefile==' ' || *savefile=='\t')
X								savefile++; 
X			} else savefile = SAVEFILE;
X			savelet(let, savefile, 1);
X			continue;
X		case 't':
X			temp = printmode;
X			printmode = 1;
X			if (!interrupted) printlet(let, stdout);
X			printmode = temp;
X			continue;
X		case 'w':
X			savefile = &input[1];
X			if (*savefile != '\0') {
X			  	while (*savefile==' ' || *savefile=='\t')
X								savefile++; 
X			} else savefile = SAVEFILE;
X			savelet(let, savefile, 0);
X			continue;
X		case 'x':
X			exit(0);
X		default:
X			if (isdigit(input[0])) {
X				templet = goto_letter(atoi(input));
X				if (templet != NIL_LET) {
X					let = templet;
X					printlet(let, stdout);
X			   	} else printf("Illegal message-number\n");
X			} else printf("Illegal command\n");
X			continue;
X  	}
X  }   
X}
X
+ END-OF-FILE wminteract.c
chmod 'u=rw,g=r,o=r' 'wminteract.c'
set `wc -c 'wminteract.c'`
count=$1
case $count in
7139)	:;;
*)	echo 'Bad character count in ''wminteract.c' >&2
		echo 'Count should be 7139' >&2
esac
echo Extracting 'wmmain.c'
sed 's/^X//' > 'wmmain.c' << '+ END-OF-FILE ''wmmain.c'
X/*
X * WMAIL -	MicroWalt Extended Mail Agent.
X *		This is the MicroWalt Mail Agent; which is derived
X *		from  the  "Mini-Mail" written by Peter S. Housel.
X *		This version  has a better  user-interface, and it
X *		also "knows" about things like forwarding, replies
X *		etc. Overall, it looks like the Mail (uppercase M)
X *		on our local DYNIX(tm) (==BSD) system...
X *		The paging-code (for paging letters on the screen)
X *		was taken from "more.c", by Brandon Allbery.
X *
X * Author:	Fred van Kempen, MicroWalt Corporation
X *
X * To Do:
X */
X#include <sys/stat.h>
X#include <stdio.h>
X#include <string.h>
X#include <errno.h>
X#include <pwd.h>
X#include "wmail.h"
X
X
Xchar *Version = VERSION;
Xint remote = FALSE;			/* use RMAIL to deliver (if any) */
Xint loclink = FALSE;			/* LMAIL: local delivery only! */
Xint old_uid, old_gid;			/* UID/GID of calling user */
Xint printmode = FALSE;			/* print-and-exit mode */
Xint immediate = FALSE;			/* send remote immediately! */
Xint quitmode = FALSE;			/* take interrupts */
Xint usedrop = TRUE;			/* read the maildrop (no -f given) */
Xint verbose = FALSE;			/* pass "-v" flag on to mailer */
Xint needupdate = FALSE;			/* need to update mailbox */
Xint sayall = FALSE;			/* include line with all recipients */
Xint checkonly = FALSE;			/* only chack if there is mail */
Xchar sender[PATHLEN];			/* who sent the message? */
Xchar forward[PATHLEN];			/* who is the message forwarded to? */
Xchar adressee[PATHLEN];			/* current recipient */
Xchar recipients[PATHLEN];		/* also to... users */
Xchar mailbox[PATHLEN];			/* user's mailbox/maildrop */
Xchar subject[PATHLEN];			/* subject of message */
Xchar msg_temp[PATHLEN];			/* temporary file */
Xchar findbuff[128];
Xchar inbuff[512];
Xchar lbuff[512];
XFILE *infp = (FILE *)NULL;		/* current message input file */
XFILE *boxfp = (FILE *)NULL;		/* mailbox file */
Xchar *progname;				/* program name */
Xjmp_buf printjump;			/* for quitting out of letters */
XLETTER *firstlet, *lastlet;		/* message pointers for readbox() */
Xint numlet, nextlet, seqno;		/* number of active letters */
Xunsigned oldmask;			/* saved umask() */ 
X
X
Xextern char *optarg;			/* from the GETOPT(3) package */
Xextern int getopt(), optind;
Xextern int errno;			/* from STDIO */
X
X
Xvoid onint(void)
X{
X  longjmp(printjump, 1);
X}
X
X
X/*
X * Chop off the last (file) part of a filename.
X */
Xchar *basename(name)
Xchar *name;
X{
X  char *p;
X   char *strrchr();
X
X  p = strrchr(name, '/');
X  if (p == NIL) return(name);	/* no pathname */
X    else return(p + 1);
X}
X
X
X/*
X * Chop off the last (user) part of a UUCP path-name.
X * This is needed for the summary() routine.
X */
Xchar *basepath(name)
Xchar *name;
X{
X  char *p;
X   char *strrchr();
X
X  p = strrchr(name, '!');
X  if (p == NIL) return(name);	/* no pathname */
X    else return(p + 1);
X}
X
X
X/*
X * return ASCII text of our login-name.
X */
Xchar *whoami(void)
X{
X  struct passwd *pw;
X
X  if ((pw = getpwuid(getuid())) != (struct passwd *)NULL)
X						return(pw->pw_name);
X    else return("nobody");
X}
X
X
X/*
X * Find the given antry in the mail-header
X * Search for the first occurence of string 'text' in the header.
X * Copy the text following it into the 'let' structure.
X * Return buffer if found, else NULL.
X */
Xchar *find_string(let, text)
XLETTER *let;
Xchar *text;
X{
X  int all;
X  off_t curr, limit;
X  register char *sp;
X
X  fseek(boxfp, let->location, 0);
X  limit = (off_t) -1L;
X  if (let->next != NIL_LET) limit = let->next->location;
X
X  all = 0;
X  curr = let->location;
X  while (curr != limit && !all) {
X	if (fgets(inbuff, sizeof(inbuff), boxfp) == NIL) all = 1;
X      	if (inbuff[0] == '\0') all = 1; /* end-of-header */
X
X      	if (!strncmp(inbuff, text, strlen(text))) {
X		sp = &inbuff[0];		/* remove '\n' */
X      		while (*sp && *sp!='\n') sp++;
X      		*sp = '\0';
X		sp = &inbuff[0] + strlen(text);	/* copy to static buff */
X		strcpy(findbuff, sp);
X		return(findbuff);		/* return adress of buff */
X       	}
X
X	curr += (off_t) strlen(inbuff);		/* update message offset */
X
X	if (!all && limit > 0L)			/* quit if past message */
X		if (curr >= limit) all = 1;
X  }
X  return(NIL);
X}
X
X
X/*
X * Check is the first line of the mailbox contains a line like
X *
X *	Forward to XXXX
X *
X * then all mail for the calling user is being forwarded
X * to user XXXX. Return a 1 value if this is the case.
X * Otherwise, return 0 (or -1 for error).
X */
Xint chk_box(void)
X{
X  char xbuf[128];
X  char *bp;
X  FILE *fp;
X
X  if (access(mailbox, 4) < 0 || 
X    (fp = fopen(mailbox, "r")) == (FILE *)NULL) {
X	if (usedrop && errno==ENOENT) return(-1);
X     	fprintf(stderr, "%s: cannot access mailbox ", progname);
X      	perror(mailbox);
X      	exit(1);
X  }
X
X  bp = fgets(xbuf, sizeof(xbuf), fp);
X  fclose(fp);
X
X  if (bp!=NIL && !strncmp(xbuf, "Forward to ", 11)) {
X	strcpy(forward, strrchr(xbuf, ' ') + 1);	/* get username */
X	forward[strlen(forward)-1] = '\0';		/* remove \n */
X	return(1);
X  }
X  return(0);
X}
X
X
X/* 
X * Read the contents of the Mail-Box into memory.
X */
Xint readbox(void)
X{
X  register LETTER *let;
X  register char *sp, *bp;
X  off_t current;
X 
X  firstlet = lastlet = NIL_LET;
X  numlet = 0;
X  seqno = 1;
X
X  if (chk_box() == 1) return(1);	/* mail is being forwarded... */
X
X  if ((boxfp = fopen(mailbox, "r")) == (FILE *)NULL) {
X	if (usedrop && errno==ENOENT) return(-1);
X      	fprintf(stderr, "%s: cannot access mailbox ", progname);
X      	perror(mailbox);
X      	exit(1);
X  }
X
X  /*
X   * Determine where all messages start.
X   * This should be done with an index file in the future!
X   */
X  current = 0L;
X  while(fgets(lbuff, sizeof(lbuff), boxfp) != NIL) {
X	current = ftell(boxfp);
X      	if (!strncmp(lbuff, "From ", 5)) {
X		if ((let = (LETTER *)malloc(sizeof(LETTER))) == NIL_LET) {
X			fprintf(stderr, "%s: out of memory.\n", progname);
X			exit(1);
X	 	}
X        	if (lastlet == NIL_LET) {
X			firstlet = let;
X			let->prev = NIL_LET;
X	 	} else {
X	 		let->prev = lastlet;
X	     	 	lastlet->next = let;
X	    	  }
X		lastlet = let;
X		let->next = NIL_LET;
X
X		let->status = UNREAD;
X		let->location = current - (off_t) strlen(lbuff);
X		let->seqno = seqno++;
X		numlet++;
X	}
X  }
X
X  /*
X   * We now know where the messages are, read message headers.
X   */
X  let = firstlet;
X  while (let != NIL_LET) {
X	sp = find_string(let, "From ");
X	if (sp == NIL) sp = "<unknown>";	/* should never occur! */
X	strncpy(let->sender, sp, 511);
X	sp = let->sender;
X	while (*sp && *sp!=' ') sp++;
X	*sp = '\0';
X	
X	sp = find_string(let, "Subject: ");
X	if (sp == NIL) sp = "<none>";
X	strncpy(let->subject, sp, 79);
X
X	sp = find_string(let, "From ");
X	while (*sp && *sp!=' ') sp++;
X	sp++;
X	strncpy(let->date, sp, 31);
X	
X	let = let->next;
X  }
X}
X
X
X/*
X * Check if there is any mail for the calling user.
X * Return 0 if there is mail, or 1 for NO MAIL.
X */
Xstatic int chk_mail(void)
X{
X  FILE *fp;
X  char temp[512];
X
X  if ((fp = fopen(mailbox, "r")) != (FILE *)NULL) {
X	if (fgets(temp, sizeof(temp), fp) == NIL) {
X		fclose(fp);	/* empty mailbox, no mail! */
X		return(1);
X	}
X      	if (!strncmp(temp, "Forward to ", 11)) {
X		fclose(fp);	/* FORWARD line in mailbox */
X		return(2);	/* so no mail. */
X	}
X	fclose(fp);	/* another line, so we have mail! */
X	return(0);
X  }
X  return(1);
X}
X
X
Xstatic void usage(void)
X{
X  fprintf(stderr, "Usage:\n");
X  fprintf(stderr, "\t%s [-epqrv] [-f file]\n", progname);
X  fprintf(stderr, "\t%s [-dtv] [-i file] [-s subject] user ...\n", progname);
X  fprintf(stderr, "\t%s [-lv] [-i file] user\n\n", progname);
X}
X
X
Xmain(argc, argv)
Xint argc; char *argv[];
X{
X  int c, st;
X
X  strcpy(sender, whoami());
X  old_uid = getuid();			/* get calling user and save */
X  old_gid = getgid();
X  setuid(geteuid());			/* set UID to ROOT (SU) */
X  setgid(getegid());			/* set GID to ROOT (SU) */
X
X  progname = basename(argv[0]);		/* how are we called? */
X  if (*progname == 'l') {
X	remote = 0;			/* 'lmail' link? */
X	loclink = 1;
X  }
X  strcpy(msg_temp, MAILTEMP);
X  mktemp(msg_temp);			/* name the temp file */
X  oldmask = umask(077);			/* change umask for security */
X  infp = stdin;				/* set INPUT to stdin */
X  
X  while ((c = getopt(argc, argv, "def:i:lpqrs:tv")) != EOF) switch(c) {
X	case 'd':
X		immediate++;
X		break;
X	case 'e':
X		checkonly++;
X		break;
X	case 'f':
X		usedrop = 0;
X		strncpy(mailbox, optarg, PATHLEN - 1);
X		break;
X	case 'i':
X		infp = fopen(optarg, "r");
X		if (infp == (FILE *)NULL) {
X			fprintf(stderr,
X				"%s: cannot open %s\n", progname, optarg);
X			exit(-1);
X		}
X		break;
X	case 'l':
X		loclink = 1;
X		break;
X	case 'p':
X		printmode++;
X		break;
X	case 'q':
X		quitmode++;
X		break;
X	case 'r':
X		break;		/* no reverse order supported! */
X	case 's':
X		strcpy(subject, optarg);
X		break;
X	case 't':
X		sayall++;
X		break;
X	case 'v':
X		verbose++;
X		break;
X	default:
X		usage();
X		exit(2);
X  }
X
X  if (optind >= argc) {
X	  if (usedrop) sprintf(mailbox, DROPNAME, sender);
X
X	  if (checkonly) {
X		st = chk_mail();
X		exit(st);
X	  }
X
X	  if ((st = readbox()) == 1) {
X		fprintf(stderr, "Your mail is being forwarded to %s.\n",
X								forward);
X		exit(1);
X	  } else {
X		  st = 0;
X	 	  if (printmode) printall();
X		    else interact();
X
X		  if (needupdate) updatebox();
X	    }
X    } else st = deliver(argc - optind, argv + optind);
X
X  unlink(msg_temp);
X  exit(st);    
X}
+ END-OF-FILE wmmain.c
chmod 'u=rw,g=r,o=r' 'wmmain.c'
set `wc -c 'wmmain.c'`
count=$1
case $count in
9095)	:;;
*)	echo 'Bad character count in ''wmmain.c' >&2
		echo 'Count should be 9095' >&2
esac
echo Extracting 'wmread.c'
sed 's/^X//' > 'wmread.c' << '+ END-OF-FILE ''wmread.c'
X/*
X * WMAIL -	MicroWalt Extended Mail Agent.
X *		This is the MicroWalt Mail Agent; which is derived
X *		from  the  "Mini-Mail" written by Peter S. Housel.
X *		This version  has a better  user-interface, and it
X *		also "knows" about things like forwarding, replies
X *		etc. Overall, it looks like the Mail (uppercase M)
X *		on our local DYNIX(tm) (==BSD) system...
X *		The paging-code (for paging letters on the screen)
X *		was taken from "more.c", by Brandon Allbery.
X *
X *		R E A D    M A I L    M O D U L E
X *
X * Author:	Fred van Kempen, MicroWalt Corporation
X *
X * To Do:
X *		- TERMCAP/TERMINFO use !
X */
X#include <stdio.h>
X#include <string.h>
X#include <sgtty.h>
X#include "wmail.h"
X
X
Xstatic int mline;		/* current terminal line */
Xstatic int mcol;		/* current terminal column */
Xstatic char mobuf[512];		/* output buffer */
Xstatic int mobc;		/* position in output buffer (== chars in) */
Xstatic int misdone;		/* flag: return EOF next read even if not */
X
X
X/*
X * Write one line of text to the screen.
X * Return 1 if a Quit command was given.
X */
Xstatic int lwrite(fd, buf, len)
Xint fd;
Xchar *buf;
Xunsigned len;
X{
X  unsigned here, start;
X  char cmd;
X
X  start = 0;
X  here = 0;
X  while (here != len) {
X	cmd = '\0';
X      	switch (buf[here++]) {
X		case '\n':
X		    mcol = 0;
X		    if (++mline == 23) {
X			fflush(stdout);
X		     	write(1, buf + start, here - start);
X		     	fflush(stdout);
X		     	fprintf(stderr, "\007\033[7m--More--\033[0m");
X		     	do {
X			    read(fd, &cmd, 1);
X       			   } while (strchr(" \r\nqQ'nN", cmd)
X						== (char *)NULL);
X		        fprintf(stderr, "\r\033[K");
X		        mline = 0;
X		        start = here;
X 	  	    }
X		   break;
X		case '\r':
X		    mcol = 0;
X		    break;
X	case '\b': 
X		    if (mcol != 0) mcol--;
X		      else {
X			    mline--;
X			    mcol = 80 - 1;
X		      }
X		    break;
X	case '\t':
X		    do {
X		        mcol++;
X		    } while (mcol % 8 != 0);
X		    break;
X	default:   
X		    if ( buf[here-1] < ' ' || (buf[here-1] & 0x80) )
X		  					 buf[here-1] = '?';
X		    if (++mcol == 80) {
X		     	mcol = 0;
X		     	if (++mline == 23) {
X		       		fflush(stdout);
X		       		write(1, buf + start, here - start);
X		       		fflush(stdout);
X		       		fprintf(stderr, 
X					"\007\033[7m--More--\033[0m");
X		       		do {
X			   	    read(fd, &cmd, 1);
X       			  	} while (strchr(" \r\nqQ'nN", cmd)
X							== (char *)NULL);
X		       		fprintf(stderr, "\r\033[K");
X		       		mline = 0;
X		       		start = here;
X		      	}
X		    }
X       	}
X      	switch (cmd) {
X		case '\0':
X			break;
X		case ' ':
X			mline = 0;
X		   	break;
X		case '\r':
X		case '\n':
X			mline = 23 - 1;
X		   	break;
X		case 'q':
X		case 'Q':
X			misdone = 1;
X		   	return(1);
X		case 'n':
X		case 'N':
X			misdone = 1;
X			return(1);
X		default:
X			break;
X	}
X  }
X  if (here != start) {
X	fflush(stdout);
X	write(1, buf + start, here - start);
X	fflush(stdout);
X  }
X}
X
X
X/*
X * Display the given letter on the screen.
X * Do this on a per-page basis...
X */
Xvoid showlet(let)
XLETTER *let;
X{
X  struct sgttyb ttymode;
X  off_t curr, limit;
X  int c, fd, st;
X
X  if ((fd = open("/dev/tty", 0)) == -1) {
X	fprintf(stderr, "%s: cannot open /dev/tty\n", progname);
X	return;
X  }
X  ioctl(fd, TIOCGETP, &ttymode);
X  ttymode.sg_flags |= CBREAK;
X  ttymode.sg_flags &= ~ECHO;
X  ioctl(fd, TIOCSETP, &ttymode);
X
X  fseek(boxfp, (curr = let->location), 0);
X  limit = (let->next != NIL_LET) ? let->next->location : -1L;
X
X  st = mline = mcol = mobc = misdone = 0;
X  printf("Message %d:\n", let->seqno);
X  while(curr != limit && ((c = fgetc(boxfp)) != EOF) && st==0) {
X	if (mobc == sizeof(mobuf)) {
X		st = lwrite(fd, mobuf, strlen(mobuf));
X        	mobc = 0;
X       	}
X      	mobuf[mobc++] = (char) c;
X      	++curr;
X  }
X  if (st == 0) lwrite(fd, mobuf, mobc);
X  mobc = 0;
X  fflush(stdout);
X
X  ttymode.sg_flags &= ~CBREAK;
X  ttymode.sg_flags |= ECHO;
X  ioctl(fd, TIOCSETP, &ttymode);
X  close(fd);
X}
X
X
X/*
X * Print the contents of letter 'let' to file 'tofp'
X */
Xvoid printlet(let, tofp)
XLETTER *let;
XFILE *tofp;
X{
X  off_t curr, limit, oldpos;
X  int c;
X
X  if (tofp==stdout && !printmode) {
X	showlet(let);
X	return;
X  }
X
X  oldpos = ftell(boxfp);
X  fseek(boxfp, (curr = let->location), 0);
X  limit = (let->next != NIL_LET) ? let->next->location : -1L;
X
X  if (tofp == stdout) printf("Message %d:\n", let->seqno);
X  while(curr != limit && (c = fgetc(boxfp)) != EOF) {
X	fputc(c, tofp);
X	++curr;
X  }
X  fflush(tofp);
X  fseek(boxfp, oldpos, 0);
X}
X
X
X/*
X * Print all letters and quit.
X */
Xvoid printall()
X{
X  LETTER *let;
X
X  let = firstlet;
X  if (let == NIL_LET) {
X	fprintf(stderr, "No mail for %s.\n", sender);
X	return;
X  }
X
X  while(let != NIL_LET) {
X      	printlet(let, stdout);
X      	let = let->next;
X  }
X}
+ END-OF-FILE wmread.c
chmod 'u=rw,g=r,o=r' 'wmread.c'
set `wc -c 'wmread.c'`
count=$1
case $count in
4664)	:;;
*)	echo 'Bad character count in ''wmread.c' >&2
		echo 'Count should be 4664' >&2
esac
echo Extracting 'wmtime.c'
sed 's/^X//' > 'wmtime.c' << '+ END-OF-FILE ''wmtime.c'
X/*
X * XTIME	-	Create ASCII string of the given time.
X *			This file contains a modified version
X *			of the ctime(3) function from the MINIX
X *			C library. The format of the string is:
X *
X *				Sat, Oct 14 89 20:26:00\0
X *
X */
X#include <time.h>
X
Xstatic int days_per_month[] = {
X	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X};
Xstatic char *months[] = { 
X	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X};
Xstatic char *days[] = {
X	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X};
X
X#define	MIN	60L		/* # seconds in a minute */
X#define	HOUR	(60 * MIN)	/* # seconds in an hour */
X#define	DAY	(24 * HOUR)	/* # seconds in a day */
X#define	YEAR	(365 * DAY)	/* # seconds in a year */
X
Xchar *xtime(void)
X{
X  static struct tm tm;
X  static char xtmbuf[30];
X  long t;
X  long year;
X
X  time(&t);
X  tm.tm_year = 0;
X  tm.tm_mon = 0;
X  tm.tm_mday = 1;
X  tm.tm_hour = 0;
X  tm.tm_min = 0;
X  tm.tm_sec = 0;
X
X  /* t is elapsed time in seconds since Jan 1, 1970. */
X  tm.tm_wday = (int) (t/DAY + 4L) % 7;	/* Jan 1, 1970 is 4th wday */
X  while (t >= (year=((tm.tm_year%4)==2) ? YEAR+DAY : YEAR)) {
X	tm.tm_year += 1;
X	t -= year;
X  }
X  tm.tm_year += 1970;
X
X  /* t is now the offset into the current year, in seconds. */
X  tm.tm_yday = (t/DAY);		/* day # of the year, Jan 1 = 0 */
X
X  days_per_month[1] = 28;
X  if ((tm.tm_year % 4) == 0)	/* check for leap year */
X		days_per_month[1]++;
X
X  /* Compute month. */
X  while (t >= (days_per_month[tm.tm_mon] * DAY))
X		t -= days_per_month[tm.tm_mon++] * DAY;
X
X  /* Month established, now compute day of the month */
X  while (t >= DAY) {
X	t -= DAY;
X	tm.tm_mday++;
X  }
X
X  /* Day established, now do hour. */
X  while (t >= HOUR) {
X	t -= HOUR;
X	tm.tm_hour++;
X  }
X
X  /* Hour established, now do minute. */
X  while (t >= MIN) {
X	t -= MIN;
X	tm.tm_min++;
X  }
X
X  /* Residual time is # seconds. */
X  tm.tm_sec = (int) t;
X
X  /* Generate output in ASCII in _buf_. */
X  sprintf(xtmbuf, "%s, %2.2d %s %2.2d %02d:%02d:%02d",
X	days[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], 
X	    tm.tm_year - 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); 
X  return(xtmbuf);
X}
+ END-OF-FILE wmtime.c
chmod 'u=rw,g=r,o=r' 'wmtime.c'
set `wc -c 'wmtime.c'`
count=$1
case $count in
2099)	:;;
*)	echo 'Bad character count in ''wmtime.c' >&2
		echo 'Count should be 2099' >&2
esac
exit 0