#!/usr/local/bin/perl
#                                                          # -*-Perl-*-
#=======================================================================
#            :
#        File: mj_build_aliases.pl     
#            :
#     Purpose: This routine builds .majordomo_aliases using the ownership
#            : info in the individual list config files. Lists without an
#            : "owner" defined will not be activated in the aliases file.
#            : The .majordomo_aliases file can then be combined with other
#            : system aliases to make a complete aliases file for sendmail.
#            :
#            : The changes from the original mj_build_aliases are shown
#            : at the end of this file, where RCS log. information goes.
#            : I advice you to take a look down there :)
#-----------------------------------------------------------------------
#            :
#   $Revision: 1.4 $        
#       $Date: 1997/07/16 15:25:28 $
#      $State: Exp $
#            :
#     $Source: /u/ricky/perl/majordomo/RCS/mj_build_aliases2.pl,v $
#    $RCSfile: mj_build_aliases2.pl,v $
#            :
#     $Locker:  $
#            :
#=======================================================================
#
# RCS stuff
#

$MJBA_revision  = ' $Revision: 1.4 $ ';
$MJBA_revision  =~ s/^\D*(\d+\.\d+)\D*$/$1/;


# In addition, the "owner" field is used to automatically define
# a "majordomo-users" mailing list. Addresses listed in the
# %ignore_owners array will not be included in the list.

$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf"; 
$aliases = ".majordomo_aliases";
$admins = "majordomo-users";
$owner = "postmaster";

# these owners will not be added to the majordomo-users list
#
%ignore_owners = (
	'nobody',		1,
	'wwis.sdhelp',		1,
	'sdassign',		1,
	'web.master',		1,
);

# Before doing anything else tell the world I am majordomo
# The mj_ prefix is reserved for tools that are part of majordomo proper.
$main'program_name = 'mj_build_aliases2.pl';

require "getopts.pl";


$usage_message = <<"EOM";

Usage: $main'program_name [-C config_file] [-a aliases_file] 
              [-l owners_file] [-o owner] [-v] [-f] [-m] [-t]
      
Options:  -C config_file    Set config_file
          -a aliases_file   build aliases_file ($aliases)
          -l owner_file     use owners_file or list ($admins)
          -o owner          Set the main majordomo/majorcool owner ($owner)
          -f                Force
          -m                Mail results to majordomo owner
          -t                Test only
          -v                Be verbose

EOM
      
die($usage_message) unless &Getopts("C:a:l:o:tvfm");

#
# The following is for compatibility with the old mj_build_aliases
# script
#

$cf =       $opt_C if $opt_C;
$aliases =  $opt_a if $opt_a;
$admins =   $opt_l if $opt_l;
$owner =    $opt_o if $opt_o;

#
# Reference and temporary files...
#

$aliases_ref = "$aliases.ref";
$aliases_tmp = "$aliases.tmp";

# Read and execute the .cf file
die("$cf not readable; stopped") unless -r $cf;
die("require of majordomo.cf failed $@") unless require $cf;

# 1.94 has this set in $CF already
$sendmail_command = "/usr/lib/sendmail" unless $sendmail_command;

# Go to the home directory specified by the .cf file
chdir("$homedir");

# All these should be in the standard PERL library
unshift(@INC, $homedir);
require "ctime.pl";		# To get MoY definitions for month abbrevs
require "majordomo_version.pl";	# What version of Majordomo is this?
require "majordomo.pl";		# all sorts of general-purpose Majordomo subs
require "shlock.pl";		# NNTP-style file locking
require "config_parse.pl";	# functions to parse the config files

# Here's where the fun begins...

# check to see if the cf file is valid
die("listdir not defined. Is majordomo.cf being included correctly?")
	if !defined($listdir);

# where do we look for files, by default?
$filedir = $listdir unless defined($filedir);
$filedir_suffix = ".archive" unless defined($filedir_suffix);

#----------------------------------------------------------------------------

$majordomo_cmd =
	"|$homedir/wrapper majordomo";			# "-l $list" optional
$owner_bounce_cmd =
	"|$homedir/wrapper mj_owner_bounce";		# no args needed
$filter_cmd =
	"|$homedir/wrapper mj_filter";			# no args needed
$log_cmd =
	"|$homedir/wrapper mj_log2 -m ";		# "$list" needed
