Here it is! My autobounce program for Majordomo 1.62
There are two files, "autobounce" and "autobounce.cf". Both go
in the majordomo directory.
autobounce:
====================================================================
#!/usr/local/bin/perl
# == Autobounce ==
# (C) copyright 1994 by Alan Millar. This program may be freely
# copied, but may not be sold for profit. No warranty, etc.
# Move problem addresses from mailing list to bounces list.
# Done by interpreting bounce e-mail messages sent in reply
# to a list posting
# Interpretation is done based on a table of possible incoming message
# formats. The table is made of six assoc. arrays, which contain
# patterns which must be matched to extract a bounced address from
# the message. Things to match are the sender, the subject line,
# a starting and ending line of the bounce section of the message,
# and right and left patterns surrounding the bounced address.
# When a valid address is found, a message is sent to Majordomo
# with the appropriate commands.
#
# approve passwd unsubscribe this-list user@fubar.com
# approve passwd subscribe bounces user@fubar.com (930401 this-list)
#
# All subscription/unsubscription is done by mail to Majordomo,
# to keep the interface open-ended.
# Typical use: create alias which pipes into this program, and send
# out mail from this alias address, so that bounce replies come
# back here. Any unrecognized message is quietly ignored.
# This program is actually rather safe. It will only remove an
# address (and add to bounces list) if that address is a list
# member. So spurious addresses or garbage that accidentally
# slips through will not be added to the bounces list.
# In these cases, it does a Majordomo "which" command just to
# be helpful.
# Parameters:
# -l listname list to remove from
# -f address approval address; defaults to listname-approval
# -b bouncelist list to add to; defaults to "bounces"
# -n if defined, don't add to bounces list
# -d [mailer] print debug messages, optionally trace specific mailer
# Written by Alan Millar June 14 1994.
# inspired by "bounce" by Brent Chapman
#---------------------
# What shall we use for temporary files?
$tmp = "/tmp/majordomo.$$";
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
&abort("$cf not readable; stopped");
}
eval(`cat $cf`);
chdir($homedir) || &abort("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
require "majordomo.pl";
require "shlock.pl";
require "getopts.pl";
&Getopts("l:f:b:d:n") || &abort("autobounce: Getopts(): $!");
#-----------------------------
# Get name of list we are processing bounces for
# List name should be -l. Try looking at first arg if no -l spec'd.
if (defined($opt_l)) {
$list = $opt_l;
} else {
$list = $ARGV[0];
}
$list = &valid_list($listdir,$list);
if (! $list ) {
&abort("autobounce: no valid list specified");
}
#-----------------------------
# approval address for requests. Majordomo will send reply here.
if (defined($opt_f)) {
$approval = $opt_f;
} else {
$approval = $list . "-approval@" . $whereami;
}
#-----------------------------
# If option -n is specified, address should not be added to bounces list.
$add_bounces = (! defined($opt_n));
#-----------------------------
if (defined($opt_b)) {
$bounce_list = $opt_b;
} else {
$bounce_list = "bounces";
}
$bounce_list = &valid_list($listdir,$bounce_list);
if (! $bounce_list && $add_bounces ) {
&main'abort("autobounce: no valid bounce list specified:" .
" $bounce_list $opt_b");
}
#--------------------------------
# pick up table of bounce message profiles.
do 'autobounce.cf';
#-----------------------------------
# grab current time
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
#--------------------------
# Get password for list to unsubscribe from
open (PASSWD, "<$listdir/$list.passwd")
|| &abort ("Can't read password file $listdir/$list.passwd\n");
$list_passwd = &chop_nl(<PASSWD>);
if (! $list_passwd) {
&abort("no password for list $list; stopping");
}
close (PASSWD);
#--------------------------
# Get password for bounces list to subscribe to.
if ($add_bounces) {
open (PASSWD, "<$listdir/$bounce_list.passwd")
|| &abort ("Can't read password file $listdir/$bounce_list.passwd\n");
$bounce_passwd = &chop_nl(<PASSWD>);
if (! $bounce_passwd) {
&abort("no password for list $bounce_list; stopping");
}
close (PASSWD);
} # if not add_bounces
#-----------------------------------------
# read headers from incoming message
#-----------------------------------------
&ParseMailHeader(STDIN, *hdrs);
#--------------------------------
# Try to determine sending domain
# Many bounce messages only give local user name. Try appending
# domain of sending mailer as fall-back
($from_address,@junk) = &ParseAddrs($hdrs{"from"});
if ($from_address =~ /@/) {
# address is @domain
$sending_domain = $from_address;
$sending_domain =~ s/^.*@//;
if ($opt_d) {printf "@domain=%s\n", $sending_domain; }
} elsif ($from_address =~ /!/ ) {
# try parsing bang path
# strip last item, should be user name
$sending_domain = $from_address;
$sending_domain =~ s/![^!]+$//;
# strip any leading items
$sending_domain =~ s/^.*!//;
if ($opt_d) {printf "domain!=%s\n", $sending_domain; }
} else {
$sending_domain = "";
} # if @ domain
#---
# initialize message section state
foreach $bouncer (keys %bounce_from) {
$section_ok{$bouncer} = 0;
} # foreach
#-----------------------------------------
# read message body, looking for bounce section
#-----------------------------------------
while ($line = <STDIN> ) {
$line = &chop_nl($line);
if ($opt_d) {print "$opt_d=$section_ok{$opt_d} $line\n"; }
# on each line, check to see if it matches profile of any known
# bouncer in table.
foreach $bouncer (keys %bounce_from) {
# first check from: and subject: to see if they match
if ($hdrs{"from"} =~ /$bounce_from{$bouncer}/i &&
$hdrs{"subject"} =~ /$bounce_subject{$bouncer}/i ) {
# then check line contents
if ($line =~ /$bounce_startline{$bouncer}/i) {
$section_ok{$bouncer} = 1;
} elsif ($line =~ /$bounce_endline{$bouncer}/i) {
$section_ok{$bouncer} = 0;
} elsif ( $section_ok{$bouncer} &&
$line =~ /$bounce_left{$bouncer}/i &&
$line =~ /$bounce_right{$bouncer}/i) {
#Line matches left/right patterns
$address = $line;
if ($opt_d) {print "$bouncer line= $address\n"; }
#strip left part preceding address
$address =~ s/$bounce_left{$bouncer}//i;
if ($opt_d) {print "$bouncer L= $address\n"; }
#strip right part following address
$address =~ s/$bounce_right{$bouncer}//i;
if ($opt_d) {print "$bouncer R= $address\n"; }
# strip any comments or brackets from address
($newaddr,@junk) = &ParseAddrs($address);
$rest_of_line = $line;
$rest_of_line =~ s/$newaddr//i; # take address out of rest of line
$rest_of_line =~ s/[^a-zA-z0-9]+/ /g; # strip garbage
if ($rest_of_line !~ /^ *$/) {$rest_of_line = " - " . $rest_of_line;}
# Add address to list of addresses needing to be bounced.
$newaddr =~ tr/A-Z/a-z/;
if ($newaddr !~ /^ *$/) {
$bounce_address{$newaddr} = $rest_of_line;
} # if non-blank
# remember which profile matched message.
$mailer_found = $bouncer;
} # if line matches
} # if subject and sender
} # foreach $bouncer
} # while STDIN
#----------------------------
# Done reading message.
# Only do the rest if we found some addresses.
if (scalar(keys %bounce_address) >= 1) {
# We have some addresses. Create message to Majordomo.
$to = $whoami;
$sender = $approval;
if (defined($opt_d)) {
open(MSG, ">&STDOUT");
} else {
eval "\$prog=\"$mailer\"";
open(MSG, "|$prog") ||
&abort("open(MSG, \"|$prog\"): $!\nStopped");
}
print MSG "To: $to\n";
print MSG "From: $sender\n";
print MSG "Subject: autobounce request for list $list\n";
print MSG "\n\n";
foreach $address (keys %bounce_address) {
# Put in comments on what we're doing.
printf MSG "# Autobounce request\n";
printf MSG "# Bouncing address : %s\n", $address;
printf MSG "# From mailer : %s\n", $hdrs{"from"};
printf MSG "# Mailer type : %s\n", $mailer_found;
printf MSG "# On Date : %s\n", $hdrs{"date"};
printf MSG "# Reason : %s\n", $bounce_address{$address};
# If we extracted any addresses, make sure they are on the list.
# if not, don't do subscribe/unsub.
if (&is_list_member($address,$listdir,$list) > 0) {
$final_address = $address;
} else {
# address wasn't on list, try appending sending domain
$final_address = $address . "@" . $sending_domain;
if (! &is_list_member($final_address,$listdir,$list) > 0) {
$final_address = "";
} # if not list member
} # if list member
if ($final_address ne "" ) {
printf MSG "approve %s unsubscribe %s %s\n",
$list_passwd, $list, $final_address;
if ($add_bounces) {
printf MSG "approve %s subscribe %s %s (%02d%02d%02d %s%s)\n",
$bounce_passwd, $bounce_list, $final_address,
$year, $mon+1, $mday, $list,
$bounce_address{$address};
} # if add_bounces
} else {
print MSG "which $address\n";
} # if final_address not blank
} # foreach address
print MSG "# autobounce by Alan Millar <amillar@bolis.sf-bay.org>";
close(MSG);
} # if any addresses found
exit (0);
====================================================================
autobounce.cf:
====================================================================
#-------------------------------------
# NOTE: Make sure the bounce_left pattern starts with ^ and
# bounce_right ends with $ anchors!
#
# Back-quoted metacharacters need a double backslash.
#-------------------------------------
# Most versions of sendmail
$bounce_from{"sendmail"} = "mail delivery subsystem";
$bounce_subject{"sendmail"} = "returned mail";
$bounce_startline{"sendmail"} = "^ *-+ *transcript of session";
$bounce_endline{"sendmail"} = "^ *-+ *unsent message";
$bounce_left{"sendmail"} = "^ *5[0-9]+ *";
$bounce_right{"sendmail"} = "[.][.][.].*$";
#-------------------------------------
# Microsoft Mail for PC networks
$bounce_from{"ms-mail"} = "admin";
$bounce_subject{"ms-mail"} = "mail failure";
$bounce_startline{"ms-mail"} = "following unknown address";
$bounce_endline{"ms-mail"} = "---+";
$bounce_left{"ms-mail"} = "^ *[a-z0-9/]+/";
$bounce_right{"ms-mail"} = " *$";
#-------------------------------------
# SMail 3
$bounce_from{"smail3"} = "mailer-daemon";
$bounce_subject{"smail3"} = "mail failed";
$bounce_startline{"smail3"} = "failed addresses follow";
$bounce_endline{"smail3"} = "message text follow";
$bounce_left{"smail3"} = "^ *";
$bounce_right{"smail3"} = "[.][.][.].*$";
#-------------------------------------
# LMail
$bounce_from{"lmail"} = "lmail";
$bounce_subject{"lmail"} = "undeliver";
$bounce_startline{"lmail"} = "error description";
$bounce_endline{"lmail"} = "^ *error-end:";
$bounce_left{"lmail"} = "^ *error-for: *";
$bounce_right{"lmail"} = " *$";
#-------------------------------------
# PMDF
$bounce_from{"pmdf"} = "pmdf";
$bounce_subject{"pmdf"} = "undeliver";
$bounce_startline{"pmdf"} = "could not be delivered";
$bounce_endline{"pmdf"} = "^ *reason:";
$bounce_left{"pmdf"} = "^ *addressee: *";
$bounce_right{"pmdf"} = " *$";
#-------------------------------------
# IBM VM Batch SMTP mailer
$bounce_from{"ibm-bsmtp"} = "network mailer";
$bounce_subject{"ibm-bsmtp"} = "delivery";
$bounce_startline{"ibm-bsmtp"} = "transaction log follows";
$bounce_endline{"ibm-bsmtp"} = "message follows";
$bounce_left{"ibm-bsmtp"} = "^5[0-9]+.*: *";
$bounce_right{"ibm-bsmtp"} = " *$";
#-------------------------------------
# America On-Line service
$bounce_from{"aol"} = "aol.com";
$bounce_subject{"aol"} = "returned mail";
$bounce_startline{"aol"} = "could not be delivered";
$bounce_endline{"aol"} = "text you sent follows";
$bounce_left{"aol"} = "^.*\\(";
$bounce_right{"aol"} = "\\).*$";
#-------------------------------------
# MCI Mail service
$bounce_from{"mcimail"} = "mcimail.com";
$bounce_subject{"mcimail"} = "rejected";
$bounce_startline{"mcimail"} = "could not be forwarded";
$bounce_endline{"mcimail"} = "your message follows";
$bounce_left{"mcimail"} = "^ *to: *";
$bounce_right{"mcimail"} = " *$";
#-------------------------------------
# CompuServe users
$bounce_from{"compuserve"} = "compuserve.com";
$bounce_subject{"compuserve"} = "undeliverable";
$bounce_startline{"compuserve"} = "\\*\\*\\*\\*\\*";
$bounce_endline{"compuserve"} = "could not process";
$bounce_left{"compuserve"} = "^\\?.*: *";
$bounce_right{"compuserve"} = " *$";
#-------------------------------------
====================================================================
- Alan
----
Alan Millar E-Mail: amillar@bolis.SF-Bay.org
System Administrator Web: ftp://ftp.netcom.com/pub/amillar/welcome.html
I can't give you brains, but I can give you a diploma -Wizard of Oz to Scarecrow
|
|