#!/usr/bin/perl
#
#   cvs_log - This program can be run from the $CVSROOT/CVSROOT/loginfo
#               file to send e-mail.
#
#	Copyright (C) 2000,2002 Arizona Board of Regents on behalf of the
#   Planetary Image Research Laboratory, Lunar and Planetary Laboratory
#   at the University of Arizona
#
#   CVS $Id: cvs_log,v 1.4 2002/02/17 17:35:44 rbeyer Exp $
#
#
#   License & Copyright Information
#   -------------------------------
#
#   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 2 of the License, 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
#   Program Description
#   -------------------
#
#   This file is similar in intended purpose to the log.pl program
#   distributed in the contrib directory of the CVS 1.11 
#   distribution (among others).  It differs in the following ways:
#       - It does not require the -f option.
#       - It only allows a single argument to the -m option.
#       - It can handle whatever its given from options passed by
#           loginfo via the %{sVv} expansions.
#
#   In order for this Perl program to work on your system, you 
#   may have to change the path to the Perl executable on the
#   first line of this program, and you may have to change the
#   way that this program talks to your MAIL program.
#
#   By default, this program will attempt to talk directly to the
#   SMTP mail server on your machine via the Net::SMTP Perl module.
#   If you would rather have it use Mail or Sendmail directly (not
#   advised) like the older log.pl program,  then go down to the
#   ---MAIL SETUP--- area and follow the directions.
#
#   This program is intended to be called from the $CVSROOT/CVSROOT/loginfo
#   file, like so:
#
#   ALL cvs_log -m rbeyer@lpl.arizona.edu -f $CVSROOT/CVSROOT/commitlog %s 
#
#   where ALL can be replaced with DEFAULT or regular expressions, see 
#   the information on the CVS admin files.  The filenames for cvs_log
#   and the argument to the -f option should be absolute path names.  The
#   above example assumes that this program resides at $CVSROOT/CVSROOT/cvs_log

# This is an example of what the output might look like:
#
#    From: rbeyer@lpl.arizona.edu
#    Subject: CVS update: cvs_log
#
#    Date: Friday February 15, 2002 @ 14:41
#    Author: rbeyer 
#
#    Update of /usr/home/rbeyer/.cvs_repository/PIRL_CVS_utilities/cvs_log
#    In directory diligent:/usr/home/rbeyer/PIRL_CVS_utilities/cvs_log
#    
#    Modified Files:
#       cvs_log
#    Log Message:
#    Modified to use the Perl getopts module.
#
#    ==================================================================
#    File: cvs_log              Status: Up-to-date
#    
#       Working revision:    1.21   Fri Feb 15 14:46:27 2002
#       Repository revision: 1.21   
#    /usr/home/rbeyer/.cvs_repository/PIRL_CVS_utilities/cvs_log
#
#       Existing Tags:
#           No Tags Exist.
#

use Sys::Hostname;
use Net::SMTP;
use Mail::Header;
use Getopt::Std;

$usage = qq{cvs_log Usage:
    cvs_log
        -m <mailto address(es)>] | -f <logfile>
        [-u <from user>]
        [-s]
        [<expansion from format strings>]

    This program requires either a <mailto address> or a <logfile> (or both),
    to function.  Additionally, it listens to STDIN for creating the body.

    -m The <mailto address> is the address that this e-mail will get
           sent to.  If you want to send to multiple addresses, separate
           them with commas but no spaces.  (e.g.
           cvs_log -m rbeyer\@lpl.arizona.edu,rbeyer\@pirlmail.lpl.arizona.edu)
    -u If a value for <from user> is not specified, then the
           program will use your username.
    -s Prevents "cvs status -v" messages.
    -f If a value for <logfile> is specified, then this program will
           append the body of the e-mail to that <logfile> as well as
           send it.};


# Parse command line arguments
my %option = ();
unless( getopts ('m:u:f:s', \%option) ) {die "$usage\n";}

unless( $option{m} or $option{f} )
    {
    die "Either a <mailto address> or a <logfile> is required.\n$usage\n";
    }