$unavail_cmd =
	"|$homedir/wrapper mj_list-unavail";		# "$list" needed
$newlist_cmd =
	"|$homedir/wrapper new-list";			# "$list" needed
$resend_cmd =
	"|$homedir/wrapper resend -h $whereami -l";	# "$list", "$list-outgoing"
$archive_cmd = 
	"|$homedir/wrapper archive2.pl -a -f";		# archive-base, frequency (-[dmy])
$digest_cmd =
	"|$homedir/wrapper digest -r -C -l";		# "$list", "$list-outgoing"

# check if process already running
#
unless (($opt_t) || &shlock("$listdir/.build.LOCK")) {
	printf STDERR "$main'program_name: build already running\n" if ($opt_v);
	exit;
}

# check if $listdir, config files, or lists have changed
#
if (-r "$ENV{HOME}/$aliases" && !($opt_f)) {
	unless (`find $listdir/. -type f -name '.[a-z]*' -prune -o \\( -name '*.config' -o -name '.' \\) -newer $ENV{HOME}/$aliases -print`) {
		print STDERR "$main'program_name: no Majordomo list changes detected.\n";
		exit(0);
	}
}

# open alias file
#
unless ($opt_t) {
	printf STDERR "$main'program_name: rebuilding $aliases\n" if ($opt_v);
	open(STDOUT, ">$ENV{HOME}/$aliases_tmp");
}

# match all lists
#
local($nlists_total, $nlists_active) = 0;
opendir(RD_DIR, $listdir) || die("opendir failed $!");
@lists = readdir(RD_DIR);
closedir(RD_DIR);

# these are top-level MD aliases
#
printf STDERR "$main'program_name: adding Majordomo aliases\n" if ($opt_v);
print <<"EOM";
#=======================================================================
#            :
#        File: $aliases
#            :
#     Purpose: This file contains the automatically builded aliases for 
#            : majordomo. It was produced by running the program
#            : $main'program_name (Rev. $MJBA_revision)
#            :
#-----------------------------------------------------------------------
#            :
#   \$\urevision: \$
#       \$\udate: \$
#      \$\ustate: \$
#            :
#     \$\usource: \$
#    \$\urCSfile: \$
#            :
#     \$\ulocker: \$
#            :
#=======================================================================
#
# MAJORDOMO CONFIGURATION
#
#-----------------------------------------------------------------------
majordomo:		"$majordomo_cmd"
majordomo-owner:	$owner
owner-majordomo:	$owner
owner-owner:		$owner
listmanager:	$owner
pubs:			"$filter_cmd"

EOM

foreach (sort @lists) {
	local($list) = $_;
	$list =~ s,^.*/,,;				# strip off leading path
	$list =~ /[^-_0-9a-zA-Z]/ && next; # skip non-list files (*.info, etc.)

	# get/make config file
	&get_config($listdir, $list) if !&cf_ck_bool($list, '', 1);
	# make alias entries
	$owner = &do_list_aliases($list);
	if ($owner) {
		$owner =~ tr/A-Z/a-z/;			# match lowercase
		next if $ignore_owners{$owner};		# some we ignore
		$owner_list{$owner} .= "$list,";	# save the owner
	}
}

print <<"EOM";

#=======================================================================
#
#                                  END of FILE
#
#                       No not change any thing below this line
#
#=======================================================================
EOM

exit(0) if ($opt_t);
close(STDOUT);

#
# Make a backup copy of the $aliases file into $aliases_ref
# (Used to compute the description message for mailing results or
# optionally for RCS description messages..
#
if (-f "$ENV{HOME}/$aliases") {
    rename("$ENV{HOME}/$aliases", "$ENV{HOME}/$aliases_ref");
}

rename("$ENV{HOME}/$aliases_tmp", "$ENV{HOME}/$aliases");

printf STDERR "$main'program_name: $nlists_total lists processed ($nlists_active active)\n"
	if ($opt_v);

# open owner-list file
#
printf STDERR "$main'program_name: rebuilding $admins\n" if ($opt_v);
open(FILE, ">$listdir/$admins");

foreach (keys(%owner_list)) {
	chop($owner_list{$_});
	print FILE "$_ ($owner_list{$_})\n";
}
close(FILE);
unlink("$listdir/.build.LOCK");

#
# Mail results??
#

