From: drich@sandman.lerc.nasa.gov (Daniel Rich)
Subject: SCRIPT: perl sendmail utilities
Summary: log parsing and alias verification in perl
Keywords: sendmail,perl
Organization: NASA Lewis Research Center [Cleveland, Ohio]
Date: Tue, 25 Aug 1992 21:25:50 GMT


As a thank you to all of the people who have helped me with my
perl/sendmail questions over the last couple of weeks, I am posting
the scripts that have resulted.  These are two utilities that I have
needed for some time, and I want to thank everyone who was helpful in
their creating.

First of all, we have a script for parsing the sendmail syslog.  I
have had several occasions where managers have asked me if people are
using e-mail to communicate, or asked how much of the e-mail was being
sent off site.  This script will take a syslog file, and output a mail
summary including the total use statistics, and a summary by user and
host (anything within your domain is defined as "local").  In order to
run it, you will  need to change the $local_domain line, and either
change the $systype to match your system (no guarantees that this will
work :-), or hardcode the value for $MAILLOG (the name of your syslog
output file for sendmail).

The second script will validate user mail ids/aliases.  It should work
as-is, and will accept the following command line options:
	-n - noresolv: don't resolve to a local address
	-s - short output format (don't print "real name" and <>)
	-v - verbose output
It will find mail loops, expand mailing lists, and resolve all
addresses down to a local delivery (at least, what sendmail thinks is
local).  If it gets an unknown hostname from the host in the address,
it will attempt to find an MX record for that host, and try that.
This may produce unexpected mail loop messages, however; I haven't
come up with a good way of handling some of the MX hosts.  Also, you
may occasionally get a mail loop message if the same user is used
twice (ie. using addrcheck drich@lerc.nasa.gov drich@lerc.nasa.gov
will print a loop message for the second address).  This is a bug, but
the loop checking is rather simplistic at this stage.

Please let me know if you find these scripts useful, and I would
appreciate hearing of any suggestions/modifications you might have.

Just cut on the dotted lines below, and enjoy!

-- 
Dan Rich                    | drich@lerc.nasa.gov   |  (216) 433-4000
Sr. Systems Engineer        | "Danger, you haven't seen the last of me!"
RMS Technologies, Inc.      |    "No, but the first of you turns my stomach!"
NASA Lewis Research Center  | -- The Firesign Theatre's Nick Danger


8<- sm.logger ------------------ Cut Here ------------------------------>8
#! /usr/local/bin/perl
# $Id: sm.logger,v 1.3 92/08/25 16:00:34 drich Exp Locker: drich $
#
# Copyright (C) 1992  Daniel Rich
#
# Author: Daniel Rich (drich@lerc.nasa.gov)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License can be obtained from this
# program's author (send electronic mail to ange@hplb.hpl.hp.com) or from
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
# 02139, USA.
#
# sm.logger - parse the sendmail log and produce a summary
#
# $Log:	sm.logger,v $
# Revision 1.3  92/08/25  16:00:34  drich
# Fixed divide by zero error if no mail either delivered or sent.
# 
# Revision 1.2  92/08/05  14:03:14  drich
# Replaced '=' with '-' in output report
# 
# Revision 1.1  92/07/22  16:36:54  drich
# Logfile processor for sendmail
#
#
# Written by Dan Rich - drich@lerc.nasa.gov
#     Wed July 22, 1992
#

# Change the following for the appropriate system type.
$systype = "SGI";		# Valid are Ultrix, Sun, SGI, RS6000

# Change the following to the local sendmail domain
$local_domain = "lerc.nasa.gov";

LOOP: {
    if ( $systype eq "SGI")    { $MAILLOG = "/usr/adm/SYSLOG"; 
				 last LOOP; }
    if ( $systype eq "Ultrix") { $MAILLOG = "/usr/spool/mqueue/syslog";
				 last LOOP; }
    if ( $systype eq "Sun")    { $MAILLOG = "/var/adm/messages";
				 last LOOP; }
    if ( $systype eq "RS6000") { $MAILLOG = "/var/adm/messages";
				 last LOOP; }
    print "This script does not support the system type: $systype"; exit(1);
}

sub parse_mail_addr {
    local($addr) = @_;
    # Attempt to parse an address down to an *originating* user and host.
    # Assume the address takes one of the following forms:
    #     user@host.domain
    #     host!host!host!user
    #     host!host!host!user@host.domain
    #	  @host.domain:user@host.domain

    $user = "";
    $host = "";
    $domain = "";

    # Get rid of <> in address
    $addr =~ s/\<//g;
    $addr =~ s/\>//g;

    # Get rid of (Real Name)
    $addr =~ s/\(.*\)//;

    # Strip spaces
    $addr =~ s/ //g;

    # Split user and host
    if ( $addr =~ /[@!]/ ) {		# If we have and @ or ! address
        if ( (($user,$host) = ($addr =~ /@.*:(.*)@(.*)/ )) || 
	     (($user,$host) = ($addr =~ /(.*)@(.*)/ )) ) {
            if ( $user =~ /!/ ) {
	        ( $host, $user ) = ( $user =~ /([^!]*)!([^!]*)$/ );
            }
        } else {			# Ok, it is uucp format
            if ( $addr =~ /!/ ) {
	        ( $host, $user ) = ( $addr =~ /([^!]*)!([^!]*)$/ );
            }
        }
    } else {				# This had better be local...
        $user = $addr;
	$host = "";
	$domain = "";
    }

    # Split host and domain
    if ( $host =~ /\./ ) {
        ($host,$domain) = ( $host =~ /([^.]*)\.(.*)/ );
    }

    return ($user, $host, $domain);
}

sub format_addr {
    local($username, $host, $domain) = @_;

    $addr = "";
    $username =~ tr/A-Z/a-z/;
    $host =~ tr/A-Z/a-z/;
    $domain =~ tr/A-Z/a-z/;

    if ((length($domain) != 0) && ($domain ne $local_domain)) {
        $addr = $username. "@" . $host . "." . $domain;
    } elsif (length($host) != 0 ) {
	$addr = $username. "@" . $host;
    } else {
        $addr = $username;
    }
    return $addr;
}

sub format_host {
    local($host, $domain) = @_;

    $addr = "";
    $host =~ tr/A-Z/a-z/;
    $domain =~ tr/A-Z/a-z/;

    if (($domain eq $local_domain) || 
	(($host . "." . $domain) eq $local_domain) ||
	(length($domain) == 0)) {
        $addr = "local";
    } else {
        $addr = $host . "." . $domain;
    }
    return $addr;
}

open MAILLOG || die "failed to open log file: $!\n";

$start_date = "";
$start_time = "";

while ( <MAILLOG> ) {
    $line = "";
    ( $systype eq "SGI" ) && ( /sendmail\[[0-9]*\]:/ && ($line = $_) );
    ( $systype eq "Ultrix") && ( /sendmail:/ && ($line = $_) );
    if ( length($line) == 0 ) {
	next;
    }

    if ( length($start_date) == 0 ) {
        ($start_date, $start_time) = 
	    ($line =~ /^([A-Z][a-z]* *[0-9]*) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/);
    }
    ($end_date, $end_time) = 
	($line =~ /^([A-Z][a-z]* *[0-9]*) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])/);
	
    if (($ID, $addr) = ($line =~/: ([A-Za-z0-9]*): to=(.*), delay/)) {
        if ( $line =~ /stat=Sent/ ) {
            foreach $taddr (split(/,/, $addr)) {
                ($username, $host, $domain) = &parse_mail_addr($taddr);
                $user = &format_addr($username, $host, $domain);
                $host = &format_host($host, $domain);
                $userlist{$user} = 1;
                $delivered{$user} .= $ID . ' ';
    	        $hostlist{$host} = 1;
                $delivered{$host} .= $ID . ' ';
                # Check if it was deferred
                $IDlist = $deferred{$user};
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
    	                $deferred{$user} =~ s/$ID //g;
                    }
                }
                $IDlist = $deferred{$host};
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
    	                $deferred{$host} =~ s/$ID //g;
                    }
                }
            }
        } elsif ( $line =~ /stat=Deferred/ ) {
            foreach $taddr (split(/,/, $addr)) {
                ($username, $host, $domain) = &parse_mail_addr($taddr);
                $user = &format_addr($username, $host, $domain);
                $host = &format_host($host, $domain);
                $userlist{$user} = 1;
    	        $hostlist{$host} = 1;
                # Check if it was deferred earlier
                $IDlist = $deferred{$user};
		$IDdeferred = 0;
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
    	                $IDdeferred = 1;
                    }
                }
		if ( $IDdeferred == 0 ) {$deferred{$user} .= $ID . ' ';}
                $IDlist = $deferred{$host};
		$IDdeferred = 0;
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
    	                $IDdeferred = 1;
                    }
                }
		if ( $IDdeferred == 0 ) {$deferred{$host} .= $ID . ' ';}
            }
        } else {
            foreach $taddr (split(/,/, $addr)) {
                ($username, $host, $domain) = &parse_mail_addr($taddr);
                $user = &format_addr($username, $host, $domain);
                $host = &format_host($host, $domain);
                $IDlist = $deferred{$user};
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
                        $deferred{$user} =~ s/$ID //g;
                        last;
                    }
                }
                $IDlist = $deferred{$host};
                foreach $tID (split(/ /, $IDlist)) {
                    if ( $tID == $ID ) {
        		    $deferred{$host} =~ s/$ID //g;
                        last;
                    }
                }
            }
        }
    }
    if (($ID, $addr, $size) = ($line =~/: ([A-Za-z0-9]*): from=(.*), size=([0-9]*)/)) {
        ($username, $host, $domain) = &parse_mail_addr($addr);
        $user = &format_addr($username, $host, $domain);
	$host = &format_host($host, $domain);
        $userlist{$user} = 1;
        $sent{$user} .= $ID . ' ';
        $hostlist{$host} = 1;
        $sent{$host} .= $ID . ' ';
        $size{$ID} = $size;
    }
}

