#! /usr/bin/perl
=comment
/****
* GLIST - LIST MANAGER
* ============================================================
* FILENAME
*	rewrited
* PURPOSE
*	Get files in the rewrite queue and rewrite the headers
*	so it matches the configuration, then pass it on to
*	the send queue.
* AUTHORS
*	Ask Solem Hoel <ask@unixmonks.net>
* ============================================================
* This file is a part of the glist mailinglist manager.
* (c) 2001 Ask Solem Hoel <http://www.unixmonks.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* 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
*/
=cut

##############################
# Configuration
#
# ### Full path to the mail spool dir

  my $PREFIX = '@@PREFIX@@';

##############################

require 5;
use strict;
use lib '@@INCLUDE@@';
use POSIX;
use Getopt::Std;
use Glist;
use Glist::Rewrite;
use Version;
use Socket;
use vars qw($VERSION $opt_D $opt_v $opt_n $opt_s $opt_t);

sub fsetpnam {eval{$0=shift}};
my $myself = $0;
$myself =~ s%.*/%%;
fsetpnam("[glist/rewrited]");

# Need arguments.
unless(@ARGV) {
	print_usage();
};

# ##############################################
# Get command line arguments:
#
# Switch	Type		Name
# ------	-------------	----------------
# -D		boolean		Daemon
# -v		boolean		verbose
# -n		boolean		no action
# -s		boolean		single
# -t		argument	time to sleep
####
getopts('Dvnst:');


# Signal handlers. We should clean up our mess.
$SIG{INT} 	= \&cleanup_no_remove;
$SIG{TERM} 	= \&cleanup;
$SIG{HUP}	= \&cleanup;

my $LOCKFILE = $PREFIX . "/var/run/rewrited-lock";


if($opt_D) {
	# Become a daemon:
	my $pid = fork;
	exit if $pid;
	cleanup_no_remove("Couldn't fork: $!") unless defined($pid);
	POSIX::setsid() or cleanup_no_remove("Can't start a new session: $!");


	my $gl = Glist::new(
		prefix		=> $PREFIX,
		verbose		=> $opt_v,
		no_action	=> $opt_n,
		daemon		=> 1,
		name		=> 'rewrited',
	);
	cleanup($gl->error()) if $gl->error();
	my $r = $gl->Glist::Rewrite::new();

	my $logerror = $gl->dead_logdaemon;
        die("$logerror\n") if $logerror;
	lockfile() || cleanup_no_remove();
	eval{setpriority(PRI_PROCESS, $pid, PRIORITY)};

	$SIG{HUP} = sub {
		$gl->gconf($gl->get_config());
		$gl->log("Daemon restart. Configuration re-read.");
	};

	# Run in loop until killed
	while(1) {
		fsetpnam("[glist/rewrited] (work)");
		$r->handle_files() or cleanup();
		fsetpnam("[glist/rewrited] (idle)");
		sleep time_to_sleep();
	};
}
elsif($opt_s) {
	# Run once


	my $gl = Glist::new(
		prefix		=> $PREFIX,
		verbose		=> $opt_v,
		no_action	=> $opt_n,
		name		=> 'rewrited',
	);
	cleanup($gl->error()) if $gl->error();

	my $r = $gl->Glist::Rewrite::new();
        
	my $logerror = $gl->dead_logdaemon;
        die("$logerror\n") if $logerror;
	lockfile() || cleanup_no_remove();
	$r->handle_files() or cleanup();
}
else {
	print_usage();
	cleanup("Missing required arguments");
};

cleanup();

############################################
# DESTRUCTOR: cleanup
#
# DESCRIPTION:
#	Be nice, exit sweet and remove our lockfile.
#
sub cleanup {
	my $msg = shift;
	if($msg) {
		print $msg, "\n";
	}
	if(-f $LOCKFILE) {
		unlink($LOCKFILE);
	};
	exit;
};

