#!/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 and Tom # Christiansen . # # The original is available from CPAN as # # CPAN/scripts/mailstuff/vacation # # This version by Peter Samuel # # Minor changes by Daniel van Raay # ########################################################################### 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(); 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 = ; 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() { 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 = ; $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() { 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 = ; 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':'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); }