printf ("\n\n\t\t\tSendmail activity report\n");
printf ("Starting: %s %s\n",$start_date,$start_time);
printf ("Ending: %s %s\n",$end_date,$end_time);

#
# User statistics
$totsent = 0;
$totdelivered = 0;
$totpctsent =0;
$totpctdelivered = 0;
$countsent = 0;
$countdelivered = 0;
$countdeferred = 0;
foreach $user (sort keys(%userlist)) {
    $totsent{$user} = 0;
    $totdelivered{$user} = 0;
    $countsent{$user} = 0;
    $countdelivered{$user} = 0;
    $countdeferred{$user} = 0;

    # Count total messages sent by each user
    $IDlist = $sent{$user};
    foreach $ID (split(/ /, $IDlist)) {
	$totsent{$user} += $size{$ID};
        $countsent{$user}++;
    }
    $totsent += $totsent{$user};
    $countsent += $countsent{$user};

    # Count total messages received by each user
    $IDlist = $delivered{$user};
    foreach $ID (split(/ /, $IDlist)) {
	$totdelivered{$user} += $size{$ID};
        $countdelivered{$user}++;
    }
    $totdelivered += $totdelivered{$user};
    $countdelivered += $countdelivered{$user};

    # Count deferred messages for each user
    $IDlist = $deferred{$user};
    foreach $ID (split(/ /, $IDlist)) {
        $countdeferred{$user}++;
    }
    $countdeferred += $countdeferred{$user};
}

