#!/usr/local/bin/perl5 -w
#
#	majordomo2
#
#	This is the completion routine for signing up for a majordomo list.
#	Check the variables for sanity, and then send e-mail to sign up for
#	a list.
#
#       Written by Dave Regan
#       24 June 1996
#       This program is in the Public Domain.
#       Do what you want with it.
#
#	Packages which deal with the same sort of topic:
#		http://iquest.com/~fitz/www/mailserv/
#		http://hellfire.hare.net.au/cgi-bin/MailServ/majordomo
#		http://www.vv.com.au/cgi-bin/vv/mailserv/majordomo-admin
#

###
###	Configuration
###
$DefaultHost	= "peak.org";
$Mail		= "/usr/lib/sendmail";
$LogFile	= "/info/var/log/httpd/majordomo";
$HotList	= "/info/peak_info/mlists/hotlist";

###
###	Main program
###

#   CheckSanePost();
    $Vars{'bgcolor'} = "#FFFFFF";
    $Vars{'link'} = "";
    ParseFormVariables();
    ParseQueryParameters();
    HTMLhead("Account Validation");
    print "<body bgcolor=\"$Vars{'bgcolor'}\">\n";          
    $| = 1;
#   printenv();
#   printvars();
    ReadHotList();
    if (CheckData() == 0)
	{
	print "<p><h2>Please use the <b>back</b> button of your browser and correct the form.\n";
	print "Once the data is corrected, resubmit the data.</h2>\n";
	}
    elsif (CheckHotList())
	{
	print "This program has been disabled from your site.  Sorry.\n";
	LogAccess(0);
	}
    else
	{
	print "Your request has been sent.  Expect to see results in your e-mail soon.\n";
	if ($Vars{'link'} ne "")
	    {
	    print "<p>Please <a href=\"$Vars{'link'}\">continue</a>.\n";
	    }
	LogAccess(1);
	SendMail();
	}
    HTMLterm();
    exit 0;


###
###	CheckData
###
###	See if the data looks reasonable.
###
sub CheckData
    {
    local($retval);

    $retval = 1;

    # Make sure that the values exist
    $Vars{'subscribe'} = "" if (!defined($Vars{'subscribe'}));
    $Vars{'unsubscribe'} = "" if (!defined($Vars{'unsubscribe'}));
    $Vars{'help'} = "" if (!defined($Vars{'help'}));
    $Vars{'info'} = "" if (!defined($Vars{'info'}));
    $Vars{'index'} = "" if (!defined($Vars{'index'}));
    $Vars{'which'} = "" if (!defined($Vars{'which'}));
    $Vars{'who'} = "" if (!defined($Vars{'who'}));
    $Vars{'lists'} = "" if (!defined($Vars{'lists'}));
    $Vars{'get'} = "" if (!defined($Vars{'get'}));

    # We need an e-mail address to do anything
    if ($Vars{'email'} eq "")
	{
	print "You must specify a valid e-mail address to do much of anything ";
	print "with majordomo.<br>\n";
	$retval = 0;
	}
    $Vars{'email'} = "$Vars{'email'}\@$DefaultHost" if ($Vars{'email'} !~ /\@/);

#    # subscribe and unsubscribe really want a real name
#    if ( ($Vars{'subscribe'} ne "" || $Vars{'unsubscribe'} ne "") && $Vars{'name'} eq "")
#	{
#	print "Subscriptions and unsubscriptions require your name.<br>\n";
#	$retval = 0;
#	}

    # For some of the operations, a mailing list and host must be specified
    if ( ($Vars{'mlist'} eq "" || $Vars{'host'} eq "") &&
    	 ($Vars{'subscribe'} ne "" ||
	  $Vars{'unsubscribe'} ne "" ||
	  $Vars{'info'} ne "" ||
	  $Vars{'index'} ne "" ||
	  $Vars{'who'} ne "" ||
	  $Vars{'get'} ne ""))
	{
	print "The options you have selected require that you specify a mailing list name\n";
	print "as well as a host name.<br>\n";
	$retval = 0;
	}

    # Cannot both subscribe and unsubscribe
    if ($Vars{'subscribe'} ne "" && $Vars{'unsubscribe'} ne "")
	{
	print "Cannot subscribe and unsubscribe at the same time.<br>\n";
	$retval = 0;
	}

    # Cannot specify "get" unless there is a filename
    if ($Vars{'get'} ne "" && $Vars{'fname'} eq "")
	{
	print "Please specify a filename when using the \"GET\" option.<br>\n";
	$retval = 0;
	}

    return $retval;
    }


