Welcome to Aaron Thompson's Page Monday, October 20 2014 @ 21:19 CDT  
Personal
Contact Info
Family
Resume
 
Development
CGI
probability project
 
Perl Modules
Win32::AD::User (cpan)
 
Shell
backup_file (source)
chkconfig (source)
gen-autohome (source)
group-utils (source)
mail-deny (source)
mail-logs (source | archive)
mailman-qmail (source)
qmail vacation (source)
 
Links
Beast of Burden LLC
Central Iowa LUG
CedarLUG
CedarvalleyPM
ITS-IS Home
ITS Home
UNI Home
 
 
#!/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