printf ("\n\n");
$REPORTFMT = "%-20s %5s %8s\n";
$REPORTNUM = "%-20s %5d %8d\n";
printf ($REPORTFMT,"Message Status","Total","Size");
printf ("-----------------------------------\n");
printf ($REPORTNUM,"Received",$countsent,$totsent);
printf ($REPORTNUM,"Delivered",$countdelivered,$totdelivered);
printf ($REPORTNUM,"Deferred",$countdeferred);

printf ("\n\nUser Statistics:\n\n");
$REPORTFMT = "%-30s %6s %8s %7s %6s %8s %7s\n";
$REPORTNUM = "%-30s %6d %8d %6.2f%% %6d %8d %6.2f%%\n";
printf ($REPORTFMT,"User Name","# from","size","%","# to","size","%");
printf ($REPORTFMT,"---------","------","--------","------","------","--------","------");
foreach $user (sort keys(%userlist)) {
    $percent1 = 0;
    $percent2 = 0;

    $percent1 = ($totsent{$user}/$totsent)*100		    if ($totsent != 0);
    $percent2 = ($totdelivered{$user}/$totdelivered)*100    if ($totdelivered != 0);
    printf ($REPORTNUM,substr($user,0,30),
	$countsent{$user},$totsent{$user},$percent1,
	$countdelivered{$user},$totdelivered{$user},$percent2);
    $totpctsent += $percent1;
    $totpctdelivered += $percent2;
}
printf ("------------------------------------------------------------------------------\n");
printf ($REPORTNUM,"Totals",$countsent,$totsent,$totpctsent,$countdelivered,$totdelivered,$totpctdelivered);