###
###	CheckHotList
###
###	See if either the REMOTE_HOST or REMOTE_ADDR match any
###	of the hot list patterns.
###
sub CheckHotList
    {
    my($pat);

    for $pat (@HotPattern)
	{
	return 1 if ($ENV{'REMOTE_HOST'} =~ /$pat/);
	return 1 if ($ENV{'REMOTE_ADDR'} =~ /$pat/);
	}
    return 0;
    }


####
####	CheckSanePost
####
####	See that this is a legitimate POST request.  Die if not.
####	This assumes that the initial Content-type message has *not*
####	been sent.
####
#sub CheckSanePost
#    {
#    ###
#    ###	Ensure that the form of the request looks valid.
#    ###
#    if ($ENV{'REQUEST_METHOD'} ne "POST")
#    	{
#	HTMLhead("Bad method");
#    	print "This script should be referenced with a METHOD of POST.\n";
#    	print "If you don't understand this, see this:\n";
#        print "<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.\n";
#	HTMLterm();
#        exit 0;
#    	}
#
#    if ($ENV{'CONTENT_TYPE'} ne "application/x-www-form-urlencoded")
#    	{
#	HTMLhead("Bad encoding");
#        print "This script can only be used to decode form results.\n";
#	HTMLterm();
#        exit 1;
#        }
#    }


###
###	HTMLhead
###
###	Put out a HTML header
###
sub HTMLhead
    {
    local($title) = @_;

    print "Content-type: text/html\n\n";
    print "<html><head><title>$title</title></head>\n";
    }


###
###	HTMLterm
###
###	Put out the end of an HTML body.
###
sub HTMLterm
    {
    print "</body></html>\n";
    }


###
###	LogAccess
###
###	Write some information out into a log file.
###
sub LogAccess
    {
    my($honor) = @_;
    my($email, $host, $key, $mlist);

    $email = $Vars{'email'};
    $host = $Vars{'host'};
    $host =~ s/[^-_.A-Za-z0-9]//g;	# Restrict the host name.
					# It may be necessary to expand this to include
					# other characters.  Do so if needed.
    $mlist = $Vars{'mlist'};

    if (!open(LOG, ">>$LogFile"))
	{
#	print STDERR "Cannot open $LogFile\n";
	return;
	}
    print LOG scalar localtime;
    if ($honor == 0)				{	$honor = " NOT";		}
    else					{	$honor = "";			}
    print LOG "\nRequest$honor honored\n";
    print LOG "From: $email\n";
    print LOG "To: majordomo\@$host\n";
    print LOG "\n";
    print LOG "subscribe $mlist $email\n"	if ($Vars{'subscribe'} ne "");
    print LOG "unsubscribe $mlist $email\n"	if ($Vars{'unsubscribe'} ne "");
    print LOG "help\n"				if ($Vars{'help'} ne "");
    print LOG "info $mlist\n"			if ($Vars{'info'} ne "");
    print LOG "index $mlist\n"			if ($Vars{'index'} ne "");
    print LOG "which $email\n"			if ($Vars{'which'} ne "");
    print LOG "who $mlist\n"			if ($Vars{'who'} ne "");
    print LOG "lists\n"				if ($Vars{'lists'} ne "");
    print LOG "get $mlist $Vars{'fname'}\n"	if ($Vars{'get'} ne "");
    print LOG "\nVariables passed into majordomo2\n";
    for $key (sort(keys %Vars))
	{
	printf LOG "  %-20.20s %s\n", $key, $Vars{$key};
	}
    print LOG "Environment variables\n";
    for $key (sort(keys %ENV))
	{
	next if ($key =~ /^SERVER_|PATH|SCRIPT_|CONTENT_|DOCUMENT_ROOT|GATEWAY_INTERFACE/);
	next if ($key =~ /^HTTP_ACCEPT|HTTP_CONNECTION|HTTP_HOST/);
	printf LOG "  %-20.20s %s\n", $key, $ENV{$key};
	}
    print LOG "\n\n";
    close LOG;
    }


###
###     ParseInfo
###
###     The work routines for parsing data.
###
sub ParseInfo
    {
    my($data) = @_;
    my($item, $name, @table, $value);

    $data =~ s/\&*\s*$//;               # Remove trailing garbage
    @table = split(/&/, $data);         # Variables split at "&"
    for $item (@table)
        {
        $item = unquote($item);
        ($name = $item) =~ s/\n//mg;
        $name =~ s/=.*//m;
        ($value = $item) =~ s/^.*?=//;
        $Vars{$name} = $value;
        }
    }