if ($opt_m) {

    $desc = &get_changes_description("$ENV{HOME}/$aliases","$ENV{HOME}/$aliases_ref");
    print STDERR "--- $main'program_name: Description of changes are ---\n$desc--\n" if ($opt_v);

    #
    # Now mail the results :)
    #
    &set_mailer($bounce_mailer ? $bounce_mailer : $mailer);
    &set_mail_sender($whoami_owner);
    &set_mail_from($whoami_owner);
    &sendmail(MAIL, $opt_o, "Mail aliases changed by $main'program_name");
    print MAIL <<"EOF";
Hello Majordomo owner:

The following changes were done on the mail aliases
'$ENV{HOME}/$aliases' file

The changes are:
------------------------------------------------------------------------------

$desc
------------------------------------------------------------------------------


FYI, a copy of the old '$aliases' file 
was saved as '$aliases_ref' file. 

--- $whoami
P.D. Contrary to popular belief, Unix is user friendly.  
     It just happens to be selective about who it makes friends with.
EOF

    close(MAIL);

}

# do all additional tasks as background process
#
if (-x "$homedir/mj_background_tasks") {
	printf STDERR "$main'program_name: invoking background tasks\n" if ($opt_v);
	system "$homedir/wrapper mj_background_tasks" . (($opt_v) ? " -v" : "") . "&";
}

#----------------------------------------------------------------------------

# Everything from here on down is subroutine definitions

sub do_list_aliases {
	local($list) = shift;
	local($list_owner,$list_moderator,$supplemental);
	$list_owner = $config_opts{$list,'owner'};
	$list_moderator = $config_opts{$list,'moderator'};
	$list_moderator = $list_owner unless ($list_moderator);

	# 'owner' keyword is not implemented! default to Mj owner
	$list_owner = $list_moderator = $owner
		unless defined($config_opts{$list,'owner'});

	# check validity of owner/moderator addresses
	$list_owner = &valid_addr($list_owner);
	$list_moderator = &valid_addr($list_moderator);

	# Archive and Digest are stubs for work-in-progress
	if (&cf_ck_bool($list,'archive')) {
		local($dir,$freq);
		printf STDERR "$main'program_name: <$list> is archived\n" if ($opt_v);
		$dir = $config_opts{$list,'archive_dir'};
		$dir = "$filedir/$list$filedir_suffix" unless $dir;
		unless (-d $dir) {
			printf STDERR "$main'program_name: creating archive directory\n" 
				if ($opt_v);
			printf STDERR "$main'program_name: $dir mkdir failed ($!)\n" unless
				mkdir($dir, 0770);
		}
		$freq = $config_opts{$list,'archive_frequency'};
		$freq = "-d" if $freq eq "daily";
		$freq = "-m" if $freq eq "monthly";
		$freq = "-y" if $freq eq "yearly";
		$freq = "-m" unless $freq;	# default
		$supplemental .= ", \"$archive_cmd $dir/archive $freq\"";
	}
	if (&cf_ck_bool($list,'digest')) {
		printf STDERR "$main'program_name: <$list> is digested\n" if ($opt_v);
		$supplemental .= ", \"$digest_cmd $list-digest $list-digest-outgoing\"";
	}

	$nlists_total++;
	unless ($list_owner && $list_moderator) {
		printf STDERR "$main'program_name: owner/moderator invalid or not specified for <$list>\n" if ($opt_v);
		print <<"EOM";

#=======================================================================
#
# $list (UNAVAILABLE)
#
#-----------------------------------------------------------------------
$list:		"$unavail_cmd $list"
$list-request:	"$majordomo_cmd -l $list"

EOM
		return;
	}


	$nlists_active++;
	printf STDERR "$main'program_name: active list <$list>\n" if ($opt_v);
	print <<"EOM";

#=======================================================================
#
# $list (ACTIVE)
#
#-----------------------------------------------------------------------
$list:		"$resend_cmd $list $list-outgoing", "$log_cmd $list"
$list-request:	"$majordomo_cmd -l $list"
$list-outgoing:	:include:$listdir/$list $supplemental
$list-approval:	$list_moderator
$list-owner:	$list_owner
$list-outgoing-owner:	$list_owner
owner-$list:	$list_owner
owner-$list-outgoing:	$list_owner

EOM
	if ($config_opts{$list,"digest"}) {
		print <<"EOM";
$list-digest:	$list
$list-digest-request:	"$majordomo_cmd -l $list-digest"
$list-digest-outgoing:	:include:$listdir/$list-digest
$list-digest-approval:	$list_moderator
$list-digest-owner:	$list_owner
$list-digest-outgoing-owner:	$list_owner
owner-$list-digest:	$list_owner
owner-$list-digest-outgoing:	$list_owner

EOM
	}
	return $list_owner;
}