# the same but without removing the lockfile.
sub cleanup_no_remove {
	my $msg = shift;
	if($msg) {
		print $msg, "\n";
	};
	exit;
};

# get's the time to sleep (in seconds) from the
# command line options.
sub time_to_sleep {
	my $tts; # time to sleep
	if($opt_t) {
		$tts = $opt_t;
	}
	else {
		# default is 5 seconds
		$tts = 5;
	};
	return $tts;
};

sub print_usage {
	my $version = new Version($Glist::VERSION);
	printf("rewrited (glist %s)\n", $version->extended());
	printf("Usage: %s [-v] [-n] {-D [-t time_to_sleep]|-s}\n", $myself);
	cleanup_no_remove();
};

############################################
# FUNCTION: process_running($)
# DESCRIPTION:
#	Check if a PID is still running.
#
sub process_running {
	my $pid = shift;
	unless(-d "/proc/$pid") {
		return 0;
	}
	else {
		return 1;
	};
};

############################################
# FUNCTION: lockfile()
# DESCRIPTION:
#	We don't want two of use running at the same time.
#	
sub lockfile {
	if(-l $LOCKFILE) {
		cleanup_no_remove("Oops. $LOCKFILE is a symbolic link. possible race attempt.");
		return undef;
	};

	if(-f $LOCKFILE) {
		open(LOCK, $LOCKFILE)
			|| cleanup_no_remove("Couldn't open lockfile $LOCKFILE: $!");
		my $lock_pid;
		while(<LOCK>) {
			chomp;
			$lock_pid = $_ if (/\d+/);
		};
		unless($lock_pid) {
			cleanup_no_remove("Invalid lock file. Please check and remove by hand.");
		};

		if(process_running($lock_pid)) {
			cleanup_no_remove("We're already running under PID $lock_pid");
		}
		else {
			print STDERR ("Stale lockfile found (owned by PID $lock_pid). Removing\n");
			unlink($LOCKFILE);
		};
	};

	open(LOCK, ">$LOCKFILE")
		|| cleanup_no_remove("Couldn't create lockfile $LOCKFILE: $!");
	print LOCK $$, "\n";
	close(LOCK);

	return 1;
};

__END__

=cut
=head1 NAME

rewrited - Rewrite messages in the rewrite spool

=head1 SYNOPSIS

	Run from crontab:

	00-59 * * * * /path/to/rewrited -s

	Or in daemon mode:

	/path/to/rewrited -D -t time_to_sleep

=head1 COMMAND LINE SWITCHES AND OPTIONS

	Usage: rewrited [-v] [-n] {-D [-t time_to_sleep]|-s}

=over 4

=item -D

	Run the program in daemon mode.

=item -t

	Time (in seconds) which we'll be sleeping
	between each run. (only in deamon mode)

=item -s

	Run once and exit.

=item -v

	Give verbose error and info messages in logging

=item -n

	Debug mode. Don't really move anything.

=back

=head1 DESCRIPTION

	rewrited finds new messages in $SPOOL/rewrite and moves
	them to $SPOOL/outgoing.

=head1 CONFIGURATION

	Configuration is done in the script it self.
	Thogh this is preferred to be changed in the Makefile,
	this can be done in the script as well.

	In the first lines of sendd you can configure the following variables:

=over 4

=item	PREFIX

	rewrited's prefix path.

=back

=head1	FILES

=over 4
	
=item	Message files in PREFIX/spool/rewrited

	These are standard mails sent from any mail client.


=back

=head1 REQUIREMENTS

=over 4

=item	Perl 5

	Maybe even Perl 5.6?

=item	POSIX

	Should be in the standard perl distribution.

=item	Getopt:Std

	Should be in the standard perl distribution.

=item	File::Copy

	Should be in the standard perl distribution.

=back

=head1 VERSION

	This is version 1.00

=head1 BUGS

	None known as of this date :)

=head1 AUTHOR

	Ask Solem Hoel <ask@unixmonks.net>, http://www.unixmonks.net

=cut
