|
|
#!/usr/bin/perl
#
#Version 1.4m
#
# $Id: vacation.pl,v 1.4 2001/05/09 14:39:45 peters Exp $
#
# Vacation program for qmail. Based on the original version for
# sendmail by Larry Wall <lwall@jpl-devvax.jpl.nasa.gov> and Tom
# Christiansen <tchrist@convex.com>.
#
# The original is available from CPAN as
#
# CPAN/scripts/mailstuff/vacation
#
# The next version was by Peter Samuel <peter@uniq.com.au>
# http://www.gormand.com.au/peters/tools/
#
# This version modified by @ (Aaron Thompson) to work with
# existing .qmail files assuming that they are setup to
# work with procmail or to forward email to another
# account. This version will also use spamassassin to
# check and make sure SPAM is not replied to.
#
# Modified: 11/2002, 06/2003
#
# released under GPL with permission.
###########################################################################
require 5;
$check_to_and_cc = 1;
###########################################################################
#
# Process any command line arguments.
while ($ARGV[0] =~ /^-/)
{
$_ = shift;
if (/^-I/i)
{
&initialise();
exit(0);
}
if (/^-n/)
{
$no_msg_no_reply = 1;
}
if (/^-j/)
{
$check_to_and_cc = 0;
}
if (/^-s/)
{
chdir;
&get_user_details();
&show_dbm_file("$dbm_file");
exit(0);
}
if (/^-t([\d.]*)([smhdw])/)
{
&time_scales();
$timeout = $1;
$timeout *= $scale{$2} if $2;
}
}
&interactive() if (! scalar @ARGV);
###########################################################################
#
# Process incoming mail. Qmail provides a number of environment
# variables that detail the properties of the incoming mail message.
# Qmail always supplies $DTLINE. If it isn't set then we probably
# aren't being called by qmail.
exit(0) unless $ENV{'DTLINE'};
$rpline = $ENV{'RPLINE'};
$ufline = $ENV{'UFLINE'};
exit(0) if ($ufline =~ /-REQUEST\@/i);
exit(0) if ($rpline =~ /-REQUEST\@/i);
$home = $ENV{'HOME'};
$host = lc($ENV{'HOST'});
$sender = lc($ENV{'SENDER'});
$user = lc($ENV{'USER'});
$timeout = 60 * 60 * 24 * 7 unless $timeout;
chdir;
&get_program_details();
&check_ignores();
&check_headers();
&check_lastdate("$dbm_file");
&send_reply();
exit(0);
#############################################################################################
sub interactive{
chdir;
&get_user_details();
if (-f "$dot_qmail_file"){
if (&vacation_in_use($dot_qmail_file)){
print "Vacation is currently enabled for your account\n\n";
if (&yesno("Would you like to disable vacation?") ){
if(-f "$dot_qmail_file.bak"){
print "Your previous $dot_qmail_file will be restored..\n";
&restore_qmail_file($dot_qmail_file);
if(&yesno("Would you like to remove your $dot_qmail_file.bak file?")){
&delete_qmail_file("$dot_qmail_file.bak");
&show_dbm_file("$dbm_file");
&clear_dbm_file("$dbm_file");
print "\nBack to normal reception of mail.\n";
}#end if
}
else{
#was not initialy a .qmail file.
&delete_qmail_file("$dot_qmail_file");
&show_dbm_file("$dbm_file");
&clear_dbm_file("$dbm_file");
print "\nBack to normal reception of mail.\n";
}#end if
exit(0);
}
else{
print "Vacation is still active for your account\n\n";
exit(0);
}#end if
}
else{
print "You have a $dot_qmail_file in your home directory containing:\n\n";
&cat_file("$dot_qmail_file");
print "A backup will be stored in $dot_qmail_file.bak\n";
&backup_qmail_file($dot_qmail_file);
print "This program can be used to answer your mail automatically\n";
print "when you go away on vacation.\n\n";
if (-f "$message_file"){
print "You already have a message file in $home/$message_file.\n";
if (&yesno("Would you like to see it?")){
&show_file("$message_file");
}#end if
if (&yesno("Would you like to edit it?")){
&edit_file("$message_file");
}#end if
}
else{
&create_msg_file("$message_file", "$vacation_msg");
print "A default vacation message has been created in $home/$message_file.\n";
print "This message will be automatically returned to anyone sending you mail\n";
print "while you're away.\n\n";
if (&yesno("Would you like to see it?")){
&show_file("$message_file");
}#end if
if (&yesno("Would you like to edit it?")){
&edit_file("$message_file");
}#end if
}#end if
print "To enable the vacation feature a $home/$dot_qmail_file file is created.\n";
if (&yesno("Would you like to enable the vacation feature now?")){
&create_qmail_file("$dot_qmail_file", "$dot_qmail_commands");
&clear_dbm_file("$dbm_file");
print "The vacation feature has been enabled. Please remember to turn it off\n";
print "when you return. Bon voyage!\n\n";
}
else{
print "\nThe vaction feature has not been enabled.\n";
}#end if
exit(0);
}#end if
}#end if
print "This program can be used to answer your mail automatically\nwhen you go away on vacation.\n\n";
if (-f "$message_file"){
print "You already have a message file in $home/$message_file.\n";
if (&yesno("Would you like to see it?")){
&show_file("$message_file");
}#end if
if (&yesno("Would you like to edit it?")){
&edit_file("$message_file");
}#end if
}
else{
&create_msg_file("$message_file", "$vacation_msg");
print "A default vacation message has been created in $home/$message_file.\n";
print "This message will be automatically returned to anyone sending you mail\n";
print "while you're away.\n\n";
if (&yesno("Would you like to see it?")){
&show_file("$message_file");
}#end if
if (&yesno("Would you like to edit it?")){
&edit_file("$message_file");
}#end if
}#end if
print "To enable the vacation feature a $home/$dot_qmail_file file is created.\n";
if (&yesno("Would you like to enable the vacation feature now?")){
&create_qmail_file("$dot_qmail_file", "$dot_qmail_commands");
&clear_dbm_file("$dbm_file");
print "The vacation feature has been enabled. Please remember to turn it off\n";
print "when you return. Bon voyage!\n\n";
}
else{
print "\nThe vaction feature has not been enabled.\n";
}#end if
exit(0);
}#end interactive
#############################################################################################
sub initialise
{
chdir;
&get_user_details();
if (&vacation_in_use($dot_qmail_file)){
if(-f "$dot_qmail_file.bak"){
&restore_qmail_file($dot_qmail_file);
&delete_qmail_file("$dot_qmail_file.bak");
}
else{
&delete_qmail_file("$dot_qmail_file");
}#end if
&clear_dbm_file("$dbm_file");
print "\nVacation disabled.\n\n";
exit(0);
}
else{
&clear_dbm_file("$dbm_file");
&create_msg_file("$message_file", "$vacation_msg");
&backup_qmail_file($dot_qmail_file);
&create_qmail_file("$dot_qmail_file", "$dot_qmail_commands");
print "\nVacation enabled.\n\n";
exit(0);
}#end if
}
#############################################################################################
sub edit_file
{
my($file) = @_;
print "\n\n** Opening $file with $editor...\n\n";
sleep(1);
system("$editor $file");
}
#############################################################################################
sub vacation_in_use{
# written by @ returns 1 if "file" sent to the sub.
# has at least one line containing "vacation" in
# it. Otherwise it will return 0.
my($file) = @_;
my($vacation) = 0;
open(FILE, "$file");
while(<FILE>){
if (/vacation/){ $vacation++};
}#end while
close(FILE);
return ($vacation > 0);
}# end vacation_in_use
#############################################################################################
sub cat_file
{
my($file) = @_;
open(FILE, "$file");
print while(<FILE>);
close(FILE);
}
#############################################################################################
sub show_file
{
my($file) = @_;
print "\n\n** Press 'q' to quit the viewer...\n\n";
sleep(1);
system("$pager $file");
}
#############################################################################################
sub show_dbm_file
{
my($file) = @_;
local(%DBM); # Can't be my()
my($key);
require "ctime.pl";
open(PAGER, "| $pager");
print PAGER << "EOF";
Welcome back!
While you were away, vacation mail was sent to the following addresses:
EOF
dbmopen(%DBM, "$file", 0644);
foreach $key (sort keys %DBM)
{
print PAGER "$key\n";
print PAGER " ", ctime(unpack("L", $DBM{$key}));
}
dbmclose(%DBM);
close(PAGER);
}
#############################################################################################
sub clear_dbm_file
{
my($file) = @_;
local(%DBM); # Can't be my()
dbmopen(%DBM, "$file", 0644);
undef %DBM;
dbmclose(%DBM);
}
#############################################################################################
sub create_msg_file
{
my($file, $msg) = @_;
open(MSG, "> $file");
print MSG $msg;
close(MSG);
chmod(0644, $file);
}
#############################################################################################
sub create_qmail_file{
my($file, $msg) = @_;
$noBack = 0;
$currentQmailLength = 0;
open(IN, "$file.bak") or $noBack++;
if($noBack < 1){@current_qmail_file = <IN>};
close(IN);
@msg = split /\n/,$msg;
$msg = "";
$currentQmailLength = @current_qmail_file;
if ($currentQmailLength){
foreach $line (@msg){ if($line !~ /Mailbox/){ $msg .= $line . "\n"; } };
foreach $line (@current_qmail_file){ $msg .= $line };
}
else{
foreach $line (@msg){ $msg .= $line . "\n"; };
}#end if
open(MSG, "> $file");
print MSG $msg;
close(MSG);
chmod(0644, $file);
}
#############################################################################################
sub restore_qmail_file{
#restore from $file.bak to $file
use File::Copy 'cp';
my($file) = @_;
$backupFile = $file . ".bak";
cp ($backupFile, $file);
}#end restore_qmail_file
#############################################################################################
sub backup_qmail_file{
use File::Copy 'cp';
my($file) = @_;
$backupFile = $file . ".bak";
cp ($file, $backupFile);
}# end backup_qmail_file
#############################################################################################
sub delete_qmail_file
{
my($file) = @_;
unlink("$file");
}
#############################################################################################
sub yesno
{
my($msg) = @_;
my($answer);
while (1)
{
print "$msg [y/n] ";
$answer = <STDIN>;
last if $answer =~ /^[yn]/i;
}
$answer =~ /^y/i;
}
#############################################################################################
sub get_common_details
{
$message_file = ".vacation.msg";
$dbm_file = ".vacation";
$vacation_msg = << 'EOF'; # Must use single quotes
Subject: away from my mail
I will not be reading my mail for a while. Your mail regarding
"$SUBJECT"
will be read when I return.
EOF
}
#############################################################################################
sub get_program_details
{
&get_common_details();
$mailprog = "/var/qmail/bin/qmail-inject";
$aliases = ".vacation.aliases";
$noreply = ".vacation.noreply";
}
#############################################################################################
sub get_user_details
{
&get_common_details();
$user = $ENV{'USER'} || $ENV{'LOGNAME'} || getlogin || (getpwuid($>))[0];
$dot_qmail_file = ".qmail";
$editor = $ENV{'VISUAL'} || $ENV{'EDITOR'} || 'vi';
$home = (getpwnam($user))[7];
$mailbox = "$home/Mailbox";
$pager = $ENV{'PAGER'} || 'less';
$vacation = "/usr/local/bin/vacation";
$dot_qmail_commands = << "EOF"; # Must use double quotes
|preline $vacation $user
$mailbox
EOF
}
#############################################################################################
sub time_scales
{
%scale =
(
's', 1,
'm', 60,
'h', 60 * 60,
'd', 60 * 60 * 24,
'w', 60 * 60 * 24 * 7,
);
}
#############################################################################################
sub check_ignores
{
&get_aliases();
push(@ignores, @aliases);
push(@ignores,
'daemon',
'postmaster',
'mailer-daemon',
'mailer',
'root',
);
if (-f "$noreply")
{
open(NOREPLY, "$noreply");
while(<NOREPLY>)
{
chomp;
next if (/^\s*#|^$/);
push(@ignores, lc($_));
}
close(NOREPLY);
}
for (@ignores)
{
exit(0) if ($sender eq $_);
exit(0) if ($sender =~ /^$_\@/);
}
}
#############################################################################################
sub check_headers
{
my($header);
$/ = ''; # Read in paragraph mode
$header = <STDIN>;
#tmpmsg is used to check if the message is spam later...
$tmpmsg = $header;
while (<STDIN>){$tmpmsg .= $_;};
$header =~ s/\n\s+/ /g; # Join continuation lines
$* = 1; # Multi line matching within a string
#This is used to check for spam ... a copy of the message is placed int /tmp
#and it is deleted before this script finishes.
$spamassassin="/usr/bin/spamassassin";
$spamTmpFile="/tmp/vacation-$user";
if ( -e $spamassassin){
open (OUT, ">$spamTmpFile");
print OUT $tmpmsg;
close(OUT);
$spam = `cat $spamTmpFile | $spamassassin -P | grep -c X-Spam-Flag`;
chomp($spam);
unlink $spamTmpFile;
exit(0) if ($spam > 0);
}#fi
#it appears that if you add header checks (exit if exist) they
#go here :) -- @
exit(0) if ($header =~ /^Precedence:\s+(bulk|junk)/i);
exit(0) if ($header =~ /^From.*-REQUEST\@/i);
exit(0) if ($header =~ /^Mailing-List:/i);
if ($check_to_and_cc)
{
($to) = ($header =~ /To:\s+(.*)/i);
($cc) = ($header =~ /Cc:\s+(.*)/i);
$to .= ', ' . $cc if $cc;
$to = lc($to);
for (@aliases)
{
++$alias_match if $to =~ /\b$_\b/;
}
exit(0) unless $alias_match;
}
($subject) = ($header =~ /^Subject:\s+(.*)/);
$subject =~ s/\s*$//; # Remove trailing spaces
$subject = "(No subject)" unless $subject;
}
#############################################################################################
sub get_aliases
{
@aliases =
(
"$user\@$host",
);
if (-f "$aliases")
{
open(ALIASES, "$aliases");
while(<ALIASES>)
{
chomp;
next if (/^\s*#|^$/);
push(@aliases, lc($_));
}
close(ALIASES);
}
}
#############################################################################################
sub check_lastdate
{
my($file) = @_;
dbmopen(%DBM, "$file", 0644);
$now = time;
$then = unpack("L", $DBM{"$sender"});
exit(0) if (($now - $then) <= $timeout);
$DBM{$sender} = pack("L", $now);
close(%DBM);
}
sub send_reply()
{
if (-f "$message_file")
{
open(MSG, "$message_file");
undef $/; # Read in the entire file
$vacation_msg = <MSG>;
close MSG;
}
else
{
# Do not generate a reply if the user doesn't have a message file
# and -n was supplied on the command line.
exit(0) if ($no_msg_no_reply);
}
$vacation_msg =~ s/\$SUBJECT/$subject/g;
open(MAILPROG, "| $mailprog");
print MAILPROG << "EOF";
To: $sender
Precedence: junk
EOF
print MAILPROG $vacation_msg;
close(MAILPROG);
}
syntax highlighted by Code2HTML, v. 0.9.1
Return to qmail-vacation page
|