# 
# Host statistics
foreach $host (sort keys(%hostlist)) {
    $totsent{$host} = 0;
    $totdelivered{$host} = 0;
    $countsent{$host} = 0;
    $countdelivered{$host} = 0;
    $countdeferred{$host} = 0;

    # Count total messages sent by each host
    $IDlist = $sent{$host};
    foreach $ID (split(/ /, $IDlist)) {
	$totsent{$host} += $size{$ID};
        $countsent{$host}++;
    }

    # Count total messages received by each host
    $IDlist = $delivered{$host};
    foreach $ID (split(/ /, $IDlist)) {
	$totdelivered{$host} += $size{$ID};
        $countdelivered{$host}++;
    }
}

printf ("\n\nHost Statistics:\n\n");
$REPORTFMT = "%-30s %6s %8s %7s %6s %8s %7s\n";
$REPORTNUM = "%-30s %6d %8d %6.2f%% %6d %8d %6.2f%%\n";
printf ($REPORTFMT,"Host Name","# from","size","%","# to","size","%");
printf ($REPORTFMT,"---------","------","--------","------","------","--------","------");
foreach $host (sort keys(%hostlist)) {
    $percent1 = 0;
    $percent2 = 0;

    $percent1 = ($totsent{$host}/$totsent)*100		    if ($totsent != 0);
    $percent2 = ($totdelivered{$host}/$totdelivered)*100    if ($totdelivered != 0);
    printf ($REPORTNUM,substr($host,0,30),
	$countsent{$host},$totsent{$host},$percent1,
	$countdelivered{$host},$totdelivered{$host},$percent2);
}
printf ("------------------------------------------------------------------------------\n");
printf ($REPORTNUM,"Totals",$countsent,$totsent,$totpctsent,$countdelivered,$totdelivered,$totpctdelivered);

8<- addrcheck ------------------ Cut Here ------------------------------>8
#!/usr/local/bin/perl
# $Id: addrcheck,v 1.2 92/08/25 16:56:59 drich Exp $
#
# Copyright (C) 1992  Daniel Rich
#
# Author: Daniel Rich (drich@lerc.nasa.gov)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 1, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License can be obtained from this
# program's author (send electronic mail to ange@hplb.hpl.hp.com) or from
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
# 02139, USA.
#
# addrcheck - verify a user's e-mail address (will continue contacting hosts
#	      until it either finds a local address, or a loop).
#	      It will also expand any mailing lists it finds.
#	-n - noresolv: don't resolve to a local address
#	-s - short output format (don't print "real name" and <>)
#	-v - verbose output
#
# $Log:	addrcheck,v $
# Revision 1.2  92/08/25  16:56:59  drich
# Added MX record lookup for unknown hosts.
# 
# Revision 1.1  92/08/21  11:13:04  drich
# Initial revision
# 
# Written by:
#     Dan Rich (drich@lerc.nasa.gov)
#	Friday August 21, 1992
# Based on an original perl script by:
#     Nick Holloway (alfie@dcs.warwick.ac.uk)
#

$0 =~ s%.*/%%;			# $0 = basname $0

require('getopts.pl');

