#!/usr/bin/perl

# randomsig -  A program that picks a random line from one or more files for
#              for use as an email signature.
#
# Copyright (C) 2000 Suso Banderas

# 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.
#
# You may contact the author at <suso@suso.org>.


# Description:  randomsig is a program that, when run, will create a .signature file
#               in your home directory that is a named pipe.  This pipe will produce
#               a random line each time it is read from.  This is useful for generating
#               random signatures and the like.

######################
# USER DEFINED STUFF #
######################

#***********************************************************
# I like to setup variables for each of the mailboxes that
# I use in my @files array.  This makes the @files array
# easier to read and manipulate.

$homedir	= "/home/suso";
$maildir	= "$homedir/mail";
$mailbox1    	= "$maildir/saved-messages";
$mailbox2	= "$maildir/sent-mail";

#************************************************************
# Set this to whatever you use for a signature file.  If any
# files are already there they will be removed.
#

$sigfile	= ".signature";

#*****************************************************************
# The @files array is a list of filenames or variable names
# separated by comma that will be read and searched for lines
# that qualify as worthy to be used as a random signature.
#

@files		= ($mailbox1, $mailbox2);

#*****************************************************************
# The @quotes array is a list of filenames or variable names
# separated by comma that will be read in and *all* the lines
# will qualify as worthy to be used as a random signature.
# This is useful if you want to include some of your own quotes
# or sayings as possibilities for a random sig.
#

@quotes		= ("$homedir/.sigquotes");

#*******************************************************************
# The cancel file can be used to make it convient for you to
# exclude lines from qualifying as potential random signatures.
# Each line of the file can include just a normal line in full
# that must exactly match the line that you want to exlude.  Or
# You can use a perl regular expression on a line to match a line.
#

$cancelfile	= "$homedir/.sigcancel";

#*****************************************************************
# The update_time variable is a measure in seconds of how
# long the program will wait until it re-reads the files that
# it pulls the random strings from.  Note that the files won't
# be read again until the first time you read from the signature
# after this amount of time has passed. Don't set it to anything
# less than the time it takes for it to parse all the files
# initially.  Keeping the number above 60 or so should be a good
# bet.
# Some values you might try are are:
#
#    1800   = 30 minutes
#    3600   =  1 hour
#   14400   =  4 hours
#   43200   = 12 hours 
#   86400   =  1 day
#   
#  It all depends upon how often the files you are reading from
# are updated.
#

$update_time = 3600;

#                      #
# END OF CONFIGURATION #
########################




################
# MAIN PROGRAM #
################

# See the subroutines section for an explaination
# on why there are here.
$SIG{PIPE} = 'signal_handler';  # pine sends these sometimes. :-(
$SIG{TERM} = 'signal_handler';  # A normal kill command sends this.
$SIG{INT}  = 'signal_handler';  # Ctrl-C from the keyboard.

chdir;  # go home
$FIFO = $sigfile;  # Somehow having the user set a variable
		   # named FIFO didn't seem right.

$| = 1;

use Getopt::Std;

        getopts('hvl');

        if ($opt_h || $opt_v) { &usage; exit(0); }

srand;

#******************************************************************************
# This first loop is the outside loop.  It gets read when the program starts
# and creates the array that holds all the valid lines.  It will get reread
# after the first read from the pipe after $time seconds has passed.  This
# keeps your random lines array up to date with what's in the files.
#
READ: while (1) {
	$lasttime = time(); # Used later to calculate how much time has passed.
			    # since the files were last read.

	open (CANCEL, "$cancelfile");
	while(<CANCEL>) {
		$cancelline = $_;
		chomp($cancelline);
		push(@cancel_array, $cancelline);
	}
	close(CANCEL);


	%sighash = {};

	foreach $file (@files) {	
		open (FILE, $file);		# Just continue so that there
						# are no problems if the file
						# is empty.

		#**************************************************************
		# This is the loop that goes through the file $file
		# and checks lines for validity.  Unless you're just weird
		# you probably don't want every line to be considered valid,
		# Especially if your files are Mailbox format. I've found that
		# searching for lines with punctuation at the end works well.
		# In the future I may make this configurable.
		#
		LINE: while(<FILE>) {
			my $mailline = $_;
			chomp($mailline);
			if (grep(/^.{1,80}[\.\!\?]$/, $mailline)) {
				foreach $expression (@cancel_array) {
					if (grep(/^$expression$/, $mailline)) {
						next LINE;
					}
				}
				$sighash{$mailline}++;
			}
		}
	        close(FILE);
	}

	#*********************************************************
	# If you have a special file with lines that you want
	# included in the line array no matter what this loop
	# will read them in.  Just add them to the @quotes array
	# at the top of the program.
	#
	foreach $quotefile (@quotes) {
		open (QUOTES, $quotefile);
		while (<QUOTES>) {
			my $line = $_;
			chomp($line);
			$sighash{$line}++;
		}
		close(QUOTES);
	}

	# Make an sorted array of the lines that qualify.
	@line_array = sort keys(%sighash);
	$numlines = scalar(@line_array);


        #*************************************************************************
        # This is the inside loop that continuously runs, waiting for you to
        # read from the .signature file.  If a certain amount of time has passed
        # it will back once to the outter loop.
	#
	while (1) {
		unless ($opt_l) {               # We don't need to create the pipe if we are
			unless (-p $FIFO) {     # just listing out the lines or the pipe is 
				unlink $FIFO;   # already there.
				system('mknod', $FIFO, 'p') && die "can't mknod $FIFO: $!";
			}
		}

		# This random number will be used to determine which line to use
		# out of all the lines read in from all the files.
		$random = int (rand($numlines));
	
		$theline = $line_array[$random];
		chomp($theline);

		if($opt_l) {        # Just list the qualifying lines and exit.
			foreach $line (@line_array) {
				print $sighash{$line}, ":$line\n";
			}
			exit(0);
		} else {            # run the program normally in pipe mode.
			open (FIFO, "> $FIFO") or die "can't write $FIFO: $!";

			#**************************************************************
			# This is where the signature is sent out to the file
			# You can modify the section between the "print FIFO <<EOF;"
			# statement and the EOF marker if you wish to change how the 
			# signature looks.
			#
			print FIFO <<EOF;
=-------------------------------------==--------------------------------------=
$theline
=-------------------------------------==--------------------------------------=
EOF
			close (FIFO);
			sleep 1;  # Don't change this value.
		}

		#**************************************************
		#  This small piece of code will cause the
		# files to be reread every so many seconds.
		# This is so that we aren't bogging down the
		# CPU every 5 minutes or so.  It probably only
		# needs to run every hour or so.  Maybe only
		# once a day?  Change the $update_time variable
		# according to what you want.
		#
		if ((time() - $lasttime) > $update_time) {
			next READ;
		}
	}
}

exit(0);


###############
# SUBROUTINES #
###############

sub usage {
	print <<EOF;
----------------
 randomsig v1.0
----------------
 Description:  Program that will pull a random line
               out of some files and send it to a
	       named pipe for reading.
               See top of code for details.

 Usage:
        randomsig &  ||  randomsig [options]

 Options:
           -h -v  -- Show this message
           -l     -- Only print out all qualifying
		     lines and exit.
 
EOF
} 

#****************************************
# If for some reason the program
# dies we don't want to leave the named
# pipe file behind because if another
# program reads it that program might
# freeze up.  So we have our own signal
# handler.

sub signal_handler {
	$sig = shift;
	print STDERR "\nGot a SIG $sig! Cleaning up and exiting\n";
	unlink($sigfile);
	exit(1);
}
	