###
###     ParseQueryParameters
###
###     Read the query string and bust it up just as if it came
###     from a form.
###
sub ParseQueryParameters
    {
    ParseInfo($ENV{'QUERY_STRING'});
    }


###
###	ParseFormVariables
###
###	The variables from a CGI FORM come in on standard input.
###	Read this string, and break it up into the Vars associative
###	array.
###
sub ParseFormVariables
    {
    my($data, $item, $name, @tbl, $val);

    $data = <STDIN>;
#    print STDERR "The raw data is $data<br>\n";
    $data =~ s/query..=//g;
    $data =~ s/&*\s*$//;
    @tbl = split(/&/, $data);		# Vars separated by &
    for $item (@tbl)
    	{
    	# Process the variables.  Be careful to avoid removing needed characters.
    	chomp($item = unquote($item));
    	($name, $val) = split(/=/, $item, 2);
    	$Vars{$name} = $val;
    	}
    }


###
###	printvars
###
###	Print the contents of the Vars variable.
###
sub printvars
    {
    local($key);

    print "Variables:<br>\n";
    for $key (sort(keys(%Vars)))
    	{
    	print "$key = $Vars{$key}<br>\n";
    	}
    }


###
###     printenv
###
###     Display the environment.
###	This assumes that we can write on stdout.  This may not
###	be true if we haven't written the header line yet.
###
sub printenv
    {
    local(@env, $var);

    @env = `printenv`;
    for $var (@env)
        {
        print "$var<br>\n";
        }
    }


###
###	ReadHotList
###
###	Read in a list of Perl regular expressions to compare against the address.
###
sub ReadHotList
    {
    @HotPattern = ();
    if (open(HOT, "<$HotList"))
	{
	while (<HOT>)
	    {
	    chomp;
	    s/\s*#.*//;
	    next if (/^\s*$/);
	    s/^\s*//;
	    push(@HotPattern, $_);
	    }
	close HOT;
	}
    }


###
###	SendMail
###
###	Send mail to the majordomo server.
###
###	The mail needs to appear as if it is from the specified user.
###	This is not as needed for the subscribe/unsubscribe, but is
###	absolutely required for most commands to get information back
###	to the user.
###
###	The host is can be specified by the user.  Make sure that it doesn't
###	have any shell metacharacters.
###
sub SendMail
    {
    local($email, $host, $mlist);
    $email = $Vars{'email'};
    $host = $Vars{'host'};
    $host =~ s/[^-_.A-Za-z0-9]//g;	# Restrict the host name.
					# It may be necessary to expand this to include
					# other characters.  Do so if needed.
    $mlist = $Vars{'mlist'};

    if (open(MAIL, "|$Mail majordomo\@$host") == 0)
	{
	print "Cannot start mailer\n";
	return;
	}
    print MAIL "From: $email\n";
    print MAIL "To: majordomo\@$host\n";
    print MAIL "\n";
    print MAIL "subscribe $mlist $email\n"	if ($Vars{'subscribe'} ne "");
    print MAIL "unsubscribe $mlist $email\n"	if ($Vars{'unsubscribe'} ne "");
    print MAIL "help\n"				if ($Vars{'help'} ne "");
    print MAIL "info $mlist\n"			if ($Vars{'info'} ne "");
    print MAIL "index $mlist\n"			if ($Vars{'index'} ne "");
    print MAIL "which $email\n"			if ($Vars{'which'} ne "");
    print MAIL "who $mlist\n"			if ($Vars{'who'} ne "");
    print MAIL "lists\n"			if ($Vars{'lists'} ne "");
    print MAIL "get $mlist $Vars{'fname'}\n"	if ($Vars{'get'} ne "");
    print MAIL ".\n";
    close MAIL;
    }


###
###	unquote
###
###	Unescape a CGI form variable.
###
sub unquote
    {
    my($raw) = @_;
    my($code, @pieces, $piece);

    $raw =~ s/\+/ /mg;
    @pieces = split(/%/, $raw);
    for ($piece = 1; $piece <= $#pieces; $piece++)
    	{
    	$pieces[$piece] =~ s/^%//;
    	$code = substr($pieces[$piece], 0, 2);
    	$code = hex($code);
    	$pieces[$piece] = sprintf("%c%s", $code, substr($pieces[$piece], 2));
    	}
    return join("", @pieces);
    }


