smeserver-vacation/root/usr/local/bin/vacation

512 lines
8.9 KiB
Perl

#!/usr/bin/perl
#
# $Id: vacation.pl,v 1.3 1999/01/04 04:28:17 psamuel 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
#
# This version by Peter Samuel <peter@uniq.com.au>
#
# Minor changes by Daniel van Raay <danielvr@caa.org.au>
#
###########################################################################
use DB_File;
require 5;
$check_to_and_cc = 1;
$dot_vacation_prefix = "";
###########################################################################
#
# 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;
}
if (/^-p*/)
{
$dot_vacation_prefix = $1;
}
}
&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")
{
print
"You have a $dot_qmail_file in your home directory containing:\n\n";
&cat_file("$dot_qmail_file");
print "\n";
print "Would you like to remove it and disable the vacation feature?";
if (&yesno())
{
&delete_qmail_file("$dot_qmail_file");
&show_dbm_file("$dbm_file");
&clear_dbm_file("$dbm_file");
print "\nBack to normal reception of mail.\n";
exit(0);
}
print << "EOF";
Mail is still under the control of your $dot_qmail_file file.
EOF
exit(0);
}
print << "EOF";
This program can be used to answer your mail automatically
when you go away on vacation.
EOF
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");
}
if (&yesno("Would you like to edit it?"))
{
&edit_file("$message_file");
}
}
else
{
&create_msg_file("$message_file", "$vacation_msg");
print << "EOF";
A default vacation message has been created in $home/$message_file.
This message will be automatically returned to anyone sending you mail
while you're away.
EOF
if (&yesno("Would you like to see it?"))
{
&show_file("$message_file");
}
if (&yesno("Would you like to edit it?"))
{
&edit_file("$message_file");
}
}
print << "EOF";
To enable the vacation feature a $home/$dot_qmail_file file is created.
EOF
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 << "EOF";
The vacation feature has been enabled. Please remember to turn it off
when you return. Bon voyage!
EOF
}
else
{
print "\nThe vaction feature has not been enabled.\n";
}
exit(0);
}
sub initialise
{
chdir;
&get_user_details();
&clear_dbm_file("$dbm_file");
&create_msg_file("$message_file", "$vacation_msg");
&create_qmail_file("$dot_qmail_file", "$dot_qmail_commands");
exit(0);
}
sub edit_file
{
my($file) = @_;
system("$editor $file");
}
sub cat_file
{
my($file) = @_;
open(FILE, "$file");
print while(<FILE>);
close(FILE);
}
sub show_file
{
my($file) = @_;
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) = @_;
open(MSG, "> $file");
print MSG $msg;
close(MSG);
chmod(0644, $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 = $dot_vacation_prefix . ".vacation.msg";
$dbm_file = $dot_vacation_prefix . ".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/datemail -t";
$aliases = $dot_vacation_prefix . ".vacation.aliases";
$noreply = $dot_vacation_prefix . ".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/Maildir/";
$pager = $ENV{'PAGER'} || 'less';
$vacation = "/usr/local/bin/vacation";
$dot_qmail_commands = << "EOF"; # Must use double quotes
| $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>;
$header =~ s/\n\s+/ /g; # Join continuation lines
exit(0) if ($header =~ /^Precedence:\s+(bulk|junk|list)/im);
exit(0) if ($header =~ /^From.*-REQUEST\@/im);
exit(0) if ($header =~ /^Mailing-List:/im);
exit(0) if ($header =~ /^X-Spam-Status:\s+Yes/im);
if ($check_to_and_cc)
{
($to) = ($header =~ /To:\s+(.*)/im);
($cc) = ($header =~ /Cc:\s+(.*)/im);
$to .= ', ' . $cc if $cc;
$to = lc($to);
for (@aliases)
{
++$alias_match if $to =~ /\b$_\b/im;
}
exit(0) unless $alias_match;
}
($subject) = ($header =~ /^Subject:\s+(.*)/im);
$subject =~ s/\s*$//m; # 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);
}
my $type = ($vacation_msg =~ m/<html/ && $vacation_msg =~ m/<\/html>/ ) ? 'html':'plain';
$vacation_msg =~ s/\$SUBJECT/$subject/g;
open(MAILPROG, "| $mailprog");
print MAILPROG << "EOF";
To: $sender
Precedence: junk
Content-Type: text/$type; charset="UTF-8"
EOF
print MAILPROG $vacation_msg;
close(MAILPROG);
}