taylor@hplabs.HP.COM (Dave Taylor) (01/16/88)
While working on getting the latest version of Elm up and happy, I
noticed that the 'filter' program wasn't interacting with Elm too
well about lock files. Further investigation showed that in fact
the locking routines used within the filter program are garbage
and, as far as I could tell, accomplish nothing. Not good.
So I took the specific lock() and unlock() calls and put them in
a different file, rewriting "actions.c" along the way. If you
are using "filter" then you should update to the version included
herein ASAP to ensure you don't have any problems (I lost about
ten messages out of my mailbox before I tracked it down).
And again, if anyone has noticed any other quirks in any of the parts
of Elm, please drop me a note!
-- Dave Taylor
-- -- -- partial shell archive for "filter" program: -- -- --
# Shell Archive created by taylor@atom.HPL.HP.COM at Fri Jan 15 11:11:49 1988
# To unpack the enclosed files, please use this file as input to the
# Bourne (sh) shell. This can be most easily done by the command;
# sh < thisfilename
# This archive contains;
# Patch.Instruct actions.c lock.c
# ---------- file Patch.Instruct ----------
filename="Patch.Instruct"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file Patch.Instruct...
fi
cat << 'END-OF-FILE' > $filename
This patch to filter should be real easy to install: just
unpack the two files contained in the shar file (they are
"lock.c" and "actions.c") letting the latter replace the
existing one in your source tree, then go into your Makefile
("Elm/filter/Makefile") and change the SRC and OBJ targets
to include the new file "lock.c" as appropriate.
Then just type "make" for it to be rebuilt.
Sorry for the confusion.
Dave Taylor
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 428 ]
then
echo $filename changed - should be 428 bytes, not $size bytes
fi
chmod 666 $filename
fi
# ---------- file actions.c ----------
filename="actions.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file actions.c...
fi
cat << 'END-OF-FILE' > $filename
/** actions.c **/
/** RESULT oriented routines *chuckle*. These routines implement the
actions that result from either a specified rule being true or from
the default action being taken.
(C) Copyright 1986, Dave Taylor
**/
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>
#include <fcntl.h>
#include "defs.h"
#include "filter.h"
FILE *emergency_local_delivery();
mail_message(address)
char *address;
{
/** Called with an address to send mail to. For various reasons
that are too disgusting to go into herein, we're going to actually
open the users mailbox and by hand add this message. Yech.
NOTE, of course, that if we're going to MAIL the message to someone
else, that we'll try to do nice things with it on the fly...
**/
FILE *pipefd, *tempfd, *mailfd;
int in_header = TRUE, line_count = 0;
char tempfile[SLEN], mailbox[SLEN], lockfile[SLEN],
buffer[VERY_LONG_STRING];
if (verbose && ! log_actions_only && outfd != NULL)
fprintf(outfd, "filter (%s): Mailing message to %s\n",
username, address);
if (! show_only) {
sprintf(tempfile, "%s.%d", filter_temp, getpid());
if ((tempfd = fopen(tempfile, "r")) == NULL) {
if (outfd != NULL)
fprintf(outfd, "filter (%s): Can't open temp file %s!!\n",
username, tempfile);
if (outfd != NULL) fclose(outfd);
exit(1);
}
if (strcmp(address, username) != 0) { /* mailing to someone else */
if (already_been_forwarded) { /* potential looping! */
if (contains(from, username)) {
if (outfd != NULL)
fprintf(outfd,
"filter (%s): Filter loop detected! Message left in file %s.%d\n",
username, filter_temp, getpid());
if (outfd != NULL) fclose(outfd);
exit(0);
}
}
sprintf(buffer, "%s %s %s", sendmail, smflags, address);
if ((pipefd = popen(buffer, "w")) == NULL) {
if (outfd != NULL)
fprintf(outfd, "filter (%s): popen %s failed!\n", buffer);
sprintf(buffer, "((%s %s %s ; %s %s) & ) < %s &",
sendmail , smflags, address, remove, tempfile, tempfile);
system(buffer);
return;
}
fprintf(pipefd, "Subject: \"%s\"\n", subject);
fprintf(pipefd, "From: The Filter of %s@%s <%s>\n",
username, hostname, username);
fprintf(pipefd, "To: %s\n", address);
fprintf(pipefd, "X-Filtered-By: filter, version %s\n\n", VERSION);
fprintf(pipefd, "-- Begin filtered message --\n\n");
while (fgets(buffer, LONG_SLEN, tempfd) != NULL)
if (already_been_forwarded && in_header)
in_header = (strlen(buffer) == 1? 0 : in_header);
else
fprintf(pipefd," %s", buffer);
fprintf(pipefd, "\n-- End of filtered message --\n");
fclose(pipefd);
fclose(tempfd);
return; /* YEAH! Wot a slick program, eh? */
}
/** OTHERWISE it is to the current user... **/
sprintf(mailbox, "%s%s", mailhome, username);
if (! lock()) {
if (outfd != NULL) {
fprintf(outfd, "filter (%s): Couldn't create lockfile %s\n",
username, lockfile);
fprintf(outfd, "filter (%s): Can't open mailbox %s!\n",
username, mailbox);
}
if ((mailfd = emergency_local_delivery()) == NULL)
exit(1);
}
else if ((mailfd = fopen(mailbox,"a")) == NULL)
if ((mailfd = emergency_local_delivery()) == NULL)
exit(1);
while (fgets(buffer, sizeof(buffer), tempfd) != NULL) {
line_count++;
if (the_same(buffer, "From ") && line_count > 1)
fprintf(mailfd, ">%s", buffer);
else
fputs(buffer, mailfd);
}
fputs("\n", mailfd);
fclose(mailfd);
unlock(); /* blamo or not? Let it decide! */
fclose(tempfd);
} /* end if show only */
}
save_message(foldername)
char *foldername;
{
/** Save the message in a folder. Use full file buffering to
make this work without contention problems **/
FILE *fd, *tempfd;
char filename[SLEN], buffer[LONG_SLEN];
if (verbose && outfd != NULL)
fprintf(outfd, "filter (%s): Message saved in folder %s\n",
username, foldername);
if (!show_only) {
sprintf(filename, "%s.%d", filter_temp, getpid());
if ((fd = fopen(foldername, "a")) == NULL) {
if (outfd != NULL)
fprintf(outfd,
"filter (%s): can't save message to requested folder %s!\n",
username, foldername);
return(1);
}
if ((tempfd = fopen(filename, "r")) == NULL) {
if (outfd != NULL)
fprintf(outfd,
"filter (%s): can't open temp file for reading!\n",
username);
return(1);
}
while (fgets(buffer, sizeof(buffer), tempfd) != NULL)
fputs(buffer, fd);
fclose(fd);
fclose(tempfd);
}
return(0);
}
execute(command)
char *command;
{
/** execute the indicated command, feeding as standard input the
message we have.
**/
char buffer[LONG_SLEN];
if (verbose && outfd != NULL)
fprintf(outfd, "filter (%s): Executing %s\n",
username, command);
if (! show_only) {
sprintf(buffer, "%s %s.%d | %s", cat, filter_temp, getpid(), command);
system(buffer);
}
}
FILE *
emergency_local_delivery()
{
/** This is called when we can't deliver the mail to the usual
mailbox in the usual way ...
**/
FILE *tempfd;
char mailbox[SLEN];
sprintf(mailbox, "%s/%s", home, EMERGENCY_MAILBOX);
if ((tempfd = fopen(mailbox, "a")) == NULL) {
if (outfd != NULL)
fprintf(outfd, "filter (%s): Can't open %s either!!\n",
username, mailbox);
sprintf(mailbox,"%s/%s", home, EMERG_MBOX);
if ((tempfd = fopen(mailbox, "a")) == NULL) {
if (outfd != NULL) {
fprintf(outfd,"filter (%s): Can't open %s either!!!!\n",
username, mailbox);
fprintf(outfd,
"filter (%s): I can't open ANY mailboxes! Augh!!\n",
username);
}
fclose(tempfd);
leave("Cannot open any mailbox"); /* DIE DIE DIE DIE!! */
}
else
if (outfd != NULL)
fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
username, mailbox);
}
else
if (outfd != NULL)
fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
username, mailbox);
return((FILE *) tempfd);
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 6227 ]
then
echo $filename changed - should be 6227 bytes, not $size bytes
fi
chmod 666 $filename
fi
# ---------- file lock.c ----------
filename="lock.c"
if [ -f $filename ]
then
echo File \"$filename\" already exists\! Skipping...
filename=/dev/null # throw it away
else
echo extracting file lock.c...
fi
cat << 'END-OF-FILE' > $filename
/** locks.c **/
/** The lock() and unlock() routines herein duplicate exactly the
equivalent routines in the Elm Mail System, and should also be
compatible with sendmail, rmail, etc etc.
(C) Copyright 1986, 1987, 1988, Dave Taylor
**/
#include <stdio.h>
#include <fcntl.h>
#include "defs.h"
#include "filter.h"
int we_locked_it = 0;
char lockfile[SLEN];
int
lock()
{
/** This routine will return 1 if we could lock the mailfile,
zero otherwise.
**/
int attempts = 0, ret;
sprintf(lockfile, "%s%s.lock", mailhome, username);
while ((ret = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0777)) < 0
&& attempts++ < 10) {
sleep(3); /* wait three seconds each pass, okay?? */
}
if (ret > 0) {
we_locked_it++;
close(ret); /* no need to keep it open! */
}
return( (ret >= 0) );
}
unlock()
{
/** this routine will remove the lock file, but only if we were
the people that locked it in the first place... **/
if (we_locked_it)
unlink(lockfile); /* blamo! */
we_locked_it = 0;
}
END-OF-FILE
if [ "$filename" != "/dev/null" ]
then
size=`wc -c < $filename`
if [ $size != 1045 ]
then
echo $filename changed - should be 1045 bytes, not $size bytes
fi
chmod 666 $filename
fi
echo done
exit 0