sub nslookup {
    local($mxhost) = "";
    local($pref) = 10000;
    local($c) = '';

    # Use nslookup to find MX record for host name.
    pipe ( CHLD_RD, NSL_WR );
    pipe ( NSL_RD, CHLD_WR );
    if ( ( $pid = fork () ) < 0 ) {
	die ( "$0: fork failed: $!\n" );
    }
    if ( $pid == 0 ) {			# child
	open ( STDOUT, ">&CHLD_WR" );
	open ( STDERR, ">&CHLD_WR" );
	open ( STDIN,  "<&CHLD_RD" );
	close ( CHLD_RD ); close ( NSL_WR );
	close ( NSL_RD ); close ( CHLD_WR );
	select ( STDIN );  $| = 1;
	select ( STDOUT ); $| = 1;
	select ( STDERR ); $| = 1;
	exec "nslookup";
	exit ( 1 );
    } else {				# parent
	close ( CHLD_RD ); select ( NSL_WR ); $| = 1;
	close ( CHLD_WR ); select ( NSL_RD ); $| = 1;
	select ( STDOUT );
    }

    # Use read() since we have prompts
    $c = '';
    while ( ! (<NSL_RD> =~ /Default Server:/) ) {}
    while (read(NSL_RD, $c, 1) && ($c ne '>'))  {}	# Skip opening text
    if ( ! read (NSL_RD, $c, 1) ) {			# and prompt
        return 0;
    }
    print NSL_WR "set type=MX\n";			# Set type=MX
    if ( ! read (NSL_RD, $c, 1) ) {			# Skip prompt
	return 0;
    }
    print NSL_WR $node,"\n";				# Send nodename

    $mxhost = ""; $c = "";
    while ($c ne ">") {
        $line = "";
        while (read(NSL_RD, $c, 1) && ( ($c ne ">") && ($c ne "\n") ))  {
	    $line = $line . $c;
        }
        if ( $line =~ /exchanger =/ ) {
	    $line =~ /preference = ([0-9]*)/;
	    if ( $1 < $pref ) {
	        $pref = $1;
	        ( $line =~ /exchanger = (.*)/ ) && ( $mxhost = $1 );
	    }
	}
    }

    if ( $mxhost eq "" ) {
        # Ok, so it isn't an MX host, how about an A record?
        if ( ! read (NSL_RD, $c, 1) ) {	# Skip prompt
	    return 0;
        }
        print NSL_WR "set type=A\n";
        if (! read (NSL_RD, $c, 1) ) {	# Skip prompt
	    return 0;
	}
        print NSL_WR $node,"\n";

        $mxhost = ""; $c = "";
        while ($c ne ">") {
            $line = "";
            while (read(NSL_RD, $c, 1) && ( ($c ne ">") && ($c ne "\n") ))  {
	        $line = $line . $c;
            }
            if ( $line =~ /Name:/ ) {
	        ( $line =~ /Name:[ 	]*(.*)/ ) && ( $mxhost = $1 );
	    }
        }
    }

    close ( NSL_RD );	close ( NSL_WR );
    while ( wait != -1 ) { ; }
    if ( $mxhost eq "" ) {
        0;
    } else {
        $node = $mxhost;
	1;
    }
}

sub openhost {
    pipe ( CHLD_RD, SMTP_WR );
    pipe ( SMTP_RD, CHLD_WR );
    if ( ( $pid = fork () ) < 0 ) {
	die ( "$0: fork failed: $!\n" );
    }
    if ( $pid == 0 ) {			# child
	open ( STDOUT, ">&CHLD_WR" );
	open ( STDERR, ">&CHLD_WR" );
	open ( STDIN,  "<&CHLD_RD" );
	close ( CHLD_RD ); close ( SMTP_WR );
	close ( SMTP_RD ); close ( CHLD_WR );
	select ( STDIN );  $| = 1;
	select ( STDOUT ); $| = 1;
	select ( STDERR ); $| = 1;
	exec "telnet $node smtp";
	exit ( 1 );
    } else {				# parent
	close ( CHLD_RD ); select ( SMTP_WR ); $| = 1;
	close ( CHLD_WR ); select ( SMTP_RD ); $| = 1;
	select ( STDOUT );
    }
    1
}

# Parse command line args
if (! do Getopts('nsv') ) {
    die ( "usage: $0 [ -nsv ] alias ...\n" .
	  "       where alias is of the form \"user@node\" or \"user\"\n" );
}
$noresolv = 1 	if ( $opt_n );
$short = 1	if ( $opt_s );
$verbose = 1	if ( $opt_v ); 

$SIG{'CHLD'} = 'fireman';
$SIG{'HUP'}  = 'interrupt';
$SIG{'INT'}  = 'interrupt';
$SIG{'TERM'} = 'interrupt';

@aliaslist = @ARGV;		# The list of aliases to check
$aliaslist_pos = -1;		# Our position in the list

