Ryan Haggerty e50d1d
#!/usr/local/bin/perl
Ryan Haggerty e50d1d
##
Ryan Haggerty e50d1d
## Sendmail mailer for Mailman
Ryan Haggerty e50d1d
##
Ryan Haggerty e50d1d
## Simulates these aliases:
Ryan Haggerty e50d1d
##
Ryan Haggerty e50d1d
##testlist:              "|/home/mailman/mail/mailman post testlist"
Ryan Haggerty e50d1d
##testlist-admin:        "|/home/mailman/mail/mailman admin testlist"
Ryan Haggerty e50d1d
##testlist-bounces:      "|/home/mailman/mail/mailman bounces testlist"
Ryan Haggerty e50d1d
##testlist-confirm:      "|/home/mailman/mail/mailman confirm testlist"
Ryan Haggerty e50d1d
##testlist-join:         "|/home/mailman/mail/mailman join testlist"
Ryan Haggerty e50d1d
##testlist-leave:        "|/home/mailman/mail/mailman leave testlist"
Ryan Haggerty e50d1d
##testlist-owner:        "|/home/mailman/mail/mailman owner testlist"
Ryan Haggerty e50d1d
##testlist-request:      "|/home/mailman/mail/mailman request testlist"
Ryan Haggerty e50d1d
##testlist-subscribe:    "|/home/mailman/mail/mailman subscribe testlist"
Ryan Haggerty e50d1d
##testlist-unsubscribe:  "|/home/mailman/mail/mailman unsubscribe testlist"
Ryan Haggerty e50d1d
##owner-testlist:        testlist-owner
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## Some assembly required.
Ryan Haggerty e50d1d
$MMWRAPPER = "/etc/mail/mailman";
Ryan Haggerty e50d1d
$MMLISTDIR = "/etc/mailman/lists";
Ryan Haggerty e50d1d
$SENDMAIL = "/usr/lib/sendmail -oem -oi";
Ryan Haggerty e50d1d
$VERSION = '$Id: mm-handler,v 1.2 2002/04/05 19:41:09 bwarsaw Exp $';
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## Comment this if you offer local user addresses.
Ryan Haggerty e50d1d
$NOUSERS = "\nPersonal e-mail addresses are not offered by this server.";
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
# uncomment for debugging....
Ryan Haggerty e50d1d
#$DEBUG = 1;
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
use FileHandle;
Ryan Haggerty e50d1d
use Sys::Hostname;
Ryan Haggerty e50d1d
use Socket;
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
($VERS_STR = $VERSION) =~ s/^\$\S+\s+(\S+),v\s+(\S+\s+\S+\s+\S+).*/\1 \2/;
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
$BOUNDARY = sprintf("%08x-%d", time, time % $$);
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## Informative, non-standard rejection letter
Ryan Haggerty e50d1d
sub mail_error {
Ryan Haggerty e50d1d
	my ($in, $to, $list, $server, $reason) = @_;
Ryan Haggerty e50d1d
	my $sendmail;
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	if ($server && $server ne "") {
Ryan Haggerty e50d1d
		$servname = $server;
Ryan Haggerty e50d1d
	} else {
Ryan Haggerty e50d1d
		$servname = "This server";
Ryan Haggerty e50d1d
		$server = &get_ip_addr;
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	#$sendmail = new FileHandle ">/tmp/mm-$$";
Ryan Haggerty e50d1d
	$sendmail = new FileHandle "|$SENDMAIL $to";
Ryan Haggerty e50d1d
	if (!defined($sendmail)) {
Ryan Haggerty e50d1d
		print STDERR "$0: cannot exec \"$SENDMAIL\"\n";
Ryan Haggerty e50d1d
		exit (-1);
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	$sendmail->print ("From: MAILER-DAEMON\@$server
Ryan Haggerty e50d1d
To: $to
Ryan Haggerty e50d1d
Subject: Returned mail: List unknown
Ryan Haggerty e50d1d
Mime-Version: 1.0
Ryan Haggerty e50d1d
Content-type: multipart/mixed; boundary=\"$BOUNDARY\"
Ryan Haggerty e50d1d
Content-Disposition: inline
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
--$BOUNDARY
Ryan Haggerty e50d1d
Content-Type: text/plain; charset=us-ascii
Ryan Haggerty e50d1d
Content-Description: Error processing your mail
Ryan Haggerty e50d1d
Content-Disposition: inline
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
Your mail for $list could not be sent:
Ryan Haggerty e50d1d
	$reason
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
For a list of publicly-advertised mailing lists hosted on this server,
Ryan Haggerty e50d1d
visit this URL:
Ryan Haggerty e50d1d
	http://$server/
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
If this does not resolve your problem, you may write to:
Ryan Haggerty e50d1d
	postmaster\@$server
Ryan Haggerty e50d1d
or
Ryan Haggerty e50d1d
	mailman-owner\@$server
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
$servname delivers e-mail to registered mailing lists
Ryan Haggerty e50d1d
and to the administrative addresses defined and required by IETF
Ryan Haggerty e50d1d
Request for Comments (RFC) 2142 [1].
Ryan Haggerty e50d1d
$NOUSERS
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
The Internet Engineering Task Force [2] (IETF) oversees the development
Ryan Haggerty e50d1d
of open standards for the Internet community, including the protocols
Ryan Haggerty e50d1d
and formats employed by Internet mail systems.
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
For your convenience, your original mail is attached.
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
[1] Crocker, D. \"Mailbox Names for Common Services, Roles and
Ryan Haggerty e50d1d
    Functions\".  http://www.ietf.org/rfc/rfc2142.txt
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
[2] http://www.ietf.org/
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
--$BOUNDARY
Ryan Haggerty e50d1d
Content-Type: message/rfc822
Ryan Haggerty e50d1d
Content-Description: Your undelivered mail
Ryan Haggerty e50d1d
Content-Disposition: attachment
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
");
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	while ($_ = <$in>) {
Ryan Haggerty e50d1d
		$sendmail->print ($_);
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	$sendmail->print ("\n");
Ryan Haggerty e50d1d
	$sendmail->print ("--$BOUNDARY--\n");
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	close($sendmail);
Ryan Haggerty e50d1d
}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## Get my IP address, in case my sendmail doesn't tell me my name.
Ryan Haggerty e50d1d
sub get_ip_addr {
Ryan Haggerty e50d1d
	my $host = hostname;
Ryan Haggerty e50d1d
	my $ip = gethostbyname($host);
Ryan Haggerty e50d1d
	return inet_ntoa($ip);
Ryan Haggerty e50d1d
}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## Split an address into its base list name and the appropriate command
Ryan Haggerty e50d1d
## for the relevant function.
Ryan Haggerty e50d1d
sub split_addr {
Ryan Haggerty e50d1d
	my ($addr) = @_;
Ryan Haggerty e50d1d
	my ($list, $cmd);
Ryan Haggerty e50d1d
	my @validfields = qw(admin bounces confirm join leave owner request
Ryan Haggerty e50d1d
				subscribe unsubscribe);
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	if ($addr =~ /(.*)-(.*)\+.*$/) {
Ryan Haggerty e50d1d
		$list = $1;
Ryan Haggerty e50d1d
		$cmd = "$2";
Ryan Haggerty e50d1d
	} else {
Ryan Haggerty e50d1d
		$addr =~ /(.*)-(.*)$/;
Ryan Haggerty e50d1d
		$list = $1;
Ryan Haggerty e50d1d
		$cmd = $2;
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
	if (grep /^$cmd$/, @validfields) {
Ryan Haggerty e50d1d
		if ($list eq "owner") {
Ryan Haggerty e50d1d
			$list = $cmd;
Ryan Haggerty e50d1d
			$cmd = "owner";
Ryan Haggerty e50d1d
		}
Ryan Haggerty e50d1d
	} else {
Ryan Haggerty e50d1d
		$list = $addr;
Ryan Haggerty e50d1d
		$cmd = "post";
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	return ($list, $cmd);
Ryan Haggerty e50d1d
}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
## The time, formatted as for an mbox's "From_" line.
Ryan Haggerty e50d1d
sub mboxdate {
Ryan Haggerty e50d1d
	my ($time) = @_;
Ryan Haggerty e50d1d
	my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
Ryan Haggerty e50d1d
	my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
Ryan Haggerty e50d1d
	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
Ryan Haggerty e50d1d
		localtime($time);
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	## Two-digit year handling complies with RFC 2822 (section 4.3),
Ryan Haggerty e50d1d
	## with the addition that three-digit years are accommodated.
Ryan Haggerty e50d1d
	if ($year < 50) {
Ryan Haggerty e50d1d
		$year += 2000;
Ryan Haggerty e50d1d
	} elsif ($year < 1900) {
Ryan Haggerty e50d1d
		$year += 1900;
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	return sprintf ("%s %s %2d %02d:%02d:%02d %d",
Ryan Haggerty e50d1d
		$days[$wday], $months[$mon], $mday,
Ryan Haggerty e50d1d
		$hour, $min, $sec, $year);
Ryan Haggerty e50d1d
}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
BEGIN: {
Ryan Haggerty e50d1d
	$sender = undef;
Ryan Haggerty e50d1d
	$server = undef;
Ryan Haggerty e50d1d
	@to = ();
Ryan Haggerty e50d1d
	while ($#ARGV >= 0) {
Ryan Haggerty e50d1d
		if ($ARGV[0] eq "-r") {
Ryan Haggerty e50d1d
			$sender = $ARGV[1];
Ryan Haggerty e50d1d
			shift @ARGV;
Ryan Haggerty e50d1d
		} elsif (!defined($server)) {
Ryan Haggerty e50d1d
			$server = $ARGV[0];
Ryan Haggerty e50d1d
		} else {
Ryan Haggerty e50d1d
			push(@to, $ARGV[0]);
Ryan Haggerty e50d1d
		}
Ryan Haggerty e50d1d
		shift @ARGV;
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
	if ($DEBUG) {
Ryan Haggerty e50d1d
		$to = join(',', @to);
Ryan Haggerty e50d1d
		print STDERR "to: $to\n";
Ryan Haggerty e50d1d
		print STDERR "sender: $sender\n";
Ryan Haggerty e50d1d
		print STDERR "server: $server\n";
Ryan Haggerty e50d1d
		exit(-1);
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
ADDR:	for $addr (@to) {
Ryan Haggerty e50d1d
		$prev = undef;
Ryan Haggerty e50d1d
		$list = $addr;
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
		$cmd= "post";
Ryan Haggerty e50d1d
		if (! -f "$MMLISTDIR/$list/config.pck") {
Ryan Haggerty e50d1d
			($list, $cmd) = &split_addr($list);
Ryan Haggerty e50d1d
			if (! -f "$MMLISTDIR/$list/config.pck") {
Ryan Haggerty e50d1d
				$was_to = $addr;
Ryan Haggerty e50d1d
				$was_to .= "\@$server" if ("$server" ne "");
Ryan Haggerty e50d1d
				mail_error(\*STDIN, $sender, $was_to, $server,
Ryan Haggerty e50d1d
					"no list named \"$list\" is known by $server");
Ryan Haggerty e50d1d
				next ADDR;
Ryan Haggerty e50d1d
			}
Ryan Haggerty e50d1d
		}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
		$wrapper = new FileHandle "|$MMWRAPPER $cmd $list";
Ryan Haggerty e50d1d
		if (!defined($wrapper)) {
Ryan Haggerty e50d1d
			## Defer?
Ryan Haggerty e50d1d
			print STDERR "$0: cannot exec ",
Ryan Haggerty e50d1d
				"\"$MMWRAPPER $cmd $list\": deferring\n";
Ryan Haggerty e50d1d
			exit (-1);
Ryan Haggerty e50d1d
		}
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
		# Don't need these without the "n" flag on the mailer def....
Ryan Haggerty e50d1d
		#$date = &mboxdate(time);
Ryan Haggerty e50d1d
		#$wrapper->print ("From $sender  $date\n");
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
		# ...because we use these instead.
Ryan Haggerty e50d1d
		$from_ = <STDIN>;
Ryan Haggerty e50d1d
		$wrapper->print ($from_);
Ryan Haggerty e50d1d
Ryan Haggerty e50d1d
		$wrapper->print ("X-Mailman-Handler: $VERSION\n");
Ryan Haggerty e50d1d
		while (<STDIN>) {
Ryan Haggerty e50d1d
			$wrapper->print ($_);
Ryan Haggerty e50d1d
		}
Ryan Haggerty e50d1d
		close($wrapper);
Ryan Haggerty e50d1d
	}
Ryan Haggerty e50d1d
}