sub valid_addr {
	local($addr) = shift;
	return $addr;
	$_ = $addr;
	# all comparisons in l/c
	tr/A-Z/a-z/;
	# remove local domain names
	s/sandiegoca.ncr.com//;
	s/elsegundoca.ncr.com//;
	# remove trailing ., @
	s/\.$//; s/\@$//;

	# here will end up with:
	#	userid
	#	first.last
	#	anything@localhost
	#	anything@non-local.domain

	# skip anything non-local
	return $addr if /\./ && /\@/;

	# skip all @localhost
	return $addr if /\@/;

	local(@trace);
	@trace = `/usr/local/bin/rolo -u1 -L name $_ 2>&1` if /\./;
	@trace = `/bin/ypmatch -k $_ aliases 2>&1` if /^[_\w]+$/;
	return ($? ? "" : "$_");
}

sub get_changes_description {
    local($new_file,$old_file) = @_;
    local(@oldies,@newies);
    local(%MER);

    grep(($MER{$_}++) && 0,    &get_aliases_from_file($old_file));
    grep(($MER{$_} += 2) && 0, &get_aliases_from_file($new_file));

    foreach $element ( keys %MER) {
	#
	# case of $MER{$element}:
	#      1 OLD
	#      2 NEW
	#      3 No change...
	if ($MER{$element} == 1) {
            push(@oldies,$element);
	} elsif ($MER{$element} == 2) {
            push(@newies,$element);
	}
        
    }
    
    #
    # Prepare The description (Was for RCS)
    #

    $desc = '';
    if (@oldies) {
        $desc .= join(' ',"DELETED or MODIFIED:\n", sort @oldies);
    }
    if (@newies) {
        $desc .= join(' ',"ADDED or MODIFIED:\n", sort @newies);
    } 
    
    $desc = "None changes recorded.\n" if ($desc =~ /^$/);

    return $desc;

}

sub get_aliases_from_file {
    local($filename) = @_;
    local(@tmp_ref) = ();

    printf STDERR "$main'program_name: Reading $filename\n" if ($opt_v);

    if (-e $filename) {
        open(ALIASFILE, "$filename");
        @tmp_ref = <ALIASFILE>;
        @tmp_ref = grep(/:/, @tmp_ref);
        @tmp_ref = grep(!/^\#/, @tmp_ref);
        close(ALIASFILE);
    }

    return @tmp_ref;

}


##############################################################################
#
#                                  END of FILE
#
#                       No not change any thing below this line
#
##############################################################################
# 
# RCS LOG Information
# -------------------
# $Log: mj_build_aliases2.pl,v $
# Revision 1.4  1997/07/16 15:25:28  ricky
# $archive_cmd is now 'archive2.pl'
# $log_cmd is now 'mj_log2.pl'
#
# Revision 1.3  1997/07/16 15:16:35  ricky
# Removing the use of RCS, due that the aliases are always computed
# from the existent config files. (If you need/want RCS, just drop me
# a message to ricky@ornet.co.il and ask for it)
#
# Revision 1.2  1997/07/16 15:13:01  ricky
# - Adding a new flag: -m (mail) to send via e-mail a report of changes,
#   computed from the old $aliases file. (Verbose mode will also print
#   the changes on STDERR.
# - Changing the command line options parsing, now it uses Getopts.
# - Adding some comments on the resulting aliases file. (With RCS Information)
#   (Ricky 16/Jul/1997)
#
# Revision 1.1  1997/07/16 15:02:34  ricky
# Initial revision
#
#
#=============================================================================
# Do NOT remove these lines. They set mode in Emacs.
# perl-mode is OK for font locking.
#
#@ Local Variables: ***
#@ mode: perl ***
#@ End: ***
#=============================================================================


syntax highlighted by Code2HTML, v. 0.9.1