Anonymous Contact Service software v1.1, Part07/08
Dave Mack
csu at alembic.acs.com
Mon Jul 16 03:13:34 AEST 1990
This is the second distribution of the Anonymous Contact Service
software. The distribution consists of 8 shar files. This will
(hopefully) be the last full distribution of the system - all
future versions will be distributed as patches. The patchlevel of
this version is 1.
The ACS software provides a mechanism for posting anonymous articles,
for receiving replies to those articles which are also anonymous, and
permits prolonged anonymous conversations in which neither writer knows
the other's actual e-mail address.
This software is currently being used to provide an anonymous personals
service in alt.personals.
Dave Mack
csu at alembic.ACS.COM
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 7 (of 8)."
# Contents: mailer/deliver.c unspool
# Wrapped by csu at alembic on Sun Jul 15 12:46:54 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mailer/deliver.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mailer/deliver.c'\"
else
echo shar: Extracting \"'mailer/deliver.c'\" \(12633 characters\)
sed "s/^X//" >'mailer/deliver.c' <<'END_OF_FILE'
X/*
X** Deliver.c
X**
X** Routines to effect delivery of mail for rmail/smail.
X**
X*/
X
X#ifndef lint
Xstatic char *sccsid="@(#)deliver.c 2.5 (smail) 9/15/87";
X#endif
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <sys/stat.h>
X# include <ctype.h>
X# include <signal.h>
X# include "defs.h"
X
Xextern int exitstat; /* set if a forked mailer fails */
Xextern enum edebug debug; /* how verbose we are */
Xextern char hostname[]; /* our uucp hostname */
Xextern char hostdomain[]; /* our host's domain */
Xextern enum ehandle handle; /* what we handle */
Xextern enum erouting routing; /* how we're routing addresses */
Xextern char *uuxargs; /* arguments given to uux */
Xextern int queuecost; /* threshold for queueing mail */
Xextern int maxnoqueue; /* max number of uucico's */
Xextern char *spoolfile; /* file name of spooled message */
Xextern FILE *spoolfp; /* file ptr to spooled message */
Xextern int spoolmaster; /* set if creator of spoolfile */
Xextern char nows[]; /* local time in ctime(3) format*/
Xextern char arpanows[]; /* local time in arpadate format*/
Xchar stderrfile[20]; /* error file for stderr traping*/
X#ifdef ACSMAIL
Xextern char *from_addr; /* From: line contents */
X#endif
X/*
X**
X** deliver(): hand the letter to the proper mail programs.
X**
X** Issues one command for each different host of <hostv>,
X** constructing the proper command for LOCAL or UUCP mail.
X** Note that LOCAL mail has blank host names.
X**
X** The <userv> names for each host are arguments to the command.
X**
X** Prepends a "From" line to the letter just before going
X** out, with a "remote from <hostname>" if it is a UUCP letter.
X**
X*/
X
Xdeliver(argc, hostv, userv, formv, costv)
Xint argc; /* number of addresses */
Xchar *hostv[]; /* host names */
Xchar *userv[]; /* user names */
Xenum eform formv[]; /* form for each address */
Xint costv[]; /* cost vector */
X{
X FILE *out; /* pipe to mailer */
X FILE *popen(); /* to fork a mailer */
X#ifdef RECORD
X void record(); /* record all transactions */
X#endif
X#ifdef LOG
X void log();
X#endif
X char *mktemp();
X char from[SMLBUF]; /* accumulated from argument */
X char lcommand[SMLBUF]; /* local command issued */
X char rcommand[SMLBUF]; /* remote command issued */
X char scommand[SMLBUF]; /* retry command issued */
X char *command; /* actual command */
X char buf[SMLBUF]; /* copying rest of the letter */
X enum eform form; /* holds form[i] for speed */
X long size; /* number of bytes of message */
X char *flags; /* flags for uux */
X char *sflag; /* flag for smail */
X int i, j, status, retrying;
X char *c, *postmaster();
X int failcount = 0;
X int noqcnt = 0; /* number of uucico's started */
X char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately */
X char *uux_queue = UUX_QUEUE; /* uucico job gets queued */
X off_t message;
X struct stat st;
X
X#ifdef ACSMAIL
X char acs_user[SMLBUF];
X char *atsign;
X strcpy(acs_user,from_addr);
X atsign = index(acs_user,'@');
X if (atsign) *atsign = '\000';
X/* fprintf(stderr,"from_addr = %s, acs_user = %s\n",from_addr,acs_user);*/
X#endif
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X (void) fseek(spoolfp, 0L, 0);
X (void) fgets(from, sizeof(from), spoolfp);
X#ifdef ACSMAIL
X strcpy(from,acs_user);
X#endif
X if((c = index(from, '\n')) != 0) *c = '\0';
X message = ftell(spoolfp);
X
X/*
X** We pass through the list of addresses.
X*/
X stderrfile[0] = '\0';
X for(i = 0; i < argc; i++) {
X char *lend = lcommand;
X char *rend = rcommand;
X char *send = scommand;
X
X/*
X** If we don't have sendmail, arrange to trap standard error
X** for inclusion in the message that is returned with failed mail.
X*/
X (void) unlink(stderrfile);
X (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
X (void) mktemp(stderrfile);
X (void) freopen(stderrfile, "w", stderr);
X if(debug != YES) {
X (void) freopen(stderrfile, "w", stdout);
X }
X
X *lend = *rend = *send = '\0';
X
X/*
X** If form == ERROR, the address was bad
X** If form == SENT, it has been sent on a previous pass.
X*/
X form = formv[i];
X if (form == SENT) {
X continue;
X }
X/*
X** Build the command based on whether this is local mail or uucp mail.
X** By default, don't allow more than 'maxnoqueue' uucico commands to
X** be started by a single invocation of 'smail'.
X*/
X if(uuxargs == NULL) { /* flags not set on command line */
X if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
X flags = uux_noqueue;
X } else {
X flags = uux_queue;
X }
X } else {
X flags = uuxargs;
X }
X
X retrying = 0;
X if(routing == JUSTDOMAIN) {
X sflag = "-r";
X } else if(routing == ALWAYS) {
X sflag = "-R";
X } else {
X sflag = "";
X }
X
X (void) sprintf(lcommand, LMAIL(from, hostv[i]));
X (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
X
X/*
X** For each address with the same host name and form, append the user
X** name to the command line, and set form = ERROR so we skip this address
X** on later passes.
X*/
X /* we initialized lend (rend) to point at the
X * beginning of its buffer, so that at
X * least one address will be used regardless
X * of the length of lcommand (rcommand).
X */
X for (j = i; j < argc; j++) {
X if ((formv[j] != form)
X || (strcmpic(hostv[i], hostv[j]) != 0)
X || ((lend - lcommand) > MAXCLEN)
X || ((rend - rcommand) > MAXCLEN)) {
X continue;
X }
X
X /*
X ** seek to the end of scommand
X ** and add on a 'smail' command
X ** multiple commands are separated by ';'
X */
X
X send += strlen(send);
X if(send != scommand) {
X *send++ = ';' ;
X }
X
X (void) sprintf(send, RETRY(sflag));
X send += strlen(send);
X
X lend += strlen(lend);
X rend += strlen(rend);
X
X if (form == LOCAL) {
X (void) sprintf(lend, LARG(userv[j]));
X (void) sprintf(send, LARG(userv[j]));
X } else {
X (void) sprintf(lend, RLARG(hostv[i], userv[j]));
X (void) sprintf(send, RLARG(hostv[i], userv[j]));
X }
X
X (void) sprintf(rend, RARG(userv[j]));
X formv[j] = SENT;
X }
Xretry:
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X (void) fseek(spoolfp, message, 0);
X
X /* if the address was in a bogus form (usually DOMAIN),
X ** then don't bother trying the uux.
X **
X ** Rather, go straight to the next smail routing level.
X */
X if(form == ERROR) {
X static char errbuf[SMLBUF];
X (void) sprintf(errbuf,
X "address resolution ('%s' @ '%s') failed",
X userv[i], hostv[i]);
X command = errbuf;
X size = 0;
X goto form_error;
X }
X
X if (retrying) {
X command = scommand;
X } else if (form == LOCAL) {
X command = lcommand;
X } else {
X command = rcommand;
X if(flags == uux_noqueue) {
X noqcnt++;
X }
X }
X ADVISE("COMMAND: %s\n", command);
X
X/*
X** Fork the mailer and set it up for writing so we can send the mail to it,
X** or for debugging divert the output to stdout.
X*/
X
X/*
X** We may try to write on a broken pipe, if the uux'd host
X** is unknown to us. Ignore this signal, since we can use the
X** return value of the pclose() as our indication of failure.
X*/
X (void) signal(SIGPIPE, SIG_IGN);
X
X if (debug == YES) {
X out = stdout;
X } else {
X failcount = 0;
X do {
X out = popen(command, "w");
X if (out) break;
X /*
X * Fork failed. System probably overloaded.
X * Wait awhile and try again 10 times.
X * If it keeps failing, probably some
X * other problem, like no uux or smail.
X */
X (void) sleep(60);
X } while (++failcount < 10);
X }
X if(out == NULL) {
X exitstat = EX_UNAVAILABLE;
X (void) printf("couldn't execute %s.\n", command);
X continue;
X }
X
X size = 0;
X if(fstat(fileno(spoolfp), &st) >= 0) {
X size = st.st_size - message;
X }
X/*
X** Output our From_ line.
X*/
X if (form == LOCAL) {
X#ifdef SENDMAIL
X#ifdef ACSMAIL
X (void) sprintf(buf, LFROM(acs_user, nows, hostname));
X#else
X (void) sprintf(buf, LFROM(from, nows, hostname));
X#endif /* ACSMAIL */
X size += strlen(buf);
X (void) fputs(buf, out);
X#else
X char *p;
X if((p=index(from, '!')) == NULL) {
X (void) sprintf(buf,
X#ifdef ACSMAIL
X LFROM(acs_user, nows, hostname));
X#else
X LFROM(from, nows, hostname));
X#endif /* ACSMAIL */
X size += strlen(buf);
X (void) fputs(buf, out);
X } else {
X *p = NULL;
X#ifdef ACSMAIL
X (void) sprintf(buf, RFROM(acs_user, nows, from));
X#else
X (void) sprintf(buf, RFROM(p+1, nows, from));
X#endif
X size += strlen(buf);
X (void) fputs(buf, out);
X *p = '!';
X }
X#endif
X } else {
X#ifdef ACSMAIL
X (void) sprintf(buf, RFROM(acs_user, nows, hostname));
X#else
X (void) sprintf(buf, RFROM(from, nows, hostname));
X#endif
X size += strlen(buf);
X (void) fputs(buf, out);
X }
X
X#ifdef SENDMAIL
X/*
X** If using sendmail, insert a Received: line only for mail
X** that is being passed to uux. If not using sendmail, always
X** insert the received line, since sendmail isn't there to do it.
X*/
X if(command == rcommand && handle != ALL)
X#endif
X {
X (void) sprintf(buf,
X "Received: by %s (%s)\n\tid AA%05d; %s\n",
X hostdomain, VERSION,
X getpid(), arpanows);
X size += strlen(buf);
X (void) fputs(buf, out);
X }
X
X/*
X** Copy input.
X*/
X while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X (void) fputs(buf, out);
X }
X/*
X** Get exit status and if non-zero, set global exitstat so when we exit
X** we can indicate an error.
X*/
Xform_error:
X if (debug != YES) {
X if(form == ERROR) {
X exitstat = EX_NOHOST;
X } else if (status = pclose(out)) {
X exitstat = status >> 8;
X }
X /*
X * The 'retrying' check prevents a smail loop.
X */
X if(exitstat != 0) {
X /*
X ** the mail failed, probably because the host
X ** being uux'ed isn't in L.sys or local user
X ** is unknown.
X */
X
X if((retrying == 0) /* first pass */
X && (routing != REROUTE) /* have higher level */
X && (form != LOCAL)) { /* can't route local */
X /*
X ** Try again using a higher
X ** level of routing.
X */
X ADVISE("%s failed (%d)\ntrying %s\n",
X command, exitstat, scommand);
X exitstat = 0;
X retrying = 1;
X form = SENT;
X goto retry;
X }
X
X /*
X ** if we have no other routing possibilities
X ** see that the mail is returned to sender.
X */
X
X if((routing == REROUTE)
X || (form == LOCAL)) {
X
X /*
X ** if this was our last chance,
X ** return the mail to the sender.
X */
X
X ADVISE("%s failed (%d)\n",
X command, exitstat);
X
X (void) fseek(spoolfp, message, 0);
X#ifdef SENDMAIL
X /* if we have sendmail, then it
X ** was handed the mail, which failed.
X ** sendmail returns the failed mail
X ** for us, so we need not do it again.
X */
X if(form != LOCAL)
X#endif
X {
X return_mail(from, command);
X }
X exitstat = 0;
X }
X }
X# ifdef LOG
X else {
X if(retrying == 0) log(command, from, size); /* */
X }
X# endif
X }
X }
X/*
X** Update logs and records.
X*/
X# ifdef RECORD
X (void) fseek(spoolfp, message, 0);
X record(command, from, size);
X# endif
X
X/*
X** close spool file pointer.
X** if we created it, then unlink file.
X*/
X (void) fclose(spoolfp);
X if(spoolmaster) {
X (void) unlink(spoolfile);
X }
X (void) unlink(stderrfile);
X}
X
X/*
X** return mail to sender, as determined by From_ line.
X*/
Xreturn_mail(from, fcommand)
Xchar *from, *fcommand;
X{
X char buf[SMLBUF];
X char domain[SMLBUF], user[SMLBUF];
X char *r;
X FILE *fp, *out, *popen();
X int i = 0;
X
X r = buf;
X
X (void) sprintf(r, "%s %s", SMAIL, VFLAG);
X r += strlen(r);
X
X if(islocal(from, domain, user)) {
X (void) sprintf(r, LARG(user));
X } else {
X (void) sprintf(r, RLARG(domain, user));
X }
X
X i = 0;
X do {
X out = popen(buf, "w");
X if (out) break;
X /*
X * Fork failed. System probably overloaded.
X * Wait awhile and try again 10 times.
X * If it keeps failing, probably some
X * other problem, like no uux or smail.
X */
X (void) sleep(60);
X } while (++i < 10);
X
X if(out == NULL) {
X (void) printf("couldn't execute %s.\n", buf);
X return;
X }
X
X (void) fprintf(out, "Date: %s\n", arpanows);
X (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
X (void) fprintf(out, "Subject: failed mail\n");
X (void) fprintf(out, "To: %s\n", from);
X (void) fprintf(out, "\n");
X (void) fprintf(out, "======= command failed =======\n\n");
X (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
X
X (void) fprintf(out, "======= standard error follows =======\n");
X (void) fflush(stderr);
X if((fp = fopen(stderrfile, "r")) != NULL) {
X while(fgets(buf, sizeof(buf), fp) != NULL) {
X (void) fputs(buf, out);
X }
X }
X (void) fclose(fp);
X (void) fprintf(out, "======= text of message follows =======\n");
X/*
X** Copy input.
X*/
X (void) fprintf(out, "From %s\n", from);
X while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X (void) fputs(buf, out);
X }
X (void) pclose(out);
X}
END_OF_FILE
if test 12633 -ne `wc -c <'mailer/deliver.c'`; then
echo shar: \"'mailer/deliver.c'\" unpacked with wrong size!
fi
# end of 'mailer/deliver.c'
fi
if test -f 'unspool' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'unspool'\"
else
echo shar: Extracting \"'unspool'\" \(13090 characters\)
sed "s/^X//" >'unspool' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X#
X# unspool does all of the actual processing for the ACS.
X#
X#die "unspool.perl compiled successfully\n";
X#
X# If the lock file exists, we are already running. Die immediately.
Xif ( -e "/usr/personals/LCK..SPOOL" ) {
X exit 0;
X}
X#
X# set up the environment for suid operations - no longer needed but...
X#
X$ENV{"PATH"} = "/bin:/usr/bin:/usr/local/bin:/usr/ucb:/usr/personals";
X$ENV{"IFS"} = '' if $ENV{"IFS"} ne '';
X$path = $ENV{"PATH"};
X
X# set the permissions on all files we create to user only.
Xumask(0077);
X
X# flush on selected channel
X$| = 1;
X#
X# create the lock file
X#
Xopen(LCK,">/usr/personals/LCK..SPOOL");
Xclose(LCK);
X
X# open the address:alias database
Xif (! dbmopen(r2a,"/usr/personals/real2alias",0600)) {
X print STDERR ":::can't dbmopen real2alias: $!\n";
X exit(1);
X}
X
X# open the alias-index file and get the current alias.
Xif (open(INDEX,'</usr/personals/alias-index')) {
X $alias_index = <INDEX>;
X close(INDEX);
X}
Xelse {
X $alias_index = 'a';
X}
X#
X# Process all the replies in the spool directory
X#
X$seq = $$;
Xwhile (</usr/personals/spool/REP*> ) {
X $repfile = $_;
X
X # check to make sure no fast connections are running. unspool
X # kicks off quite a few other processes, which can seriously
X # degrade throughput on a fast modem connected to a slow system.
X &fstchk;
X
X # open the spooled reply file
X open(MSG,"<$repfile");
X
X # read the first line of the message, which contains the recipient's
X # alias.
X $target_alias = <MSG>;
X
X # hack off the terminal newline
X chop $target_alias;
X
X # Load the message on MSG into an array
X @message = <MSG> ;
X close(MSG);
X
X # open the file in the repair directory to store the header and
X # status info in case something goes wrong.
X $replog = 0;
X $repname = "/usr/personals/repair/REP$seq-$target_alias";
X if ( open(REPLOG,">$repname")) {
X $replog = 1;
X $seq++;
X }
X
X # get the sender's address from the From: line
X $address = &getaddr;
X
X # write the header and the extracted address to the repair file
X print REPLOG @header if ( $replog );
X print REPLOG "::: address = $address\n" if ( $replog );
X
X # if we didn't get a usable address, go on to the next message
X goto repfail if ( "$address" eq '' );
X
X # extract the username from the address
X $user = &getuser($address);
X
X # log it in the repair file
X print REPLOG "::: user = $user\n" if ( $replog );
X
X # if there is none, or if it's not acceptable, go to next message
X goto repfail if ( "$user" eq '' );
X
X # extract the subject from the Subject: line
X $subject = &getsubj;
X
X # if the subject is empty, replace it with something clever
X $subject = "(None)" if ( "$subject" eq '' );
X # and log it
X print REPLOG "::: subject = $subject\n" if ( $replog );
X
X # look up the sender's alias in the database. If s/he doesn't
X # have one, give hir one, and log it
X $sender_alias = &getsender($address);
X print REPLOG "::: sender_alias = $sender_alias\n" if ( $replog );
X
X # Lookup target_alias in real2alias db
X # WARNING: you cannot save time by jumping out of this loop
X # after the target_alias has been found. Perl's implementation
X # of the dbm stuff requires that "each" visit every entry in
X # the data base before it resets. This was the origin of the
X # infamous reply to the wrong alias bug.
X $recip_address = '';
X $found = 0;
X while (($key,$value) = each %r2a) {
X if ( $found == 0 ) {
X if ( "$value" eq "$target_alias" ) {
X $recip_address = $key;
X $found = 1;
X }
X }
X }
X
X # non-existent target alias - send a terse message to the sender
X # explaining this.
X if ( "$recip_address" eq '' ) {
X # send a bounce message to sender
X # Using elm here is a horrendous kluge. We should probably
X # use smail instead.
X open(ELM,"|/usr/local/bin/elm -s \"ACS Reply to $target_alias Failed\" $address");
X print ELM "Alias $target_alias not found in database.\nSorry.\nACS\n";
X close(ELM);
X # log the failure
X if ( $replog ) {
X print REPLOG "::: No recip_address for $target_alias\n";
X }
X goto repfail;
X }
X
X # open a pipe into acsmail to send out the anonymous reply
X if (! open(REPLY,"|/usr/personals/acsmail -F $sender_alias at alembic.ACS.COM $recip_address")) {
X goto repfail;
X }
X
X # write the reply into acsmail's stdin. acsmail will add the other
X # header fields.
X print REPLY "Subject: $subject\n";
X print REPLY "To: $recip_address\n\n";
X print REPLY @body;
X close(REPLY);
X
X # since the reply apparently succeeded, unlink the repair file.
X unlink($repname);
X next;
X # something broke. Note it in the repair file and do the next one.
Xrepfail:
X print REPLOG "::: Reply failed\n" if ( $replog );
X next;
X} continue {
X # if a repair file is open, close it
X close(REPLOG) if ( $replog );
X # and delete the spooled reply file.
X unlink($repfile);
X}
X#
X# Now do the messages to be posted
X#
Xwhile (</usr/personals/spool/POST*> ) {
X $postfile = $_;
X
X # check for other things that shouldn't be disturbed
X &fstchk;
X
X # open the spooled POST file
X open(MSG,"<$postfile");
X
X # Load the message on MSG into an array
X @message = <MSG> ;
X close(MSG);
X
X # get the sender's address from the From: line
X $address = &getaddr;
X # if it's empty, forget it and do the next message
X goto postfail if ( "$address" eq '' );
X
X # get the username from the address
X $user = &getuser($address);
X
X # if the username is empty or forbidden, do the next message
X goto postfail if ( "$user" eq '' );
X
X # get the subject from the Subject: line
X $subject = &getsubj;
X
X # trash postings with "test" in the Subject: line
X next if ( $subject =~ /test/io );
X
X # if there is no subject, insert one
X $subject = "(None)" if ( $subject eq '' );
X
X # get the sender's alias. assign one if necessary.
X $alias = &getsender($address);
X
X # open a pipe into inews for the article
X if ( ! open(INEWS,"| /bin/inews -h")) {
X print STDERR "Can\'t pipe into inews\n";
X goto postfail;
X }
X
X # write the article into inews' stdin
X print INEWS "Path: $alias\n";
X print INEWS "From: ",$alias,"@alembic.ACS.COM\n";
X print INEWS "Newsgroups: alt.personals\n";
X print INEWS "Subject: $subject\n";
X print INEWS "Distribution: local\n";
X print INEWS "Reply-To: ",$alias,"@alembic.ACS.COM\n";
X print INEWS "Followup-To: sender\n";
X print INEWS "Organization: Anonymous Contact Service\n";
X print INEWS "\n";
X print INEWS @body;
X
X # add the ACS usage "signature"
X print INEWS "\n-- \n";
X print INEWS <<EOS;
XTo use this service, send email to: | There is a 25 line
XAnonymous posting: acs-post at alembic.ACS.COM | limit on all posts
XAnonymous reply: <user's alias>@alembic.ACS.COM| and e-mail messages.
XTest path/get an alias: acs-ping at alembic.ACS.COM | Alternate path:
XACS administrator: acs-admin at alembic.ACS.COM | uunet!alembic!...
XEOS
X close(INEWS);
Xpostfail:
X next;
X} continue {
X # delete the spooled POST file
X unlink($postfile);
X}
X
X#
X# Process the acs-ping messages
X#
Xwhile (</usr/personals/spool/PING*> ) {
X $pingfile = $_;
X
X # don't disturb high-priority processing
X &fstchk;
X
X # open the spooled PING file
X open(MSG,"<$pingfile");
X
X # Load the message on MSG into an array
X @message = <MSG> ;
X close(MSG);
X
X # get the sender's address from the From: line
X $address = &getaddr;
X
X # forget it and do the next one if no address
X goto pingfail if ( "$address" eq '' );
X
X # extract the username from the address
X $user = &getuser($address);
X
X # skip to next message if the username is empty or forbidden
X goto pingfail if ( "$user" eq '' );
X
X # get the sender's alias, assigning one if necessary
X $sender_alias = &getsender($address);
X $| = 1;
X
X # open a pipe into smail to send the echo back
X open(REPLY,"|smail -F acs-ping at alembic.ACS.COM $address")
X || die "Can't pipe into smail\n";
X
X # write the ping message into smail's stdin
X print REPLY "Subject: Message RCVD\n";
X print REPLY "To: $address\n\n";
X print REPLY "Your ping request has been received by acs-ping at alembic.ACS.COM\n";
X print REPLY "Your alias will be $sender_alias at alembic.ACS.COM\n";
X print REPLY "The header of your message as it arrived here follows:\n\n";
X
X # send them a copy of their message header. Who knows why?
X print REPLY @header;
X close(REPLY);
Xpingfail:
X next;
X} continue {
X # delete the spooled PING file
X unlink($pingfile);
X}
X
X# cleanup: close the real2alias database, delete the lock file, delete
X# and rewrite the alias-index file, and exit.
Xdbmclose(r2a);
Xunlink("/usr/personals/LCK..SPOOL");
Xunlink('/usr/personals/alias-index');
Xopen(INDEX,'>/usr/personals/alias-index') ||
X die "Can't open alias-index: $!\n";
Xprint INDEX $alias_index;
Xclose(INDEX);
Xexit(0);
X
X# subroutine fstchk checks to see if there are any conditions on the
X# system which unspool would interfere with. Mostly, this consists of
X# high-speed data transfers and high-priority processes running. If
X# fstchk finds such a condition, it sleeps for 30 seconds, then checks
X# again to see if the condition still exists. It continues this loop
X# forever.
Xsub fstchk {
X #
X # If we're using a high-speed line, sleep until the call ends
X # (otherwise the transfer rate drops through the floor)
X #
X while ( -e "/usr/spool/uucp/LCK/LCK..uunet" ) {
X sleep 30;
X }
X} # end subroutine fstchk
X
X#
X# Subroutine getaddr splits the message in global array @message
X# into global arrays @header and @body, truncates @body to 25
X# lines, tries to find a signature in @body and deletes it if it
X# finds one, the searches @header for a From: line and extracts
X# the actual address from it if it can.
X# Returns $address.
X#
Xsub getaddr {
X #
X # split the message into body and header
Xhb: for ( $line = 0 ; $line <= $#message; $line++ ) {
X if ( $message[$line] eq "\n" ) {
X # store the header
X @header = @message[ 0 .. $line-1 ];
X # store the first 25 lines of the body
X @body = @message [ $line+1 .. $line+25 ];
X last hb;
X }
X }
X #
X # Trash the signature if present
Xsig: for ($line = 0; $line <= $#body; $line++ ) {
X if ( $body[$line] eq "-- \n" || $body[$line] =~ /---/ ) {
X $#body = $line - 1;
X last sig;
X }
X }
X #
X # Get From: line from header
X $from = '';
Xfrom: for ($line = 0; $line <= $#header; $line++ ) {
X if ( $header[$line] =~ /^From: (.*)/ ) {
X $from = $1;
X last from;
X }
X }
X #
X # No From: line
X #
X #
X if ( $line > $#header) {
X return '';
X }
X # Try to extract actual address from $from line
X # look for <bangpath> form first, since that's what uunet
X # put's into the From: line
X if ( $from =~ /<(.*)>/ ) {
X $Address = $1;
X }
X else {
X # try From: address ( comment )
X if ( $from =~ /(.*) \(.*\)/ ) {
X $Address = $1;
X }
X else {
X # just use whatever's there
X $Address = $from;
X }
X }
X # get rid of any whitespace following the address
X ($Address,$junk) = split(/[ \t]/,$Address);
X # return the address
X $Address;
X} # end subroutine getaddr
X
X#
X# subroutine getuser($address) -
X# extract the username from an address and check to make sure it isn't
X# one of the "forbidden" usernames. Returns either null or the username.
X#
X
Xsub getuser {
X local($addr) = pop(@_);
X #
X # if sender is uucp, news, mailer-daemon, etc., junk the message
X # get the last ! component
X @phase1 = split(/!/,$addr);
X $usr = $phase1[$#phase1];
X # get whatever sits in front of an "@".
X @phase2 = split(/@/,$usr);
X $usr = $phase2[0];
X # get whatever precedes a "%"
X @phase3 = split(/%/,$usr);
X $usr = $phase3[0];
X
X # check for anything that might conceivably be the username
X # of something that bounces mail, rather than a person. We
X # also exclude root, simply because there are too many root
X # users doing system administration at some sites.
X study $usr;
X if ( $usr =~ /MAILER/i) { return(''); }
X if ( $usr =~ /DAEMON/i) { return(''); }
X if ( $usr =~ /uucp/i) { return(''); }
X if ( $usr =~ /POSTMASTER/i) { return(''); }
X if ( $usr =~ /DELIVER/i) { return(''); }
X if ( $usr =~ /news/i) { return(''); }
X if ( $usr =~ /root/) { return(''); }
X $usr;
X} # end subroutine getuser
X
X# subroutine getsubj - search through the global array @header until
X# we find a Subject: line. Extract and return the subject.
X
Xsub getsubj {
X #
X # Get Subject: line from header
X $subj = '';
X for ($line = 0; $line <= $#header; $line++ ) {
X if ( $header[$line] =~ /^Subject: (.*)$/ ) {
X $subj = $1;
X last ;
X }
X }
X $subj;
X} # end subroutine getsubj
X
X#
X# subroutine getsender($address) - given the address of the sender of
X# a message, find hir alias in the real2alias database and return the
X# alias. If the sender is not in the database, add them. Returns the
X# sender's alias.
X
Xsub getsender {
X local($addr) = pop(@_);
X #
X # Lookup sender in real2alias db
X $Salias = $r2a{$addr};
X if ( ! defined($Salias)) {
X # create alias for sender
X $alias_index++;
X $Salias = "acs-".$alias_index;
X # add the newbie to the database
X $r2a{"$addr"} = $Salias;
X # Add alias to /usr/lib/aliases
X open(SYSALIAS,">>/usr/lib/aliases") ||
X die "Can't write to aliases file: $!\n";
X print SYSALIAS "$Salias: \"|/usr/personals/anon-reply $Salias\"\n";
X close(SYSALIAS);
X #
X # need to execute newaliases here if sendmail doesn't
X # support OD flag to automatically update dbm database
X # of course, this is irrelevant if the MTA doesn't
X # use dbm database.
X # system("/usr/ucb/newaliases");
X }
X # return the alias
X $Salias;
X} # end subroutine getsender
END_OF_FILE
if test 13090 -ne `wc -c <'unspool'`; then
echo shar: \"'unspool'\" unpacked with wrong size!
fi
chmod +x 'unspool'
# end of 'unspool'
fi
echo shar: End of archive 7 \(of 8\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 8 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
More information about the Alt.sources
mailing list