Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!hplabs!hpl-opus!hpnmdla!billm From: billm@hpnmdla.HP.COM (Bill Marlin) Newsgroups: comp.os.minix Subject: Re: Wmail 2.6 (Posted for F. van Kempen; I haven't looked at it) Message-ID: <610003@hpnmdla.HP.COM> Date: 9 Nov 89 14:32:24 GMT References: <4465@ast.cs.vu.nl> Organization: HP Network Measurements Div, Santa Rosa, CA Lines: 2155 / hpnmdla:comp.os.minix / ast@cs.vu.nl (Andy Tanenbaum) / 2:52 am Nov 8, 1989 / : 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 'Makefile' sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile' X# X# Makefile for W-MAIL Local Mail Agent (MINIX) X# X# Makefile @(#)1.4 MicroWalt W-MAIL V2.6 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 wmail Makefile wmail.h X X Xwmail: $(OBJS) X cc $(LDFLAGS) -o wmail $(OBJS) X @chmem =20000 wmail >/dev/null X Xinstall: 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 4555 $(BIN)/wmail X Xshar: X @rm -f wmail.shar X @shar -C -u -v -o wmail.shar $(OTHERS) $(SRCS) X Xtar: X @rm -f wmail.tar X @tar cfv wmail.tar $(OTHERS) $(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 1576) :;; *) echo 'Bad character count in ''Makefile' >&2 echo 'Count should be 1576' >&2 esac echo Extracting 'README' sed 's/^X//' > 'README' << '+ END-OF-FILE ''README' X W-MAIL Local Mail Agent (MINIX) X X MicroWalt W-MAIL V2.6 X ===================== X XThis archive contains the sources of the W-MAIL program, which Xis a MINIX version of the MAILX program available on most UNIXes. X XIt does not need the presence of UUCP in order to run. However, Xfor non-local mail delivery a remote mailer (like MicroWalt UMAIL) Xis required to be present. X XRevision History: X2.5 10/10/89 Initial posting. X X2.6 11/07/89 General fixes and a cleanup. X - The Makefile-macro 'OTHERS' now contains 'wmail.h' X as well. This caused incomplete archives to be X distributed. Also, the parameters to 'shar' and 'tar' X have been adapted to the new tar(1) and shar(1) programs. X X - Fixed '.' problem in edit_mail(). X X - The strings 'findbuff', 'lbuff' and 'inbuff' have been X moved to the routines in which they are used. X X - The bug in the more() code has been fixed. This bug X cause gargabe to be printed in some circumstances. X X - The dead_letter() function no longer puts the file X in the user's HOME directory. It now looks if there X is an environmental variable "DEADLETTER"; if it X exists its value will be used as the file name. X Otherwise, the message will be dumped in the file X "dead.letter" in the current directory. X X - All references to 'NIL' have been changed into 'NULL'. X It was a bit confusing to have both around. X X - The code to scan message-headers has been changed X radically. All message fields are now stored in the X 'LETTER' structure dynamically. This saves a lot of X memory, and thus allows for larger mailboxes. X X - The 'reply' bug has been fixed. This bug was caused X by the UMAIL mailer, because it generated the wrong X type of "From_" header. The header is now scanned by X a separate routine in 'ummain.c' called 'old_hdr()'. X X - The source has been edited to make it conform to the X new MINIX Style Sheet as posted by Andrew Tanenbaum. X X - The version-number has been increased to 2.6. X X X XOne last note: X If you are compiling this program, and you get a lot of X "illegal conversion of int to pointer" errors, please make X sure that your header files in /usr/include have the X "extern" declarations. Do NOT add them to this program... X XEnjoy! X 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 2591) :;; *) echo 'Bad character count in ''README' >&2 echo 'Count should be 2591' >&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] ... X lmail [-v] [-i inputfile] ... 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 X To: X Subject: X 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 so that it can X be resent. If an environmental variable "DEADLETTER" is X defined, its value will be used as the file name. Other- X wise, the name 'dead.letter' will be used in the current X directory. Also, some diagnostics will be printed on the X terminal 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 X X X X X -- 2 -- X X X XWMAIL(1) MINIX User's Manual WMAIL(1) X 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 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 -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 -- 3 -- X X 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 6511) :;; *) echo 'Bad character count in ''wmail.doc' >&2 echo 'Count should be 6511' >&2 esac echo Extracting 'wmail.h' sed 's/^X//' > 'wmail.h' << '+ END-OF-FILE ''wmail.h' 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 * D E F I N I T I O N S X * X * Author: Fred van Kempen, MicroWalt Corporation X */ X#include X#include X X X#define VERSION "2.6 (11/07/89)" X X#define DROPNAME "/usr/spool/mail/%s" /* User Mailbox */ X#define LOCKNAME "/usr/spool/mail/%s.lock" /* lockfile for box */ X#define MAILTEMP "/tmp/mailXXXXXX" /* temp. file */ X#define COPYTEMP "/tmp/mcpyXXXXXX" /* temp update file */ X#define SHELL "/bin/sh" X#define RMAIL "/usr/bin/rmail" /* the Internet Mailer */ X#define SAVEFILE "mbox" /* default mailsave */ X#define SIGNATURE ".signature" X#define DEADLETTER "dead.letter" X#define PROMPT "[%d]& " X X#ifndef PATHLEN X# define PATHLEN 128 X#endif PATHLEN X X#ifndef TRUE X# define FALSE 0 X# define TRUE 1 X#endif X X#define LOCKWAIT 5 /* seconds to wait after collision */ X#define LOCKTRIES 4 /* maximum number of collisions */ X#define MAXRCPT 100 /* maximum number of recipients */ X#define LINELEN 512 X X#define UNREAD 1 /* 'not read yet' status */ X#define DELETED 2 /* 'deleted' status */ X#define READ 3 /* 'has been read' status */ X X Xtypedef struct _letter{ X struct _letter *prev; /* linked letter list: previous letter */ X struct _letter *next; /* linked letter list: next letter */ X off_t location; /* location within mailbox file */ X int status; /* letter status */ X int seqno; /* letter number */ X char *subject; /* subject of message */ X char *sender; /* sender of message */ X char date[32]; /* date of message */ X} LETTER; X#define NIL_LET (LETTER *)NULL X X Xextern char *Version; Xextern int remote; /* use RMAIL to deliver (if any) */ Xextern int loclink; /* LMAIL: local delivery only! */ Xextern int old_uid, old_gid; /* UID/GID of calling user */ Xextern int printmode; /* print-and-exit mode */ Xextern int immediate; /* send remote immediately! */ Xextern int quitmode; /* take interrupts */ Xextern int usedrop; /* read the maildrop (no -f given) */ Xextern int verbose; /* pass "-v" flag on to mailer */ Xextern int needupdate; /* need to update mailbox */ Xextern int sayall; /* include line with all recipients */ Xextern int checkonly; /* only chack if there is mail */ Xextern char sender[PATHLEN]; /* who sent the message? */ Xextern char forward[PATHLEN]; /* who is the message forwarded to? */ Xextern char adressee[PATHLEN]; /* current recipient */ Xextern char recipients[PATHLEN]; /* also to... users */ Xextern char mailbox[PATHLEN]; /* user's mailbox/maildrop */ Xextern char subject[PATHLEN]; /* subject of message */ Xextern char msg_temp[PATHLEN]; /* temporary file */ Xextern FILE *infp; /* current message input file */ Xextern FILE *boxfp; /* mailbox file */ Xextern char *progname; /* program name */ Xextern jmp_buf printjump; /* for quitting out of letters */ Xextern LETTER *firstlet, *lastlet; /* message pointers for readbox() */ Xextern int numlet, nextlet, seqno; /* number of active letters */ Xextern unsigned oldmask; /* saved umask() */ X X Xextern char *getenv(); /* these are in libc.a */ Xextern FILE *fdopen(); Xextern long ftell(); X X Xextern void onint(/* void */); Xextern char *basename(/* char *name */); Xextern char *basepath(/* char *name */); Xextern char *whoami(/* void */); Xextern void showlet(/* LETTER *let */); Xextern void printlet(/* LETTER *let, FILE *tofp */); Xextern void printall(/* void */); Xextern void dead_letter(/* void */); Xextern char *find_string(/* LETTER *let, char *text */); Xextern void updatebox(/* void */); Xextern void interact(/* void */); Xextern void send_remote(/* char *name */); Xextern FILE *edit_mail(/* void */); Xextern int chk_box(/* void */); Xextern int deliver(/* int count, char *vec[] */); Xextern char *xtime(/* void */); X + END-OF-FILE wmail.h chmod 'u=rw,g=r,o=r' 'wmail.h' set `wc -c 'wmail.h'` count=$1 case $count in 4199) :;; *) echo 'Bad character count in ''wmail.h' >&2 echo 'Count should be 4199' >&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 * Revisions: X * 11/07/89 FvK Edited a little for the new MSS. X */ X#include X#include X#include 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 char cpbuff[1024]; /* copy buffer */ X char tmp[PATHLEN]; X register FILE *tempfp, *sigfp; X register char *sp, *bp; X register int c; 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 X * Subject: (if -s on command line or stdin) X * To: (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 != NULL) *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 = FALSE; X state = 1; /* start out in 'newline' state */ X do { X if ((c = fgetc(infp)) != EOF) { X switch(c) { X case '\n': /* mark this newline */ X if (state == 0) state++; X else if (state == 2) done = TRUE; X X fputc(c, tempfp); X break; X case '.': /* was previous a newline? */ X if (state == 1) state++; X else fputc(c, tempfp); X break; X default: /* clear 'newline' flag */ X if (state == 2) fputc('.', tempfp); X state = 0; X fputc(c, tempfp); X } X } else done = TRUE; X } while (done == FALSE); 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 == NULL) { X sp = getenv("HOME"); X if (sp != NULL) { 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 3741) :;; *) echo 'Bad character count in ''wmcreate.c' >&2 echo 'Count should be 3741' >&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 * Revisions: X * 11/07/89 FvK Edited a little for the new MSS. X * Fixed "dead.letter" pathname. X * X * To Do: X * - Aliases. X */ X#include X#include X#include X#include X#include X#include 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 char lockname[PATHLEN]; /* maildrop lock */ X char copytemp[PATHLEN]; /* temporary copy file */ X FILE *copyfp; /* fp for tempfile */ X LETTER *let; /* current letter */ X int locktries = 0; /* tries when box is locked */ 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\n", progname); X fprintf(stderr, "%sMail 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 int (*sigint)(), (*sighup)(), (*sigquit)(); /* saved signal state */ X char cpbuff[1024]; /* copy buffer */ X char lockname[PATHLEN]; /* maildrop lock */ X FILE *mailfp; /* fp for mail */ X struct stat stb; /* for checking drop modes, owners */ X struct passwd *pw; /* sender and recipent */ X int errs = 0; /* count of errors */ X int dropfd; /* file descriptor for user's drop */ X int created = FALSE; /* true if we created the maildrop */ X int locktries; /* tries when box is locked */ X register int i, c; 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 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 = TRUE; /* the guy is remote... */ X send_remote(adressee); /* call RMAIL 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 = TRUE; X send_remote(adressee); /* No, call RMAI */ 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 = 0; X 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) ? FALSE : TRUE); X} X X X/* X * Save the current message to file 'dead.letter'. X * This is sometimes needed when delivery fails. X * X * If the environmental variable "DEADLETTER" is defined, X * use its value as the file name. Otherwise, use DEADLETTER X * in the current directory. 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("DEADLETTER")) != NULL) strcpy(fname, sp); X else strcpy(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 9643) :;; *) echo 'Bad character count in ''wmdeliver.c' >&2 echo 'Count should be 9643' >&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 * Revisions: X * 11/07/89 FvK Edited a little for the new MSS. X * X * To Do: X * - Builtin escapes (~i and friends) X */ X#include X#include X#include X#include X#include 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 status, pid; X char *shell; X X if ((shell = getenv("SHELL")) == NULL) shell = SHELL; X X if ((pid = fork()) == 0) { X setgid(old_gid); /* UUCP or USER */ X setuid(old_uid); /* UUCP or USER */ X umask(oldmask); X X execl(shell, shell, "-c", command, NULL); X fprintf(stderr, "%s: cannot exec shell", progname); X exit(127); X } else { X if (pid > 0) wait(&status); X else fprintf(stderr, "%s: could not fork", progname); X } X} X X X/* X * Goto a specific letter. X */ Xstatic LETTER *goto_letter(num) Xregister int num; X{ X register 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 the current message. X * Do this by just updating the 'boxfp' pointer... X */ Xstatic off_t skiphead(void) X{ X char skbuf[1024]; X off_t count; X X count = (off_t) 0; X while (fgets(skbuf, sizeof(skbuf), boxfp) != NULL) { X count += (off_t) strlen(skbuf); X if (skbuf[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 off_t curr, limit, oldpos; X register char *bp; X FILE *savefp; X int c; 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), SEEK_SET); X limit = (let->next != NIL_LET) ? let->next->location : -1L; X X if (withhead == 0) curr += skiphead(); /* 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, SEEK_SET); 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("\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; idate; X if (strchr(sp, ',')) sp += 5; /* xtime() or 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 printf("\n"); X} X X X/* X * Interactively read the mail-box. X * This routine has to be improved a lot. X */ Xvoid interact(void) X{ X char input[512]; /* user input line */ X LETTER *let, *templet, dummy; /* current and next letter */ X int interrupted = FALSE; /* SIGINT hit during letter print */ X char *savefile, *p; 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(); /* Show a summary of all the letters. */ X X while(TRUE) { X nextlet = let->seqno; X X if (!quitmode) { X interrupted = setjmp(printjump); X signal(SIGINT, onint); X } X X if (interrupted = TRUE) printf("\n"); X printf(PROMPT, let->seqno); X fflush(stdout); X X if (fgets(input, sizeof(input), stdin) == NULL) break; X X if (!quitmode) signal(SIGINT, SIG_IGN); X X /* X * Look at the first character of the command line. X * This should be improved! X */ X switch(input[0]) { X case '!': /* Shell escape. */ X do_shell(&input[1]); X continue; X case '?': /* Type some help. */ X do_help(); X continue; X case '-': /* Show previous letter. */ X if (let->prev != NIL_LET) let = let->prev; X else printf("Top of mailbox\n"); X continue; X case '+': /* Show next letter. */ 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': /* Delete current letter. */ X let->status = DELETED; X if (let->next != NIL_LET) let = let->next; X needupdate = TRUE; X continue; X case 'i': /* Show letter summary */ X summary(); X continue; X case 'p': /* Print a letter. */ X if (!interrupted) printlet(let, stdout); X continue; X case 'q': /* Update mailbox and quit. */ X return; X case 'r': /* Reply to a message. */ X do_reply(let); X break; X case 's': /* Save message to disk. */ X savefile = &input[1]; X if (*savefile != '\0') { X while (*savefile==' ' || *savefile=='\t') X savefile++; X } else savefile = SAVEFILE; X savelet(let, savefile, TRUE); X continue; X case 't': /* Type (no paging) current letter. */ X temp = printmode; X printmode = TRUE; X if (!interrupted) printlet(let, stdout); X printmode = temp; X continue; X case 'w': /* Write (without header) message to disk. */ X savefile = &input[1]; X if (*savefile != '\0') { X while (*savefile==' ' || *savefile=='\t') X savefile++; X } else savefile = SAVEFILE; X savelet(let, savefile, FALSE); X continue; X case 'x': /* Abort, do not update mailbox. */ 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 7742) :;; *) echo 'Bad character count in ''wminteract.c' >&2 echo 'Count should be 7742' >&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 * Revisions: X * 11/07/89 FvK Edited a little for the new MSS. X * Allocate the "From_" path dynamically; X * it uses too much space now. X * Fixed the "reply" bug that was caused X * by a badly-decoded "From_" line. X */ X#include X#include X#include X#include X#include X#include X#include 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 */ 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 int getopt(), optind; /* from the GETOPT(3) package */ Xextern char *optarg; Xextern int errno; /* from STDIO */ X X Xvoid onint(void) X{ X longjmp(printjump, TRUE); X} X X X/* X * Chop off the last (file) part of a filename. X */ Xchar *basename(name) Xregister char *name; X{ X register char *p; X X p = strrchr(name, '/'); X if (p == NULL) 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) Xregister char *name; X{ X register char *p; X X p = strrchr(name, '!'); X if (p == NULL) 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 register 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 entry 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 static char findbuff[128]; X static char inbuff[512]; X off_t curr, limit; X register char *sp; X int all; X X fseek(boxfp, let->location, SEEK_SET); X limit = (off_t) -1L; X if (let->next != NIL_LET) limit = let->next->location; X X all = FALSE; X curr = let->location; X while (curr != limit && all==FALSE) { X if (fgets(inbuff, sizeof(inbuff), boxfp) == NULL) all = TRUE; X if (inbuff[0] == '\0') all = TRUE; /* 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==FALSE && limit > 0L) /* quit if past message */ X if (curr >= limit) all = TRUE; X } X return(NULL); 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 FILE *fp; X char *bp; 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!=NULL && !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 * Decode an old-style (V6/V7) mail header. X * This is a line like: X * X * From [remote from ] X * X * We want to find out the , and possible fields. X */ Xstatic void old_hdr(let, text) XLETTER *let; /* which letter? */ Xchar *text; /* message header text */ X{ X register char *bp, *sp, *cp; X int i; X X /* First, mark the end of the 'user' field. */ X sp = text; X X /* skip until field */ X while (*sp && *sp!=' ' && *sp!='\t') sp++; X *sp++ = '\0'; /* mark end, 'text' is now */ X X /* X * SP now contains and (possible) fields. X * Parse line to seek out "remote from". X */ X cp = sp; /* save the Date-pointer */ X while (TRUE) { X bp = strchr(sp++, 'r'); X if (bp != NULL) { /* we found an 'r' */ X if (!strncmp(bp, "remote from ", 12)) break; X } else break; X } X X if (bp != NULL) { /* host found --> remote mail */ X sp = strrchr(bp, ' '); /* start of "remote from" text */ X *(bp - 1) = '\0'; /* mark end-of-date */ X strcpy(let->date, cp); /* set date */ X i = strlen(++sp); /* set length of hostname */ X } else { X strcpy(let->date, cp); /* set date */ X i = 0; /* no hostname! */ X } X let->sender = (char *)malloc(strlen(text) + i + 5); X if (let->sender == NULL) { /* no memory left! */ X fprintf(stderr, "%s: out of memory.\n", progname); X exit(1); X } X if (i > 0) sprintf(let->sender, "%s!%s", sp, text); X else strcpy(let->sender, text); X} X X X/* X * Read the contents of the Mail-Box into memory. X */ Xstatic int readbox(void) X{ X static char lbuff[512]; 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 = (off_t) 0; X while(fgets(lbuff, sizeof(lbuff), boxfp) != NULL) { 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 "); /* Find the "From_" field. */ X if (sp == NULL) { X fprintf(stderr, "%s: no \"From\"-line.\n", progname); X exit(-1); X } X old_hdr(let, sp); /* decode it */ X X /* Find the "Subject" field, if any... */ X sp = find_string(let, "Subject: "); X if (sp == NULL) sp = ""; X X /* ..and stuff it in memory. */ X let->subject = (char *)malloc(strlen(sp) + 1); X if (let->subject == NULL) { /* no memory left! */ X fprintf(stderr, "%s: out of memory.\n", progname); X exit(1); X } X strcpy(let->subject, sp); 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) == NULL) { 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 = FALSE; /* 'lmail' link? */ X loclink = TRUE; 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': /* Deliver immediately. */ X immediate++; X break; X case 'e': /* Only check for mail, do not read it. */ X checkonly++; X break; X case 'f': /* use another mailbox. */ X setuid(old_uid); X setgid(old_gid); X usedrop = FALSE; X strncpy(mailbox, optarg, PATHLEN - 1); X break; X case 'i': /* Use another input-file. */ 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': /* Specify 'local' mail; same as 'lmail'. */ X loclink = TRUE; X break; X case 'p': /* Print all messages and exit. */ X printmode++; X break; X case 'q': /* Abort if SIGINT received. */ X quitmode++; X break; X case 'r': /* Show messages in reverse order. */ X break; /* This is only present for comp. with binmail! */ X case 's': /* Specify "subject" line. */ X strcpy(subject, optarg); X break; X case 't': /* Show all adressees in "To:" line. */ X sayall++; X break; X case 'v': /* Turn on debugging. */ 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 11449) :;; *) echo 'Bad character count in ''wmmain.c' >&2 echo 'Count should be 11449' >&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 * Revisions: X * 11/07/89 FvK Edited a little for the new MSS. X * X * To Do: X * - TERMCAP/TERMINFO use ! X */ X#include X#include X#include X#include X#include "wmail.h" X X Xstatic char mobuf[128]; /* output buffer */ Xstatic int mline; /* current terminal line */ Xstatic int mcol; /* current terminal column */ 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 int 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, 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 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), SEEK_SET); 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 == 128) { X st = lwrite(fd, mobuf, 128); 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), SEEK_SET); 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, SEEK_SET); X} X X X/* X * Print all letters and quit. X */ Xvoid printall(void) 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 4717) :;; *) echo 'Bad character count in ''wmread.c' >&2 echo 'Count should be 4717' >&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 of the ctime(3) X * function from the MINIX C library. The format of the X * new string is: X * X * Tue, Nov 7 89 20:09:00\0 X * X */ X#include X 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 X Xchar *xtime(void) X{ X static char xtmbuf[30]; X struct tm tm; X long t, 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 xtmbuf. */ 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 2088) :;; *) echo 'Bad character count in ''wmtime.c' >&2 echo 'Count should be 2088' >&2 esac exit 0 ----------