#!/usr/bin/perl # # NAME # vacation - Reply to mail automatically. # # SYNOPSIS # vacation [username] # # DESCRIPTION # Vacation automatically replies to incoming mail. # # It is enabled by calling vacation without arguments. The # program creates a .vacation.msg file in your home directory, # which contains the message that is automatically sent to all # senders when vacation is enabled, and starts an editor for # you to modify the message. # # If no .forward file exists in your home directory, it is # created and will contain a line of the form: # # \username, "|/usr/local/bin/vacation username" # # This sends one copy of an incoming message to username while # another copy is piped into vacation. # # If a .forward file is present in your home directory and # it does not contain a line refering to the vacation program, # a line is appended of the form: # # "|/usr/local/bin/vacation username" # # This pipes a copy of an incoming message into the # the vacation program, in addition to the copies # to users or programs which were already specified in the # .forward file. # # If a .forward file is present in your home directory which # already contains a line refering to the vacation program, # you are asked whether you want to disable the vacation # program. If you answer yes, the line refering to the # vacation program is removed from the .forward file. If the # .forward file is empty after removing this line, it is # removed completely. # # Vacation will not respond to automatically generated mails # (like mails generated by vacation). Vacation will also not # respond to mail from either postmaster or mailer-daemon. # # FILES # ~/.forward Contains e-mail adresses or programs # to which mail must be forwarded. # # ~/.vacation.msg The reply message. # # AUTHOR # Frits Wiarda # # AUTHORS ORIGINAL VERSION # Tom Christiansen # Larry Wall # # NOTES # This script has been tested with Fedora Core 6 Linux. Note that # for other systems it can be necessary to modify line 1, containing # a reference to the perl interpreter. # # Be sure .forward files are processed on your system. Note that some # systems refuse to process .forward files that are group writable, # while the systems default umask makes files group writable. # $CMDNAME = "vacation"; $VERSION = "1.8"; ###################################################################### # # Help text. # ###################################################################### $HELP = "Reply to mail automatically.\n\nUsage: vacation [username]\n\nWithout parameters vacation prompts the user for instructions.\n"; $USAGE = "Usage: vacation [username]\n"; ###################################################################### # # Print help message when the option "-?" or "--help" is specified. # ###################################################################### if($ARGV[0] eq "-?" or $ARGV[0] eq "--help") { print "$CMDNAME $VERSION\n\n$HELP"; exit 0; } ###################################################################### # # Locate various executables. # ###################################################################### $ed = "/bin/ed"; unless (-x $ed) { $ed = "/usr/bin/ed"; } unless (-x $ed) { die "$CMDNAME: Can't locate ed\n"; } $editor = $ENV{"VISUAL"} || $ENV{"EDITOR"}; unless ($editor) { $editor = "/bin/vi"; unless (-x $editor) { $editor = "/usr/bin/vi"; } unless (-x $editor) { die "$CMDNAME: Can't locate editor\n"; } } $pager = $ENV{"PAGER"}; unless ($pager) { $pager = "/bin/more"; unless (-x $pager) { $pager = "/usr/bin/more"; } unless (-x $pager) { $pager = "/bin/pg"; } unless (-x $pager) { $pager = "/usr/bin/pg"; } unless (-x $pager) { die "$CMDNAME: Can't locate pager\n"; } } $sendmail = "/bin/sendmail"; unless (-x $sendmail) { $sendmail = "/sbin/sendmail"; } unless (-x $sendmail) { $sendmail = "/usr/sbin/sendmail"; } unless (-x $sendmail) { $sendmail = "/usr/bin/sendmail"; } unless (-x $sendmail) { die "$CMDNAME: Can't locate sendmail\n"; } $vacation = $0; unless (-x $vacation) { die "$CMDNAME: Can't locate own executable\n"; } ###################################################################### # # Determine the user. # ###################################################################### $user = $ENV{"USER"} || $ENV{"LOGNAME"} || getlogin || (getpwuid($>))[0]; ###################################################################### # # Without command line arguments we are interactive. With # an option as command line argument or more then one command # line argument we print an error message. With a user name as # the only command line argument we answer mail. # ###################################################################### if (!@ARGV) { &interactive(); } else { $_ = shift; if ( /^-/ || @ARGV ) { die "$USAGE"; } else { $user = $_; &answer; } } ###################################################################### # # Both the interactive and answer subroutines call exit directly. So # this point is unreachable. # ###################################################################### die "$CMDNAME: Panic\n"; ###################################################################### # # Answer mode. The vacation program reads mail from the standard # inut, and uses sendmail to reply to it. # ###################################################################### sub answer { # Get the users home directory from the password file. $home = (getpwnam($user))[7]; die "$CMDNAME: No home directory for user $user\n" unless $home; # Change to the users home directory. chdir $home || die "$CMDNAME: Can't chdir to $home\n"; # Set input record seperator to an empty line. $/ = ''; # Read message into header. $header = ; # Concatenate headers spread over multiple lines. $header =~ s/\n\s+/ /gm; # Do not reply to automatically generated mail. if ( $header =~ /^Auto-Submitted:/im ) { exit unless ($header =~ /^Auto-Submitted: no/im ); } exit if $header =~ /^Precedence: junk/im; exit if $header =~ /^Precedence: bulk/im; # Do not reply to mail from mailer-daemon or postmaster. exit if $header =~ /^From.*mailer-daemon/im; exit if $header =~ /^From.*postmaster/im; # Get the sender of the mail. ($replyto) = ($header =~ /^Reply-To:(.*)/im); $replyto =~ s/^\s*//; $replyto =~ s/\s*$//; ($replyto) = ($header =~ /^From:(.*)/im) if $replyto eq ""; $replyto =~ s/^\s*//; $replyto =~ s/\s*$//; die "$CMDNAME: No \"From:\" or \"Reply-To:\" header\n" if $replyto eq ""; # Get the subject of the mail. ($subject) = ($header =~ /^Subject:(.*)/im); $subject =~ s/^\s*//; $subject =~ s/\s*$//; $subject = "(No subject)" unless $subject; # Get reply text. If no .vacation.msg file is present exit, # without sending anything and without generating an error # message. (So deleting the message file effectively means # disabling the vacation program.) if (open(MSG,".vacation.msg")) { undef $/; $msg = ; close MSG; } else { exit; } # Replace $SUBJECT with real subject text. $msg =~ s/\$SUBJECT/$subject/gm; # Send reply using sendmail. open(MAIL, "|$sendmail -oi -t -f $user") || die "$CMDNAME: Can't run sendmail\n"; print MAIL <) { if ( $line =~ m|$vacation| ) { $enabled = 1; } } close FOR; } # Ask whether the vacation feature must be disabled. After that # we are ready and exit. if ($enabled) { print "The vacation feature is enabled.\n"; print "\n"; if (&yorn("Would you like to disable the vacation feature? ")) { &disable; } else { print "Ok, vacation feature NOT disabled.\n"; } exit; } # Vacation feature is disabled. Start dialog to enable it. # After that we are ready and exit. print <; $edit = 1; } last unless $edit; system $editor, ".vacation.msg"; last; } if (&yorn("Would you like to enable the vacation feature now? ")) { &enable; } else { print "Ok, vacation feature NOT enabled.\n"; } exit; } ###################################################################### # # Enable the vacation feature. If no .forward file exists one is # created. If a .forward file exists, a line enabling the vacation # program is appended to it. # ###################################################################### sub enable { if (-f ".forward") { open(FOR, ">>.forward") || die "$CMDNAME: Can't open .forward\n"; print FOR "\"|$vacation $user\"\n"; close FOR; } else { open(FOR, ">.forward") || die "$CMDNAME: Can't create .forward\n"; print FOR "\\$user, \"|$vacation $user\"\n"; close FOR; } print <.vacation.msg") || die "$CMDNAME: Can't create .vacation.msg\n"; print MSG <; last if $answer =~ /^[yn]/i; print "Please answer \"yes\" or \"no\" (\"y\" or \"n\")\n"; } print "\n"; $answer =~ /^y/i; }