# The first non-switch argument is the format string.  You might
#   expect it to be the elements of @ARGV, however, CVS must quote
#   them or something because all of the format string expansions
#   are in the first element of @ARGV separated by spaces.  The
#   first item is the module location relativeto $CVSROOT, the rest
#   are the format strings of the files that have been acted upon.
my @format_strings = split(/\s+/, $ARGV[0]);
my $modulepath = shift( @format_strings );

# Get someone for the e-mail to be From:
my $from_address;
if( $option{u} )
    {
    $from_address = $option{u};
    }
else
    {
    $from_address = getlogin() || ( getpwuid($<) )[0] || "nobody";
    }

# Initialize some date and time arrays
#
my @mos = (January,February,March,April,May,June,July,August,September,
            October,November,December);
my @days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
$year += 1900;


# ---------------------------------------------------------
# ------------------MAIL SETUP-----------------------------
# ---------------------------------------------------------
# If you want to use Net::SMTP (which is highly suggested),
# then do NOTHING.
#
# Otherwise, uncomment the $mailcmd line below and use
# an appropriate mail command.  The example below uses Mail.
#
# $mailcmd = "| Mail -s 'CVS update: $modulepath'";  


# Start setting up the body of the e-mail.

# Set up the body of the message that gets sent to the logfile
# or to the recipients of an e-mail.
#
my @body;

my $preamble = "\n";
$preamble .= "Date:\t$days[$wday] $mos[$mon] $mday, $year @ $hour:";
$preamble .= sprintf("%02d", $min);
$preamble .= "\nAuthor:\t$from_address\n";
push @body, $preamble;


# Print the stuff from message that comes in on STDIN to this program
#   when called from loginfo.
my @message = <STDIN>;
push @body, "\n", @message, "\n";


# After gathering this log information, do a 'cvs -Qq status -v' on 
#   each file in the arguments, if -s not set, 
unless( $option{s} )
    {
    my $cvs_element;
    foreach $cvs_element ( @format_strings )
        {
        my @cvs_stuff_array = split(/,/, $cvs_element);
        my $file = shift @cvs_stuff_array;
        if ($file eq "-")
            {
            push @body, "[input file was '-']\n";
            last;
            }
        my @cvs_cmd = ("cvs", "-nQq", "status", "-v", $file);
        open( CVSSTATUS, '-|' )
            or exec(  @cvs_cmd ) or die "Cannot exec @cvs_cmd: $!";
        my @cvs_status = <CVSSTATUS>;
        close( CVSSTATUS );

        push @body, @cvs_status;
        }
    }
else
    {
    my $cvs_element;
    foreach $cvs_element ( @format_strings )
        {
        push @body, "CVS info:\n$cvs_element\n";
        }
    }


# Append to logfile, if the user asked for it (via -f)
#
if( $option{f} )
    {
    open( OUT, ">>$option{f}" )
        or die "Could not open $option{f} for writing. $!\n";
    print OUT "****************************************\n";
    print OUT @body;
    close( OUT );
    }


# Send mail, if there's anyone to send to! (via -m)
#
if( $option{m} )
    {
    my @to_addresses = split(/,/, $option{m});

    if ($mailcmd)
        {
        $mailcmd .= " @to_addresses";
        open(MAIL, $mailcmd) || die "Could not Exec($mailcmd): $!\n";
        print MAIL @body;
        close(MAIL);
        die "Pipe to $mailcmd failed" if $?;
        }
    else
        {
        my $smtphost = hostname();
        my $helo = $smtphost;
        my $subject = "CVS commit: $modulepath";

        # Form the Header
        my $header = Mail::Header->new();
        map{ $header->add('To', $_); } @to_addresses;
        $header->combine('To',',');
        $header->add('From',$from_addrress);
        $header->add('Subject',$subject);

        ## The header and the body are formed, let's send the e-mail:
        my $smtp = Net::SMTP->new($smtphost, Hello => $helo,);
        my $ok = $smtp->mail($from_address) &&
            $smtp->to(@to_addresses) &&
            $smtp->data(join("",@{$header->header},"\n",@body));
        $smtp->quit;
        }
    }

## Exit cleanly
##
exit(0);
