#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#               "End of shell archive."
# Contents:  resend.README resend
# Wrapped by brent@mycroft on Wed Nov 10 19:08:03 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'resend.README' -a "${1}" != "-c" ; then
 echo shar: Will not clobber existing file \"'resend.README'\"
else
echo shar: Extracting \"'resend.README'\" \(4500 characters\)
sed "s/^X//" >'resend.README' <<'END_OF_FILE'
The .cf file is a config file for my listserv-like package called
Majordomo.  The only one of those variables that "resend" actually
uses is "homedir", which tells it where to look for the "majordomo.pl"
library.
X
Sendmail (and probably other packages) have a 256 byte limit on the length
of an alias.  It's very easy to exceed that limit with all the flags
that you might use for a typical "resend" invocation.  To get around that
limit, "resend" supports an "@filename" mechanism for retrieving all the
flags from "filename".  You can put all the flags in a file (for
instance, you might name it /mail/lists/listname.resend), and
reference the file with an "@filename" argument (for instance,
X"resend @/mail/lists/listname.resend").  If you do this, you should put
ALL the flags in the file, and the "@filename" argument should be the
only argument to "resend".
X
Note that the "-C <config-file>" flag, if used, MUST BE THE FIRST FLAG,
regardless of whether it's on the command line or in the file of flags
referenced by an "@filename" argument.
X
Here's the rundown of the arguments to "resend":
X
X        -C <config-file>        specify alternate config file (must be first!)
X        -l <list-name>          REQUIRED: specify list name
X        -h <host-name>          REQUIRED: specify host name
X        -f <from-addr>          specify "sender" (default <list-name>-request)
X        -m <sendmail-flags>     specify special sendmail flags
X        -M <max-msg-length>     specify max message length to forward
X        -p <precedence>         add "Precedence: <precedence>" header
X       -r <reply-to>           add "Reply-To: <reply-to>" header
X       -I <file-list>          Bounce messages from users not listed in file
X                                       in colon-separated <file-list>
X       -a <passwd>             approval password
X       -A                      moderate list (require "Approved:" for posting)
X        -R                      delete "Received:" lines
X        -s                      enable "administrivia" checks
X        -d                      debug; say it, but don't do it
X
Any message that "resend" doesn't like is sent to the list owner (the
X"-f" address, or "<list-name>-request" if -f isn't used) along with a
comment indicating what "resend" didn't like about it.  To go ahead
and send the message, just feed it to resend without the flag that
caused it to reject it (in other words, if it rejected it because it
was too long, omit the "-M <>" flag; if it rejected it because it was
administrivia, omit the "-s" flag).
X
If you specify "-a <passwd>" flag, this "approval" password can be
used in an "Approved: <passwd>" line to override most of the other
checks (those enabled by "-s", "-M", and so forth).  The "Approved:
X<passwd>" line can either be one of the mail headers, or the first
line of the body of the message.  If it is in the headers, the rest
of the headers are resent as part of the approved message.  If it is
in the body, the current headers are discarded in favor of the headers
from the original message which should follow the "Approved:" line in
the body.
X
The owner of a mailing list can thus post messages that were initially
bounced by adding an "Approved: <passwd>" line and resubmitting the
message.  Any "Approved: <passwd>" line is stripped before the message
is sent to the mailing list, so that list members won't learn the
password.  If the <passwd> argument to the "-a" flag begins with a "/",
it is assumed to be a file name from which the actual password is read.
X
You can make a list "moderated" by specifying the "-A" flag.  If the
X"-A" flag is set, then any messages not containing a valid "Approved:"
line are sent to the list owner, rather than the whole list.; the
list owner can then review the message, add an appropriate "Approved:"
line, and resubmit them (these last two steps can be done easily with
the "approve" command that comes with Majordomo).  If you specify
the "-A" flag, you must also specify the "-a <passwd>" flag, so that
resend knows what approval password to use.
X
If you only want to accept messages from members of a list, you can
use the "-I <file-list>" flag to do this.  "<file-list>" should be a
colon-separated list of files in the $listdir directory (specified in
the config file) that "resend" will check the address in "From:" line
of a message against.  If the address doesn't show up in one of those
files, and the message doesn't have a valid "approved" header on it,
it will be bounced to the list owner.
X
X$Header: /mycroft/brent/majordomo/RCS/resend.README,v 1.5 1993/11/11 02:42:58 brent Exp $
END_OF_FILE
if test 4500 -ne `wc -c <'resend.README'`; then
   echo shar: \"'resend.README'\" unpacked with wrong size!