# Loop through the list of aliases, parsing each one.  If we find one that 
# is doesn't resolve locally, insert it into the list.  Also expand mailing
# lists by inserting them after the current address.
for $alias ( @aliaslist ) {
    $aliaslist_pos++;

    ( $user, $node ) = split ( '@', $alias );

    $node = "localhost"	if ( $node eq "" );	# Localhost if null

    if ( $nodelist{$node} ) {
	# Check for mail loops (any host/user pair that we have seen before)
	if ( $nodelist{$node} =~ /$user/ ) {
	    print "ERROR: mail loop: $alias\n";
	    next;
	} else {
	    # Build a list of users on this node
	    $nodelist{$node} = $nodelist{$node} . ":" . $user;
	}
    } else {
	$nodelist{$node} = $user
    }

    do openhost();		# Open a connection to $node

    $_ = <SMTP_RD>;
    if ( /[Uu]nknown host/ ) {
	if ( do nslookup() ) {	# If host unknown, try for MX record
	    do openhost();	# and open it again
	    $_ = <SMTP_RD>;
	} else {
            warn ( "$0: $_" );
	    close ( SMTP_WR ); close ( SMTP_RD );
	    next;
        }
    }
    $_ = <SMTP_RD>		if /^Trying/;
    $_ = <SMTP_RD>		if /^Connected/;

    $_ = <SMTP_RD>		if /^Escape/;
    if ( ! /^220/ ) {
	warn ( "$0: unable to connect to host \"$node\"\n" );
	print SMTP_WR "quit\n";
	close ( SMTP_WR ); close ( SMTP_RD );
	next;
    }

    if ( $verbose ) {
	# Set verbose mode
        print SMTP_WR "VERB\n";
        $_ = <SMTP_RD>; chop;
	if (! /^200/ ) {
	    print "$0: error setting verbose: $_\n";
	}
    }
    print SMTP_WR "VRFY $user\n";
    $_ = <SMTP_RD>; chop;

    while ( $verbose && /^050/ ) {
	print "$alias -> "; 
	s/^\d{3} //;
	print " $_\n";
        $_ = <SMTP_RD>; chop;
    }
    if ( /^250/ ) {		# alias expansion
	print "$alias ->";
	$len = length ( $alias ) + 3;
	@addrlist = ();
	while ( /^250-/ ) {
	    s/^250-//; s/\s+/ /g; 
	    push (@addrlist, $_);
	    s/.*<(.*)>.*/\1/	if $short;
	    $len += length ( $_ ) + 2;
	    if ( $len > 79 ) {
	    	print "\n ";
	        $len = length ( $_ ) + 3;
	    }
	    print " $_,";
	    $_ = <SMTP_RD>; chop;
	}
	s/^250 //; s/\s+/ /g; 
        push(@addrlist, $_);
	s/.*<(.*)>.*/\1/	if $short;
	if ( length ( $_ ) + $len > 79 ) {
	    print "\n ";
	}
	print " $_\n";
	if ( ! $noresolv ) {
	    # The following mess is what puts the new address into @aliaslist
	    if ( $#addrlist != 0 ) {
		# Process list
		for $talias ( reverse @addrlist ) {
		    $talias =~ s/.*<(.*)>.*/\1/;
		    if ( $#aliaslist > $aliaslist_pos ) {
		        @taliaslist = splice(@aliaslist, $aliaslist_pos + 1);
		        push (@aliaslist, $talias);
		        push (@aliaslist, @taliaslist);
		    } else {
		        push (@aliaslist, $talias);
		    }
		}
	    } else {
                if (($addrlist[0] =~ /<.*@(.*)>$/) eq "") {
	        } else {
	            $addrlist[0] =~ /<(.*)>$/;
		    $1 =~ s/.*<(.*)>.*/\1/;
		    if ( $#aliaslist > $aliaslist_pos ) {
		        @taliaslist = splice(@aliaslist, $aliaslist_pos + 1);
		        push (@aliaslist, $1);
		        push (@aliaslist, @taliaslist);
		    } else {
		        push (@aliaslist, $1);
		    }
		}
	    }
        }
    } else {		# Return code not 250
        s/^\d{3} //;
        print "ERROR: $alias -> $_\n";
    }
	
    print SMTP_WR "QUIT\n";
    $_ = <SMTP_RD>;			# 221 ... closing connection
    $_ = <SMTP_RD>;			# Connection closed ...
    close ( SMTP_WR ); close ( SMTP_RD );
} continue {
    while ( wait != -1 ) { ; }
}

sub fireman {
    # while ( wait != -1 ) { ; }
}

sub interrupt {
    kill 'TERM', $pid;
    print STDERR "$0: interrupted\n";
    exit ( 1 );
}
8<------------------------------ Cut Here ------------------------------>8

-- 
-- 
Dan Rich                    | drich@lerc.nasa.gov   |  (216) 433-4000
Sr. Systems Engineer        | "Danger, you haven't seen the last of me!"
RMS Technologies, Inc.      |    "No, but the first of you turns my stomach!"
NASA Lewis Research Center  | -- The Firesign Theatre's Nick Danger