fi
# end of 'resend.README'
fi
if test -f 'resend' -a "${1}" != "-c" ; then
 echo shar: Will not clobber existing file \"'resend'\"
else
echo shar: Extracting \"'resend'\" \(8759 characters\)
sed "s/^X//" >'resend' <<'END_OF_FILE'
X#!/usr/local/bin/perl -U
X
X# Copyright 1992, D. Brent Chapman.  All Rights Reserved.  For use by
X# permission only.
X#
X# $Source: /mycroft/brent/majordomo/RCS/resend,v $
X# $Revision: 1.19 $
X# $Date: 1993/11/11 02:23:37 $
X# $Author: brent $
X# $State: Exp $
X#
X# $Locker:  $
X#
X
X# set our path explicitly
X$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
X
X# What shall we use for temporary files?
X$tmp = "/tmp/majordomo.$$";
X
X# If the first argument is "@filename", read the real arguments
X# from "filename", and shove them onto the ARGV for later processing
X# by &Getopts()
X
if ($ARGV[0] =~ /^@/) {
X    $fn = shift(@ARGV);
X    $fn =~ s/^@//;
X    open(AV, $fn) || die("open(AV, \"$fn\"): $!\nStopped");
X    undef($/); # set input field separator
X    $av = <AV>;        # read whole file into string
X    close(AV);
X    @av = split(/\s+/, $av);
X    unshift(@ARGV, @av);
X    $/ = "\n";
X}
X
X# Read and execute the .cf file
X$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
X    $cf = $ARGV[1];
X    shift(@ARGV);
X    shift(@ARGV);
X}
if (! -r $cf) {
X    die("$cf not readable; stopped");
X}
eval(`cat $cf`);
X
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
require "majordomo.pl";
require "getopts.pl";
X
X&Getopts("Aa:df:h:I:l:m:M:p:Rr:s") || die("resend: Getopts(): $!");
X
if (! defined($opt_l) || ! defined($opt_h)) {
X    die("resend: must specify both '-l list' and '-h host' arguments");
X}
X
if (defined($opt_f)) {
X    $sendmail_sender = $opt_f;
X} else {
X    $sendmail_sender = "$opt_l-request";
X}
X
if (defined($opt_a)) {
X    if ($opt_a =~ /^\//) {
X       open(PWD, $opt_a) || die("resend: open(PWD, \"$opt_a\"): $!");
X       $opt_a = &chop_nl(<PWD>);
X    }
X}
X
if (defined($opt_A) && ! defined($opt_a)) {
X    die("resend: must also specify '-a passwd' if using '-A' flag");
X}
X
X$sender = "$sendmail_sender@$opt_h";
X
open(OUT, ">/tmp/resend.$$.out") ||
X    die("resend: Can't open /tmp/resend.$$.out: $!");
X
open(IN, ">/tmp/resend.$$.in") ||
X    die("resend: Can't open /tmp/resend.$$.in: $!");
X
while (<STDIN>) {
X    print IN $_;
X}
X
close(IN);
X
open(IN, "/tmp/resend.$$.in") ||
X    die("resend: Can't open /tmp/resend.$$.tmp: $!");
X
do {
X    $restart = 0;
X    $pre_hdr = 1;
X    while (<IN>) {
X       if ($pre_hdr) {
X           if (/^\s*$/) {
X               # skip leading blank lines; usually only there if this is a
X               # restart after an in-body "Approved:" line
X               next;
X           } else {
X               $pre_hdr = 0;
X               $in_hdr = 1;
X               $kept_last = 0;
X           }
X       }
X       if ($in_hdr) {
X           if (/^\s*$/) {
X               # end of header; add new header fields
X               print OUT "Sender: $sender\n";
X               if (defined($opt_p)) {
X                   print OUT "Precedence: $opt_p\n";
X               }
X               if (defined($opt_r)) {
X                   print OUT "Reply-To: $opt_r@$opt_h\n";
X               }
X               $in_hdr = 0;
X               print OUT $_;
X           } elsif (/^approved:\s*(.*)/i && defined($opt_a)) {
X               $approved = &chop_nl($1);
X               if ($approved ne $opt_a) {
X                   &bounce("Invalid 'Approved:' header");
X               }
X           } elsif (/^from /i          # skip all these headers
X               || /^sender:/i
X               || /^return-receipt-to:/i
X               || /^errors-to:/i
X               || /^return-path:/i
X               || (/^reply-to:/i && defined($opt_r))   # skip only if "-r" set
X               || (/^precedence:/i && defined($opt_p)) # skip only if "-p" set
X               || (/^received:/i && defined($opt_R))   # skip only if "-R" set
X               || (/^\s/ && ! $kept_last)                      # skip if skipped last
X           ) {
X               # reset $kept_last in case next line is continuation
X               $kept_last = 0;
X           } else {
X               # check for administrivia requests
X               if (defined($opt_s) && ! defined($approved)
X                   && (/^subject:\s*subscribe\b/i ||
X                       /^subject:\s*unsubscribe\b/i)) {
X                   &bounce("Admin request");
X               }
X               if (defined($opt_I))
X               {
X                   if ( /^from:\s*(.+)/i )
X                   {
X                       $from = $1;
X                       $from_last = 1;
X                   }
X                   elsif ( defined($from_last) )
X                   {
X                       if ( /^\s+(.+)/ )
X                       {
X                           $from .= " $1";
X                       }
X                       else
X                       {
X                           undef($from_last);
X                       }
X                   }
X               }
X               &check_hdr_line($_);    # check for length & balance
X               $kept_last = 1;
X               print OUT $_;
X           }
X       } else {
X           # this isn't a header line, so print it (maybe)
X           # first, though, is the first line of the body an "Approved:" line?
X           if (($body_len == 0) && /^approved:\s*(.*)/i && defined($opt_a)) {
X               # OK, is it a valid "Approved:" line?
X               $approved = &chop_nl($1);
X               if ($approved ne $opt_a) {
X                   &bounce("Invalid 'Approved:' header");
X               } else {
X                   # Yes, it's a valid "Approved:" line...
X                   # So, we start over
X                   $restart = 1;
X                   close(OUT);
X                   unlink("/tmp/resend.$$.out");
X                   open(OUT, ">/tmp/resend.$$.out") ||
X                       die("resend: Can't open /tmp/resend.$$.out: $!");
X                   last;
X               }
X           }
X           # make sure it doesn't make the message too long
X           if (defined($opt_M) && ! defined($approved)
X                   && ($body_len += length($_)) > $opt_M) {
X               &bounce("Message too long (>$opt_M)");
X           }
X           # add admin-request recognition heuristics here... (body)
X           if (defined($opt_s) && ! defined($approved) && ($body_line++ < 5) && (
X               /\badd me\b/i
X               || /\bdelete me\b/i
X               || /\bsubscribe\b/i || /^sub\b/i
X               || /\bunsubscribe\b/i || /^unsub\b/i
X               )) {
X                 &bounce("Admin request");
X           }
X           print OUT $_;
X       }
X    }
X} while ($restart);
X
if (defined($opt_A) && ! defined($approved)) {
X    &bounce("Approval required");
X}
X
close(OUT);
X
if ( defined($opt_I) && defined($from) && ! defined($approved) ) {
X    local($infile) = 0;
X
X    @files = split (/[:\t\n]+/, $opt_I);
X
X    foreach $file (@files) {
X        if ( open (LISTFD, "<${listdir}/${file}") != 0 ) {
X           @output = grep (&addr_match($from, $_), <LISTFD>);
X            close (LISTFD);
X
X            if ( $#output != -1 ) {
X                $infile = 1;
X                last;
X            }
X        }
X    }
X
X    if ( $infile == 0 ) {
X        &bounce ("Non-member submission from [$from]");
X    }
X}
X
X$sendmail_cmd = "/usr/lib/sendmail $opt_m -f$sendmail_sender " .
X    join(" ", @ARGV);
X
if (defined($opt_d)) {
X    $| = 1;
X    print "Command: $sendmail_cmd\n";
X    $status = (system("cat /tmp/resend.$$.out") >> 8);
X    unlink(</tmp/resend.$$.*>);
X    exit($status);
X} else {
X    system("$sendmail_cmd </tmp/resend.$$.out");
X    unlink(</tmp/resend.$$.*>);
X    exit(0);
X}
X
sub check_balance {
X    # set a temporary variable
X    local($t) = shift;
X    # strip out all nested parentheses
X    1 while $t =~ s/\([^\(\)]*\)//g;
X    # strip out all nested angle brackets
X    1 while $t =~ s/\<[^\<\>]*\>//g;
X    # if any parentheses or angle brackets remain, were imbalanced
X    if ($t =~ /[\(\)\<\>]/ && ! defined($approved)) {
X       &bounce("Imbalanced parentheses or angle brackets");
X       return(undef);
X    }
X    return(1);
X}
X
sub check_hdr_line {
X
X    local($_) = shift;
X
X    if (! /^\s/) {     # is this a continuation line?
X       # Not a continuation line.
X       # If $balanced_fld is defined, it means the last field was one
X       # that needed to have balanced "()" and "<>" (i.e., "To:", "From:",
X       # and "Cc:", so check it.  We do it here in case the last field was
X       # multi-line.
X
X       if (defined($balanced_fld)) {
X           &check_balance($balanced_fld);
X       }
X
X       # we undefine $balanced_fld and reset $field_len; these may be set below
X
X       undef($balanced_fld);
X       $field_len = 0;
X    }
X
X    # is this a field that must be checked for balanced "()" and "<>"?
X    if (defined($balanced_fld) || /^from:/i || /^cc:/i || /^to:/i) {
X       # yes it is, but we can't check it yet because there might be
X       # continuation lines.  Buffer it to be checked at the beginning
X       # of the next non-continuation line.
X
X       # is this line too long?
X       if ((length($_) > 128) && ! defined($approved)) {
X           &bounce("Header line too long (>128)");
X           return(undef);
X       }
X
X       # is this field too long?
X       if ((($field_len += length($_)) > 1024) && ! defined($approved)) {
X           &bounce("Header field too long (>1024)");
X           return(undef);
X       }
X
X       $balanced_fld .= $_;
X       chop($balanced_fld);
X    }
X
X    # if we get here, everything was OK.
X    return(1);
X}
X
sub bounce {
X    local($reason) = shift;
X    local($_);
X
X    &resend_sendmail(BOUNCE, $sender, "BOUNCE $opt_l@$opt_h: $reason");
X
X    seek(IN, 0, 0);
X    while (<IN>) {
X       print BOUNCE $_;
X    }
X    close(BOUNCE);
X    unlink(</tmp/resend.$$.*>);
X    exit(0);
X}
X
sub resend_sendmail {
X    local(*MAIL) = shift;
X    local($to) = shift;
X    local($subject) = shift;
X
X    # clean up the addresses, for use on the sendmail command line
X    local(@to) = &ParseAddrs($to);
X    for (@to) {
X        $_ = join(", ", &ParseAddrs($_));
X    }
X    $to = join(", ", @to);
X
X    # open the process
X    if (defined($opt_d)) {
X       # debugging, so just say it, don't do it
X       open(MAIL, ">-");
X       print MAIL ">>> /usr/lib/sendmail -f$sendmail_sender $to\n";
X    } else {
X       open(MAIL, "|/usr/lib/sendmail -f$sendmail_sender $to") ||
X           &abort("Can't connect to sendmail: $!");
X    }
X
X    # generate the header
X    print MAIL <<"EOM";
To: $to
XFrom: $sender
Subject: $subject
X
XEOM
X
X    return;
X}
END_OF_FILE
if test 8759 -ne `wc -c <'resend'`; then
   echo shar: \"'resend'\" unpacked with wrong size!
fi
chmod +x 'resend'
# end of 'resend'
fi
echo shar: End of shell archive.
exit 0