# -*- Perl -*-
#
# Copyright (C) 1996 Craig Ruefenacht <ruefenac@cs.utah.edu> and the
#                    University of Utah Computer Science Department
#
# $Id: Rust_Mail.pm,v 1.4 2005/05/06 17:36:28 nmueller Exp $
#
# This is part of RUST-1.0 Beta 6
#
# Abstract: This library contains Rust module functions which
#           deal with mail sent to the Rust System
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with the source distribution of RUST, in the license
# directory. If you don't have a copy of it, write to: 
#
# Free Software Foundation, Inc.
# 675 Mass Ave
# Cambridge, MA 02139, USA.

BEGIN {
    push(@INC,"/p/condor/home/rust/modules");
}

{
package Rust_Mail;

use Rust_Configs;
use Rust_Lib;
use Rust_Exit;
use Rust_Debug;
use Rust_Action;
use Mail::Util qw(mailaddress);
use Net::Domain qw(hostname);
use Net::SMTP;

require Exporter;
@ISA = qw(Exporter);
@EXPORT =
    (
     # name                       brief description
     # --------------------------------------------------------     
     'init_mail',		# Initialize this library
     'process_mail_message',	# Create a mail object using MailTool
     'process_mailbox_file',	# Process a mailbox file
     'send_logfile',		# Mail a RUST ticket logfile to someone
 );

 
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub init_mail {
    #
    # Type: Can be called by external scripts
    #
    # Abstract: Initialize this library by adding the $global
    #           hash to this object.
    
    $globals = &get_globals;
    $headers = {};
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub process_mail_message {
    #
    # Type: Can be called by external scripts
    #
    # Abstract: Take a email message in as an array, and
    #           use MailTool to parse the mail, get stuff
    #           from the headers, determine what to do,
    #           and then go do it. 
    #
    #           This is a long function as it does a lot.
    #           It is the core of the Rust mail server.

    &ddebug("Entering Rust_Mail::process_mail_message\n");

    my ($caller, $type, $queue_index, @message) = @_;

    my ($mail, @errors, @temp, $alias_dist, $mail_message_headers,
	$mail_message_body, @proc_message);
    my ($locked_files) = new Lock;

    &debug("Processing an email message from stdin\n");

    # Create a new mail message from the info in @message.

    $mail = Mail::Internet->new(\@message);
    
    # Strip out any X-Rust-Password and X-Rust headers
 
    $headers{'x-rust-password'} = $mail->get('X-Rust-Password:');
    $headers{'x-rust'} = $mail->get('X-Rust:');
    $mail->delete('X-Rust-Password');
    $mail->delete('X-Rust:');
    chomp($headers{'x-rust-password'});
    chomp($headers{'x-rust'});

    # Remove Any X-Face headers because they get messed up in here
    $mail->delete('X-Face:');

    # The above deletions need to now show up in the @message
    # array.  Easiest way is to clear @message and then push
    # the contents of the Internet object into @message...

    # Was unable to use @message again - perl just ate up
    # the 128 MByte or ram on my RUST server.  This is because
    # of the changes to MailTools, ie passing @message in as
    # an array reference to Internet::new above.  I use
    # @proc_message instead.

    @proc_message = ();
    $mail_message_headers = $mail->header();
    $mail_message_body = $mail->body();

    foreach $each (@{$mail_message_headers}) {
	push(@proc_message, $each);
    }

    push(@proc_message, "\n");

    # Also, take an X-Rust: line from the message body as well.
    # Derek Wright 2/27/98
    
    foreach $each (@{$mail_message_body}) {
	if( $each =~ s/^X-Rust:\s*(.*)$//i ) {
	    $headers{'x-rust'} = $1;
	} else {
	    push(@proc_message, $each);
	}
    }

    # Parse mail message and continue if there was no error
    $error = &parse_message($queue_index, $mail);

    &ddebug( "headers[3]: $headers[3]\n" );

    if (!$error) {  

	# Write out the information to the debug file
        &debug("\n", "=" x 75, "\n","PARSED MAIL INFORMATION\n",
			'Subject: ',$headers{'subject'},"\n",
			'X-rust: ',$headers{'x-rust'}, "\n");
	  if ($headers{'subject_queue_index'} > -1) {
	    &debug('Queue: ', &extract_element('alias_name',$headers[3]), "\n");
	  } else {
	    &debug('Queue: None in subject',"\n");
	  }
	  if ($headers{'ticket_number'} > 0) {
	    &debug('Ticket number: ',$headers{'ticket_number'}, "\n");
	  } else {
	    &debug('Ticket number: None in subject', "\n");
	  }
	  &debug('User email in "To" header: ', $headers{'to_email'}, "\n",
		 'Usernames in "To" header: ', $headers{'to_usernames'}, "\n",
		 'User email in "CC/BCC" header: ', $headers{'cc_email'}, "\n",
		 'Usernames in "CC/BCC" header: ', $headers{'cc_usernames'}, "\n",
		 'User email in "From" header: ',$headers{'from_email'}, "\n",
		 'Username in "From" header: ',$headers{'from_username'}, "\n",
		 'Staff email in "To" header: ',$headers{'staff_to_email'}, "\n",
		 'Staff names in "To" header: ',$headers{'staff_to_usernames'}, "\n",
		 'Staff email in "CC/BCC" header: ',$headers{'staff_cc_email'}, "\n",
		 'Staff names in "CC/BCC" header: ',$headers{'staff_cc_usernames'}, "\n",
		 'RUST Queue names in "To" header: ',$headers{'rust_to'}, "\n",
		 'RUST Queue names in "CC/BCC" header: ',$headers{'rust_cc'}, "\n",
		 
		 'Admin auth flag: ',$headers{'auth_okay'}, "\n",
		 'From staff flag: ',$headers{'from_staff'}, "\n",  
		 'Comment Only: ',$headers{'comment_only'}, "\n",
		 'Command Only: ',$headers{'command_only'}, "\n",        
		 "=" x 75, "\n");
	
	# Lets first check to see if we need to do anything.  If this ticket
	# has multiple RUST queues in the "To" and "CC" headers, then only
	# one of the RUST queues should take care of it.
	# The resolve_queue function will also check from whome the mail
	# came from, and will check this against the list of usernames
	# that you have specified to NOT have their mail become a
	# ticket.  This is mail from places like MAILER-DAEMON, etc..
      
	if (!($headers{'ticket_number'})) {
	    $resolve_error = &resolve_queue($queue_index, 3, $mail);
	} else {
	    $resolve_error = &resolve_queue($queue_index, 5, $mail);
	}
	  
	if (!$resolve_error) {
	      
	    # Now use the extracted information to see if we can tell whether this
	    # is an already existing ticket.

	    # If there isn't a ticket number, then assume we are creating a new 
	    # ticket.

	    if (!($headers{'ticket_number'})) {

	        &debug("Determined that this is a new ticket\n");
		
		$new_mail_type = ($type == 1) ? 3 : 4;
		$error = &process_new_ticket($caller, $new_mail_type,
					      $queue_index, $mail, @proc_message);

		&ddebug("Leaving Rust_Mail::process_mail_message\n");
	   
		if ($error) {
		    &send_admin_mail($queue_index,$error,$mail);
		}

		return $error; 
	    }
	
	
	    # If it isn't a new ticket, then we have mail concerning an
	    # existing ticket. One of two cases exist:
	    #
	    #      - If the mail was sent from the administrators, then
	    #        add the mail to the ticket logfile, and then send
	    #        the mail to the "user" of the ticket, and CC it to
	    #        the "email" of the ticket.
	    #      - If the mail is not from administrators, then add the mail
	    #        to the ticket logfile, check to make sure that everyone
	    #        on the "email" of the ticket got a copy of the mail,
	    #        and then mail the mail to the humans on the RUST queue,
	    #        if it is configured.
	
	    &debug("The mail is concerning an existing ticket\n");

	    # Mail came from staff if $headers{'auth_okay'} is true, users otherwise
	    $existing_mail_type = $headers{'auth_okay'} ? 6 : 5;

	    # If $headers{'command_only'} is true, then do commands only.  This
	    # may have some security problems.  Possibly add pgp to it later on

	    if (($headers{'command_only'}) && ($headers{'auth_okay'})) {
		$error = &do_commands;

	    } else {
		$error = &process_existing_ticket($caller, $existing_mail_type,
						   $queue_index, $mail, @proc_message);
	    }
	    
	    &ddebug("Leaving Rust_Mail::process_mail_message\n");
	    if ($error) {
		&send_admin_mail($queue_index, $error,$mail);
	    }			 

	    return $error;
	}
	  
	# If $resolve_error has a value of 24, then RUST was unable to
	# find any queue in the "To:" header.  In this case, take the
	# mail we have and just send it to the dist of the queue.  This
	# happens when RUST queues are in the "CC:" header.
	# If $resolve_error is 16, then another RUST queue is taking care
	# of the ticket.

	if (($resolve_error) && ($resolve_error != 16)) {

	    if ($resolve_error == 24) {
		&debug("I got mail for a RUST queue, but couldn't find it in the headers\n");
	    }
	    
	    &debug("I am going to send the mail to the humans on the RUST queue\n");

	    $alias_email_addr = &extract_element('alias_dist',$queue_index);
	    $mail->header;
	    $mail->tidy_body;
	    $mail->delete('To:');
	    $mail->delete('CC:');
	    $mail->delete('BCC:');
	    $mail->delete('X-Mailer:');
	    $mail->delete('Content-Type:');
	    
	    &create_signature(12, $queue_index);
	    $mail->sign($globals->{'signature_file'});
#$mail->add_signature($globals->{'signature_file'});
	    $mail->replace('To:', $alias_email_addr, 'Reply-to:',$headers{'from_email'});
	    &smtpsend($mail, $alias_email_addr);
	    unlink($globals->{'signature_file'}) if (-f $globals->{'signature_file'});
	}

      &ddebug("Leaving Rust_Mail::process_mail_message\n");
	return $resolve_error;
    } else {
	&send_admin_mail($queue_index, $error, $mail);
	return $error;
    }
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub process_new_ticket {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Create a new ticket with the email that is
    #           passed in
    #

    &ddebug("Entering Rust_Mail::process_new_ticket\n");

    my ($caller, $new_mail_type, $queue_index, $mail, @message) = @_;

    my (@errors, $new_number, $rust_info, $create_headers, $subject, $tag);
    my ($signature_done) = 0;
    my ($locked_files) = new Lock;

    # First check to see if we want to make a ticket comming
    # from the Internet domain where the mail came from

    if (&check_restrictions($queue_index)) {
	&restricted_autoreply($mail, $queue_index);
	return 27;
    }

    # Create the new ticket
    @errors = &create_ticket_headers($caller, $locked_files, $queue_index);

    # If there was an error in creating_ticket_headers, it is most likely
    # an error in the numbers file.  This can be a bad sign.

    if ($errors[0]) {
	$locked_files->unlock_all;
	return $errors[0];
    }
    $new_number = $errors[1];
    $rust_info = $errors[2];

    &debug("The status of the NEW TICKET is ", $rust_info->get_value('status'),"\n");

    # See if the ticket is already existing.  If it is, there is something
    # wrong, because we are supposed to be creating a new ticket

    $error = &existing_ticket($queue_index, $new_number);

    if (!$error) {
	$locked_files->unlock_all;
	return $error;
    }

    # If we get here, then we have a green light for creating
    # the new ticket.  Start by adding the tag to the subject

    $tag = &extract_element('tag',$queue_index);
    $new_subject =  sprintf($tag, $new_number, $headers{'subject'});
    $headers{'email_subject'} = $new_subject;

    # We need to find out if other queues were included in
    # this mail.

    if ($headers{'rust_to'} && $headers{'rust_cc'}) {
	$all_queues = join(',',$headers{'rust_to'}, $headers{'rust_cc'});
    } elsif ($headers{'rust_to'} || $headers{'rust_cc'}) {
	$all_queues = $headers{'rust_to'} ? $headers{'rust_to'} : $headers{'rust_cc'};
    } else {
	$all_queues = "";
    }

    $headers{'send_to_queues'} = $all_queues ? $all_queues : "";

    # Now initialize some of the headers for the ticket
    $rust_info->init($new_number, $queue_index);
    $rust_info->set_value('number',$new_number);
    $rust_info->set_value('type','active');

    # Headers need to be user:-:-:owner:-:-:subject:-:-:priority
    # The reason why I'm using :-:-: for the seperator is because
    # just ":" caused problems with new email with subject like
    # "Re: This is a test".  The ":" after the "Re" was making
    # it be split apart incorrectly...  
    $create_headers = join(':-:-:', $headers{'from_email'}, 0, $headers{'subject'},
			   'normal');

    # Now do the core of the create.  The create_ticket_headers already
    # got us a new number and all,  The do_create function will mainly do
    # logging stuff, and write the ticket logfile out.

    @errors = &do_create($caller, 1, $queue_index, $create_headers, $rust_info, @message);

    # If we had an error in do_create, return the error
    if ($errors[0]) {
	$locked_files->unlock_all;
	return $errors[0];
    }

    # Set some final headers here to make sure they are set to
    # what we want.  Write out the headers as well.

    # There is a slight problem with this though.  If a user's
    # email address shows up in both the To and CC headers,
    # then it will appear twice in the "email" header field of
    # the ticket.  I'm leaving this "as is" for now.  There
    # are not that many cases of the problem.

    if ($headers{'to_email'} && $headers{'cc_email'}) {  
	$rust_info->set_value('email',join(',',$headers{'to_email'},
					   $headers{'cc_email'}));
    } elsif ($headers{'to_email'}) {
	$rust_info->set_value('email',$headers{'to_email'});
    } else {
	$rust_info->set_value('email',$headers{'cc_email'});
    }

    # Do this here because the smptsend process takes too long to
    # finish, and leaving a ticket locked for 2 minutes by one
    # process isn't good.

    $rust_info->set_value('other_queues',$headers{'send_to_queues'});
    $rust_info->set_value('user',$headers{'from_email'});
    $rust_info->write_headers;
    $locked_files->unlock_all;

    if (($headers{'x-rust'}) && ($headers{'auth_okay'}))  {
	@errors = &do_xrust($mail, $rust_info);
	if ($errors[0]) {
	    &send_admin_mail($queue_index, $errors[0], $mail);
	}
	$signature_done = $errors[1] if (!$errors[0]);
    }
    
    # If $new_ticket_type = 4, we don't want to do anything else.

    if ($new_ticket_type != 4) {

	# Now send the mail out
	&create_signature(11, $queue_index)
	    if (!($signature_done));

	$headers{'email_send_to'} = "";
	$headers{'email_cc_to'} = "";
	$headers{'email_ticket_number'} = $new_number;

	$error = &send_mail_out($caller, 7, $queue_index, $mail,
				$rust_info);
	
	if ($error) {
	    $locked_files->unlock_all;
	    return $error;
	}

	# Now generate an auto-reply to send back to the user.  If
	# an error, it isn't that big a deal.  But still let the
	# admin know about it.

	&received_autoreply($mail, $rust_info);
    }

    # Now that we're done creating a new ticket, touch a file so we
    # know a new ticket came in. -Derek Wright 3/22/99
    my ($queue_name) = Rust_Configs::extract_element('alias_name',$queue_index);
    `touch /p/condor/home/rust/active/$queue_name.new`;

    # Handle savannah integration
    if ($headers{subject} =~ /^\[bug \#(\d+)/)
    {
	my $savannah_bug = $1;
	my $ticket_number = $new_number;
	my ($rust_queue) = &extract_element('tag',$queue_index) =~ /^\[(\S+)/;

	system("/p/condor/home/rust/scripts/savannah_tag --savannah-url https://savannah.cern.ch --savannah-number $savannah_bug --rust-queue $rust_queue --rust-number $ticket_number");
    }

    &ddebug("Leaving Rust_Mail::process_new_ticket\n");
    return 0;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub process_existing_ticket {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Process mail that is related to an existing
    #           ticket
    #
    #           There are a couple of cases to deal with
    #
    #           1) The mail came from the (or a) user.  In that case,
    #              check the message and make sure that everyone who is
    #              on the email list of the ticket got the mail.
    #              If there are people missing, send them a copy of
    #              the mail.  Then, send the mail to the humans
    #              on the RUST queue if it is configured to do so.
    #
    #          2) The mail came from staff.  In this case, send
    #             the mail to the "user" of the ticket,
    #             and CC the same mail to everyone on the email
    #             list of the ticket.
    #
    #          3) The mail is being created via a mailfile, so DO
    #             not send mail out. Period.  
    #
    #          If the ticket is not of type "active", then we need
    #          to reopen it first.

    &ddebug("Entering Rust_Mail::process_existing_ticket\n");

    my ($caller, $existing_mail_type, $queue_index, $mail, @message) = @_;

    my ($ticket_email_list, $ticket_user_list, $other_queues,
	@errors, @temp, $temp, @add_user, @didnt_receive, $rust_info,
	$rust_type, $ticket_usernames, $mail_usernames, $date,
	$assigned_ticket),

    my ($locked_files) = new Lock;
    my ($signature_done) = 0;
    my ($original_queue_index) = $queue_index;

    &debug("Dealing with existing ticket number ",
		      $headers{'ticket_number'},"\n");

    @errors = &read_file($caller, $locked_files, "", 
			 $headers{'ticket_number'}, $queue_index);
    if ($errors[0]) {
	$locked_files->unlock_all;
	return $errors[0];
    }

    $rust_info = $errors[1];
    $date = $rust_info->get_value('current_date');
    $rust_type = $rust_info->get_value('type');

    # If the ticket has been moved to a different queue, we need
    # to use the queue_index of where the ticket really is.

    if ($rust_info->get_value('moved_ticket') != 0) {
	  $queue_index = $rust_info->get_value('queue_index');
	  $headers{'ticket_number'} = $rust_info->get_value('number');
	  $headers{'auth_okay'} = &check_caller($headers{'from_email'}, "",
						$queue_index);
	  $headers{'from_staff'} = &check_for_staff($headers{'from_email'},
						    $queue_index);
    }

    if (!($rust_type eq 'active')) {
	&debug("Trying to reopen ticket because it isn't in active queue\n");
	@errors = &reopen_ticket($caller, 'open', $rust_info);
	if ($errors[0]) {
	    $locked_files->unlock_all;
	    return $error;
	}
	$rust_info = $errors[1];
    }

    # Resolve all the possibilities that may exist between mail headers and
    # the ticket header variables.  Add differences we find to the ticket
    # information.

    ($in_headers_only, $in_rust_only, $queues_in_headers_only, $queues_in_rust_only) = 
	&resolve_email_addresses($queue_index, $rust_info);      

    if ($in_headers_only) {
	if ($rust_info->get_value('email'))  {
	    $new_value = join(',',$rust_info->get_value('email'), $in_headers_only);
	} else {
	    $new_value = $in_headers_only;
	}
	$rust_info->set_value('email', $new_value);
    }
	
    if ($rust_info->get_value('other_queues')) {
	if ($queues_in_headers_only) {
	    $new_value = join(',',$rust_info->get_value('other_queues'), $queues_in_headers_only);
	    $rust_info->set_value('other_queues', $new_value);
	}
    } else {
	$new_value = $queues_in_headers_only;
	$rust_info->set_value('other_queues', $new_value);
    }

    # Do the bookkeeping first

    # Handle Savannah messages
    # Don't add these ourselves because we'll get an autoreply in a
    # sec anyway
    if ($rust_info->get_value("user") eq 'noreply-savannah@cern.ch'
	&& $headers{'auth_okay'})
    {
	my ($savannah_id) = $headers{subject} =~ /bug \#(\d+)/;

	open(REPOST, "|/p/condor/home/rust/scripts/savannah_repost --savannah-url https://savannah.cern.ch --savannah-number $savannah_id");
	print REPOST @message;
	close(REPOST);
    }
    # Append the email message to the ticket log
    else
    {
	$error = &write_to_rust_log(2, $rust_info, @message);
	if ($error) {
	    $locked_files->unlock_all;
	    return $error;
	}
    }

    # Log what we just did
    $log_message = join (' ',$headers{'ticket_number'}, ": Mail added by ",
			 $headers{'from_email'}, ". $date\n");
    $error = &write_log(2, $log_message, $queue_index);
    if ($error) {
	$locked_files->unlock_all;
	return $error;
    }

    # Do this here because the smptsend process takes too long to
    # finish, and leaving a ticket locked for 2 minutes by one
    # process isn't good.

    # Set the updated and status headers in the ticket header file
    $rust_info->set_value('updated',$date);

    if( $headers{'from_staff'} ) {
	&debug("Email for existing ticket is from a staffer\n");
    } else {		  
	&debug("Email for existing ticket is from a user\n");
    }

    # If the ticket is new, and someone from the staff responds to it,
    # it should be set to status "open".
    if( ($rust_info->get_value('status') eq 'new') 
       && ($headers{'from_staff'}) 
       && ($existing_mail_type != 3) ) {
	&debug("Changing status from new to open\n");
	$rust_info->set_value('status','open');
    }
    
    # If the ticket is pending, and the ticket user responds to it, 
    # it should be set to status "open".
    if( ($rust_info->get_value('status') eq 'pending')
       && (!($headers{'from_staff'}))
       && ($existing_mail_type != 3) ) {
	&debug("Changing status from pending to open\n");
	$rust_info->set_value('status','open');
    }

    $rust_info->write_headers;
    &debug("Just wrote out the ticket headers\n");
    $locked_files->unlock_all;

    # If the ticket is unowned, and staff just sent mail, assign the
    # ticket to the staff person who sent mail.  Do this here so that
    # we can include the info in the signature that is appended to
    # the outgoing mail.  Also check to see if the "notified" header
    # variable is set.  If not, and the mail is from staff, set it.
	
    $signature_type = 11;
	
    if ((!($rust_info->get_value('owner'))) && $headers{'auth_okay'} &&
	(&extract_element('take_initial_mail',$queue_index))) {

	$rust_info->set_value('notified',$date);
        &debug("Assigning ticket to ",$headers{'from_username'},
			  ," via mail\n");
	@errors = &assign_via_mail($caller, $headers{'ticket_number'},
				   $queue_index,
				   $headers{'from_username'}, $rust_info);

	if (!$errors[0]) {
	    $signature_type = 14;
	    $headers{'signature_name'} = $headers{'from_username'};
	    $rust_info->set_value('owner',$headers{'from_username'});
	} else {
	    $headers{'signature_name'} = "";
	}

	# If there was an error assigning the ticket, it isn't that bad.
	# Continue if there is an error, but tell rust-admin about it.

	if ($errors[0]) {
	    &send_admin_mail($queue_index,$errors[0],$mail);
	}
    }

    # Take care of the X-Rust headers here.

    if (($headers{'x-rust'}) && ($headers{'auth_okay'})) {
	@errors = &do_xrust($mail, $rust_info);
	if ($errors[0]) {
	    &send_admin_mail($queue_index, $errors[0], $mail);
	} else {
	    $signature_done = $errors[1];
	}
    }
    
    # If $existing_mail_type = 6, then assume the mail came from staff.
    # In this case, we want to send the mail to the "user" of the ticket,
    # and CC the "email" of the ticket.  Also send the mail to the
    # humans on the RUST queue if it is configured.
    #
    # There are no checks to see if anyone else besides this script
    # got the email message.  This script sends it out to the "user"
    # and "email" of the ticket, regardless of who is in the headers.
    # So administraters should NOT cc the mail to people, unless they
    # want to add users to the "email" of the ticket.
	
    if ($existing_mail_type == 6) {
	&create_signature($signature_type, $queue_index)
	    if (!($signature_done));

	$headers{'email_send_to'} = $rust_info->get_value('user');
	$headers{'email_cc_to'} = $rust_info->get_value('email');
	$headers{'email_ticket_number'} = $rust_info->get_value('number');
	$headers{'email_subject'} = $rust_info->get_value('subject');
	
	$error = &send_mail_out($caller, 9, $queue_index, $mail,
				$rust_info);

    } elsif ($existing_mail_type == 5) {
	  
	# If $type = 5, then assume the mail came from a user.  In this
	# case, we need to make sure that everyone on the "email" of the
	# ticket received a copy of the ticket.  Use $in_rust_only for this.
	  
	&create_signature($signature_type, $queue_index)
	    if (!($signature_done));

	$headers{'email_send_to'} = $in_rust_only;
	$headers{'email_cc_to'} = "";
	$headers{'email_ticket_number'} = $rust_info->get_value('number');
	$headers{'email_subject'} = $rust_info->get_value('subject');

	$error = &send_mail_out($caller, 8, $queue_index, $mail,
				$rust_info);

    }

    &ddebug("Leaving Rust_Mail::process_existing_ticket\n");
    return $error;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub process_mailbox_file {
    #
    # Type: Can be called by external scripts
    #
    # Abstract: Take a file that contains several email messages
    #           and use MailTool to parse the mail, get stuff
    #           from the headers, determine what to do,
    #           and then go do it. 


    &ddebug("Entering Rust_Mail::process_mailbox_file\n");

    my ($caller, $mailbox_file, $queue_index) = @_;

    my ($old_message_header, $old_message_body, $message_number, @message);

    warn "Processing the mailbox file named $mailbox_file\n";

    # Start a loop which will deal with each email message in the file
    # seperatly
	
    $message_number = 0;
    for ( Mail::Util::read_mbox ( $mailbox_file ) ) {

	@message = ();
	$mail_message = "";
	$message_number++;

	warn "Reading in message number $message_number\n";
	$mail_message = Mail::Internet->new(\$_ );

	$old_message_header = $mail_message->header();
	$old_message_body = $mail_message->body();
	foreach $each(@{$old_message_header}) {
	    if (!($each eq "END\n")) {
		push(@message, $each);
	    }
	}

	foreach $each (@{$old_message_body}) {
	    if (!($each eq "END\n")) {
		push(@message, $each);
	    }
	}


#	foreach $each_line (@message) {
#	    print "$each_line";
#	}

	&process_mail_message($caller, 1, $queue_index, @message);

    }


    warn "Finished processing mailbox file named $mailbox_file\n";
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub check_restrictions {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Check the domain from whence the mail came and
    #           see if it is an allowable domain to be making a
    #           ticket.  This feature allows you to limit who
    #           can create a ticket via mail, based on their
    #           Internet domain.
    #
    #           This is only used on new tickets.

    &ddebug("Entering Rust_Mail::check_restrictions\n");

    my ($queue_index) = @_;

    my ($match, $from_domain, $each);

    $restrict_to = &extract_element('restrict_to', $queue_index);
    $from_domain = (split('@',$headers{'from_email'}))[1];
    $match = 0;

    &debug("The mail came from the $from_domain Internet domain.\n");

    $from_domain =~ tr/A-Z/a-z/; 

    if (($restrict_to) && ($from_domain)) {

	&debug("The mail came from the $from_domain Internet domain.\n");

	foreach $each (split(',',$restrict_to)) {
	    if ($from_domain =~ /($each)/) {
	        &debug("The mail can be made into a new ticket\n");
		$match = 1;
	    }
	}
    } else {
	$match = 1;
    }

    if (!$match) {
	&debug("The mail cannot be made into a new ticket\n");
    }

    &ddebug("Leaving Rust_Mail::check_restrictions\n");
    return !$match;
} 

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub resolve_queue {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: There will be times when there are multiple
    #           RUST queue addresses in the "To:" field of
    #           email.  This function will resolve this conflict.
    #
    #           The basic algorithm is to make the list of RUST
    #           queues also a list of priority, so, say the
    #           following queues exist, and are defined in this
    #           order in &get_globals
    #
    #           foo@world.com
    #           bar@world.com
    #           doe@world.com
    #
    #           If the "To:" line contains multiple addresses,
    #           check them in order, checking for foo first, then
    #           bar, then doe.  The *first* one we find will be
    #           the RUST queue that will make a new ticket.
    #
    #           This function also checks to make sure that
    #           we want this mail to become a ticket.  There
    #           are some users who you don't want to make a
    #           ticket if the mail is from them.  Such
    #           users include MAILER-DAEMON, etc...

    &ddebug("Entering Rust_Mail::resolve_queue\n");

    my ($queue_index, $type, $mail) = @_;

    my ($alias_name) = Rust_Configs::extract_element('alias_name', $queue_index);
    my ($count, $dont_make);
    my ($return_value) = 0;
    my ($path_to_dont_make) = $globals->{'path_to_dont_make'};
    my ($from_user) = $headers{'from_username'};
    my ($dont_make) = "$path_to_dont_make/$from_user";

    &debug("Determining which RUST queue will deal with the mail\n");

    # first check to see if we even need to make a ticket...
    $dont_make = Rust_Lib::untaint_obj($dont_make);

    if (open(DONT_MAKE, "<$dont_make")) {

	$dont_make = 0;

	while (<DONT_MAKE>) {
	    next if /^#/;
	    next if /^\s*$/;
	    chomp;
	    
	    if ($_ eq "DONT_MAKE") {
		&debug("Found the DONT_MAKE section in $dont_make\n");
		$dont_make = 1;
	    }
	    if (($_ eq "END") && ($dont_make)) {
		last;
	    }

	    if ($dont_make) {
		
		if ($_ eq $alias_name) {
		    &debug("Email from $from_user will not be made into a ticket.\n");
		    &ddebug("Leaving Rust_Mail::resolve_queue\n");
		    return 26;
		}
	    }
	}

	close(DONT_MAKE);
    }

    # We know we have to do something with the mail, so resolve any
    # quueue email addressing problems.

    # If this mail is concerning an existing ticket, then the queue_index
    # should match the index determined from the subject line tag.

    if ($type == 5) {
	if ($headers{'subject_queue_index'} == $queue_index) {
	    &debug("This process is taking care of the mail\n");
	    return 0;
	} else {
	    &debug("This process is NOT taking care of the mail\n");
	    return 16;
	}
    }
     
    # If $type != 5, then it should equal 3, so no need to check.

    # Check the "To:" header first

    $count = 0;
    foreach $each_alias (split(':',$globals->{'alias_name'})) {
	foreach $each (Mail::Address->parse($mail->get('To:'))) {
	    $each_user = $each->user();
	    $each_user = $each->address() if (!($each_user));
	    if ($each_user eq $each_alias) { 
		if ($count == $queue_index) {
		    &debug("This process is taking care of the mail\n");
		    return 0;
		} else {
		    &debug("This process is NOT taking care of the mail\n");
		    return 16;
		  }
	    }
	}
	$count++;
    }

    # Now check the "Apparently-To:" header :-(
    $count = 0;
    foreach $each_alias (split(':',$globals->{'alias_name'})) {
	foreach $each (Mail::Address->parse($mail->get('Apparently-To:'))) {
	    $each_user = $each->user();
	    $each_user = $each->address() if (!($each_user));
	    if ($each_user eq $each_alias) { 
		if ($count == $queue_index) {
		    &debug("This process is taking care of the mail\n");
		    return 0;
		} else {
		    &debug("This process is NOT taking care of the mail\n");
		    return 16;
		  }
	    }
	}
	$count++;
    }

    &ddebug("Leaving Rust_Mail::resolve_queue\n");
    return 24;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub resolve_email_addresses {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Deal with the issues of email addresses.  This
    #           function takes the following lists:
    #
    #               Email found in the "To:" header (excludes staff/queues)
    #               Email found in the "CC/BCC:" header (excludes staff/queues)
    #               List of queues found in the headers.
    #
    #            It uses these lists to generate and return the following:
    #
    #                New Email list for the ticket we are working with.
    #                    This list is the union of the old email list
    #                    with anyone who was found in the "to" or "cc/bcc"
    #                    headers, as long as they are not staff of the
    #                    queue we are working with and it isn't another
    #                    queue or queue-dist list.
    #
    #                List of email addresses on the ticket email list but
    #                wasn't in the headers of the mail
    #
    #                New list of "other_queues" of the ticket we are working with
    #
    #                List of other queues which are in "other_queues" but wasn't
    #                in the headers of the mail

  &ddebug("Entering Rust_Mail::resolve_email_addresses\n");

    my ($queue_index, $rust_info) = @_;

    my ($rust_user, $rust_email, $rust_other_queues, $all_email_list, 
	$all_rust_list, $in_headers_only, $in_rust_only, $all_queue_names,
	$queues_in_headers_only, $queues_in_rust_only);

    # First lets extract information from $rust_info

    $rust_user = $rust_info->get_value('user');
    $rust_email = $rust_info->get_value('email');
    $rust_other_queues = $rust_info->get_value('other_queues');

    # The easiest way to do this is generate two big lists.  The first
    # list will contain all email addresses in the "to:" and "cc:" headers
    # of the mail.  The second list will be the "email" and "user" of the
    # ticket.
    #
    # Then all is needed is a comparison between the two.

    if ($headers{'to_email'} && $headers{'cc_email'}) {
	$all_email_list = join(',',$headers{'to_email'},
			       $headers{'cc_email'});
    } elsif ($headers{'to_email'} || $headers{'cc_email'}) {
	$all_email_list = $headers{'to_email'} ? 
	    $headers{'to_email'} : $headers{'cc_email'};
    } else {
	$all_email_list = "";
    }

    # Add the "From:" user ONLY if it isn't a staff member.
    if (!$headers{'auth_okay'}) {
	$all_email_list = $all_email_list ? 
	    join(',',$all_email_list, $headers{'from_email'}) :
		$headers{'from_email'};
    }

    # Create a list of all email on the ticket email list (indluding the user)
    $all_rust_list = $rust_email ? 
	join(',',$rust_user, $rust_email) : $rust_user;

    # Find out who is in email headers BUT not on the ticket email list

    $in_headers_only = &find_diff($all_email_list, $all_rust_list);

    # Find out who is on the ticket email list BUT not in the email headers

    $in_rust_only = &find_diff($all_rust_list, $all_email_list);

    # Now find out which queues are in the email headers BUT not on the 
    # ticket other_queues
    
    if ($headers{'rust_to'} && $headers{'rust_cc'}) {
	$all_queue_names = join(',',$headers{'rust_to'},
				$headers{'rust_cc'});
    } elsif ($headers{'rust_to'} || $headers{'rust_cc'}) {
	$all_queue_names = $headers{'rust_to'} ?
	    $headers{'rust_to'} : $headers{'rust_cc'};
    } else {
	$all_queue_names = "";
    }

    # Find out which queues in email headers BUT not on the ticket other_queues
    $queues_in_headers_only = &find_diff($all_queue_names, $rust_other_queues);

    # Find out which queues are on the ticket other_queues BUT not in
    # email headers
    $queues_in_rust_only = &find_diff($rust_other_queues, $all_queue_names);

    &ddebug("Leaving Rust_Mail::resolve_email_addresses\n");
    return ($in_headers_only, $in_rust_only, $queues_in_headers_only, 
	    $queues_in_rust_only);
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub find_diff {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Check list1 against list2 and return all elements
    #           which are in list1 but not list2.

    &ddebug("Entering Rust_Mail::find_diff\n");

    my ($list1, $list2) = @_;

    my (@temp) = ();
    my ($each_list1, $each_list2, $found);

    foreach $each_list1 (split(',',$list1)) {
	$found = 0;
	foreach $each_list2 (split(',',$list2)) {
	    $found = 1 if ($each_list1 eq $each_list2);
	}
	push(@temp, $each_list1) if !($found);
    }

    &ddebug("Leaving Rust_Mail::find_diff\n");
    return (join(',',@temp));
}
	    
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub parse_message {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Take in a message and parse out the headers
    #           that we need.
    #
    #           $mail is a reference to a Mail::Internet object
    #
    #           $headers is a hash containing the following info:
    #
    # 
    #             * "subject" = Subject of email
    #             * "subject_queue_index" = queue index if one found in subject
    #                 It will be -1 if it finds none
    #             * "ticket_number" = Ticket number if one found in subject
    #             * "to_email" = email address(s) that appears in the "to" header
    #                 This ***EXCLUDES*** RUST queues and staff members.
    #             * "to_usernames" = usernames that appear in "to_email"
    #             * "cc_email" = email addresses present in CC and BCC headers
    #                 This ***EXCLUDES*** RUST queues and staff members
    #             * "cc_usernames" = usernames that appear in "cc_email"
    #             * "from_email" = email address from which the mail came from.
    #                 If a X-Reply-To is present, use this instead
    #             * "from_username" = username that appears in "from_email"
    #             * "staff_to_email" = All staff member's email address who appear in the "to" header
    #             * "staff_to_usernames" = usernames that appear in "staff_to_email"
    #             * "staff_cc_email" = All staff member's email address who appear in CC/BCC headers
    #             * "staff_cc_usernames" = usernames that appear in "staff_cc_email"
    #             * "rust_to" = All RUST queue names found in the "to" header
    #                     This *EXCLUDES* the queue taking care of the
    #                     email, if it is this process.
    #             * "rust_cc" = All RUST queue names found in the CC and BCC headers
    #                     This *EXCLUDES* the queue taking care of the
    #                     email, if it is this process.
    #             * "from_staff" = True if mail came from staff, false otherwise    
    #             * "auth_okay" = True if the "from_username" as auth to work in the $queue_index queue, false otherwise
    #             * "comment_only" = True if X-Rust header contains "comment", false otherwise
    #             * "command_only" = True if X-Rust header contains "commands", false otherwise
    #
    #           Other stuff will be added to this hash later on.

    &ddebug("Entering Rust_Mail::parse_message\n");

    my ($queue_index, $mail) = @_;

    my (@headers, @temp, @email, $count, $tag_queue_index, $line, $found,
	$user, @queue_email);

    &debug("Parsing the email message, extracting headers\n");

    $headers{'subject'} = $mail->get('subject:');
    chomp($headers{'subject'});


    &ddebug("Before - subject: $headers{'subject'}\n");
    &ddebug("Before - queue index: $headers{'subject_queue_index'}\n");

    # To extract number, do $string =~ /$each/i, and number is $1
    # To get subject w/out rust string, do $string =~ s:$each\s*::;
    #
    # Find out if this email is already part of a ticket, save index

    ($count, $headers{'subject_queue_index'}) = (-1, -1);
    foreach $each (split(':',$globals->{'tag_queue'})) {
	$count++;
	$headers{'subject_queue_index'} = $count
	    if ($headers{'subject'} =~ /$each/i);
    }

    # Extract the ticket number from the subject if it exists.
    # If it is successful, remove the tag from the subject as well.

    $headers{'ticket_number'} = 0;
    foreach $each (split(':',$globals->{'tag_number'})) {
	(($headers{'ticket_number'} = $1) && 
	 ($headers{'subject'} =~ s:$each\s*::))
	    if ($headers{'subject'} =~ /$each/i);
    }

    &ddebug("After - subject: $headers{'subject'}\n");
    &ddebug("After - queue index: $headers{'subject_queue_index'}\n");
	
    # Extract email and usernames of people appearing in the "to"
    # header of the mail.  Also extract any RUST queues that may
    # be present.  Keep the three categories seperate.

    $to_line = $mail->get('To:');
    $to_line = $mail->get('apparently-to:') if (!$to_line);
    chomp($to_line);
    $headers{'original_to'} = $to_line;

    # If there is no "to:" line, then something is wrong!
    return 23 if (!$to_line);

    ($headers{'staff_to_email'},$headers{'staff_to_usernames'},
     $headers{'to_email'}, $headers{'to_usernames'},
     $headers{'rust_to'}) = &parse_addresses($queue_index, $to_line);

    # Extract email and usernames of people appearing in the "CC"
    # and "BCC" headers of the mail.  Also extract any RUST queues
    # that may be present.  Keep the three categories seperate.

    $cc_line = $mail->get('cc:');
    $bcc_line = $mail->get('bcc:');
    chomp($cc_line);
    chomp($bcc_line);
    
    if (($cc_line) || ($bcc_line)) {
	if (($cc_line) && ($bcc_line)) {
	    $comb_line = join(',',$cc_line, $bcc_line);
	} else {
	    $comb_line = $cc_line ? $cc_line : $bcc_line;
	}
	$headers{'original_cc'} = $comb_line;

	($headers{'staff_cc_email'},$headers{'staff_cc_usernames'},
	 $headers{'cc_email'},$headers{'cc_usernames'},
	 $headers{'rust_cc'}) = &parse_addresses($queue_index, $comb_line);
    } else {
	$headers{'staff_cc_email'} = $headers{'staff_cc_usernames'}
	= $headers{'cc_email'} = $headers{'cc_usernames'}
	=  $headers{'rust_cc'} = "";
    }

    # Extract who the mail was sent from.  If a X-Reply-To header is
    # present, use that instead.  If for some reason there are more
    # than one email address found, just use the first one, ie $temp[0]

    @temp = ();
    $original_from = $mail->get('From:');  
    $line = $mail->get('x-reply-to:');
    $line = $mail->get('reply-to:') if !$line;
    $line = $original_from if !$line;
    chomp($line);

    if ( $line =~ /(\S*\@\S*)/ ) {
	$line = $1;
	$line =~ s/<//;
	$line =~ s/>//;
    }

    chomp($original_from);
    $headers{'original_from'} = $original_from;

    # If we couldn't find a "from:" line, something is wrong!
    return 24 if (!$line);

    @object = Mail::Address->parse($line);
    $headers{'from_email'} = $object[0]->address ? $object[0]->address : $line;
    $headers{'from_username'} = $object[0]->user ? $object[0]->user : $line;
      
    # See if this is mail from staff members.
	
    $headers{'auth_okay'} = &check_caller($headers{'from_email'}, "", $queue_index);
    $headers{'from_staff'} = &check_for_staff($headers{'from_email'}, $queue_index);
    $headers{'comment_only'} = 0;
    $headers{'command_only'} = 0;

    if ($headers{'x-rust'}) {
	foreach $each_command (split(',',$headers{'x-rust'})) {
	    $each_command =~ s/\s*//;  
	    if ($each_command eq 'comment') {
		$headers{'comment_only'} = 1;
	    }
	    if (($each_command eq 'commands') || ($each_command eq 'command')) {
		$headers{'command_only'} = 1;
	    }
	}

    }

    &ddebug("Leaving Rust_Mail::parse_message\n");
    return 0;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub parse_addresses {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: This function will go through a given mail header
    #           and return five lists:
    #
    #           user addresses found in the mail header
    #           user names found in the mail header
    #           staff addresses found in the mail header
    #           staff names found in the mail headers
    #           queue names found in the mail headers

    &ddebug("Entering Rust_Mail::parse_address\n");

    my ($queue_index, $mail_header) = @_;

    my (@temp_user_email, @temp_user_names, @temp_staff_email,
	@temp_staff_names, @temp_queue_names) =
	    ((),(),(),(),());

    my ($staff_email, $staff_names, $user_email, $user_names, $queue_names);

    foreach $each (Mail::Address->parse($mail_header)) {

	# If Mail::Address can't find user, then use address.  This
	# usually means that the "To:" line has "queue_name" instead
	# of "queue_name@machine_name"

	$each_user = $each->user();
	$each_user = $each->address() if (!$each_user);

	# Extract the staff list
	if ($each_user && (&check_caller($each_user, "", $queue_index))) {
	    push(@temp_staff_email, $each->address);
	} else {
	    $found = 0;

	    # Extract the queue list
	    foreach $queue (split(':',$globals->{'alias_name'})) {
		$found = 1 if ($each_user eq $queue);
	    }

	    # Anything left over is a user
	    if (!$found) {
		push(@temp_user_email, $each->address);

	    } else {

		# Extract queue names who got the email, excluding the
		# queue who got control.

		$count = 0;
		foreach $queue (split(':',$globals->{'alias_name'})) {
		    $current_alias_name = &extract_element('alias_name',$count);
		    if ($count != $queue_index) {
			if ($each_user eq $current_alias_name) {
			    push(@temp_queue_names, $current_alias_name);
			}
		    }
		    $count++;
		}
	    }
	}
    }

    # Now compose the username list for staff in the header
    if (@temp_staff_email) {
	foreach $each (@temp_staff_email) {
	    push(@temp_staff_names, (Mail::Address->parse($each))[0]->name);
	}
	$staff_email = join(',',@temp_staff_email);
	$staff_names = join(',',@temp_staff_names);
    } else {
	$staff_email = $staff_names = "";
    }


    # Now compose the username list for users in the header
    if (@temp_user_email) {
	foreach $each (@temp_user_email) {
	    push(@temp_user_names, (Mail::Address->parse($each))[0]->name);
	}
	$user_email = join(',',@temp_user_email);
	$user_names = join(',',@temp_user_names);
    } else {
	$user_email = $user_names = "";
    }

    if (@temp_queue_names) {
	$queue_names = join(',',@temp_queue_names);
    } else {
	$queue_names = "";
    }

    &ddebug("Leaving Rust_Mail::parse_addresses\n");
    return ($staff_email, $staff_names, $user_email, $user_names,
	    $queue_names);

}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub write_archive {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: This function appends mail to a mail archive
    #           file.  Whenever mail goes to a queue, a copy
    #           of the message gets appened to this file.  This
    #           includes all mail exept those which get returned
    #           because the queue has a restricted Internet domain.
    #

  &debug("Entering Rust_Mail::write_archive\n");

    ($mail, $queue_index) = @_;

    my ($mail_archive_file, @file_contents, $old_date);
    my ($last_date_file) = "$globals->{'path_to_mail_archives'}/.date";
    my (@months) =('Jan',
		   'Feb',
		   'Mar',
		   'Apr',
		   'May',
		   'Jun',
		   'Jul',
		   'Aug',
		   'Sep',
		   'Oct',
		   'Nov',
		   'Dec');
    
    my $archive_locks = new Lock;
    my ($archive_date) = main::ctime($^T);
    chomp($archive_date);
    
    my ($self) = shift;   
    my($file_name, $hostname, $caller, $tries) = @_;

    if ($archive_locks->add($last_date_file,$globals->{'hostname'}, 
			    'mail archiver', 10)) {
	
      &debug("The current date file is now locked.  I'm now reading it\n");
	    
	if (open(LAST_DATE,"<$last_date_file")) {
	    @file_contents = <LAST_DATE>;
	    close(LAST_DATE);

	    chomp($file_contents[0]);
	    
	    $old_date = $archive_date;
	    $archive_date =~ s:$file_contents[0]\s*::;

	  &debug("The old date is $old_date and archive is $archive_date\n");

	    if ($old_date eq $archive_date) {

	      &debug("I am now archiving the logfiles from last month\n");

		$count = 0;
		while ($count <= $#months) {
		    last if ($months[$count] eq $file_contents[0]);
		    $count++;
		}
		    
		$count = -1 if ($count == 11);
		$count++;
		    
		unlink($last_date_file) if (-f $last_date_file);
		if (open(LAST_DATE,">$last_date_file")) {

		  &debug("Writing out a new current date file\n");
		    
		    print LAST_DATE "$months[$count]\n";
		    close(LAST_DATE);
		} else {
		    
		    # do nothing yet (except return)
		  &debug("I was unable to write a new current date file\n");
		    $archive_locks->unlock_all;
		    return;
		}
		
		# Get the year from the system date
		@split_date = split(' ',$archive_date);
		$year = $split_date[$#split_date];
		$year-- if ($count == 0);
		
	      &debug("Now archinving each logfile using $year as the year string\n");

		foreach $each_queue (split(':',$globals->{'alias_name'})) {
		    $queue_archive_file = join('/',$globals->{'path_to_mail_archives'},$each_queue);
		  &debug("Now checking to see if $queue_archive_file needs archived\n");
		    if ($archive_locks->add($queue_archive_file,$globals->{'hostname'}, 'mail archiver', 10) &&
			(-f $queue_archive_file)) {
			$new_file = "$queue_archive_file.$months[$count-1].$year";
		      &debug("Locked $queue_archive_file, now compressing to $new_file\n");
			rename($queue_archive_file, $new_file);
			$compress_prog = $globals->{'compress_util'};
			`$compress_prog $new_file`;
		    }
		}
	    }
	} else {

	  &debug("Unable to open current date file...Creating one\n");
	    
	    $old_date = $archive_date;
	    $count = 0;
	    while ($count <= $#months) {

		$archive_date =~ s:$months[$count]\s*::;
		if (!($old_date eq $archive_date)) {
		    if (open(LAST_DATE,">$last_date_file")) {
		      &debug("Writing out a new current date file\n");
			print LAST_DATE "$months[$count]\n";
			close(LAST_DATE);
			last;
		    } else {
			# do nothing yet (except return)
		      &debug("Was unable to create a current date file\n");
			$archive_locks->unlock_all;
			return;
		    }
		}
		$count++;
	    }
	}
	
	$archive_locks->unlock_all;
    }
	
    # Now we can get down to business.

  &debug("Now getting down to business...archiving mail message\n");

    $queue_name = &extract_element("alias_name",$queue_index);
    $mail_archive_file = join('/',$globals->{'path_to_mail_archives'},$queue_name);
  &debug("The queue is $queue_name and archive is $mail_archive_file\n");

  &debug("Trying to lock $mail_archive_file\n");
    
    if ($archive_locks->add($mail_archive_file,$globals->{'hostname'}, 'mail archiver', 10)) {
	if (-f $mail_archive_file) {
	  &debug("Opening an existing archive logfile\n");
	   open(ARCHIVE, ">>$mail_archive_file") || ($archive_locks->unlock_all && return);
	} else {
	  &debug("Opening a new archive logfile\n");
	    open(ARCHIVE, ">$mail_archive_file") || ($archive_locks->unlock_all && return);
	}

      &debug("Archive file was successfully opened\n");
	
	$mail_message_headers = $mail->header();
	$mail_message_body = $mail->body();
	
      &debug("Writing out the mail headers\n");
	foreach $each (@{$mail_message_headers}) {
	    print ARCHIVE $each;
	}

	print ARCHIVE "\n";

      &debug("Writing out the mail body\n");
	foreach $each (@{$mail_message_body}) {
	    print ARCHIVE $each;
	}
	
	print ARCHIVE "\n\n";
	close(ARCHIVE);
    }
    
    $archive_locks->unlock_all;

    &ddebug("Leaving Rust_Mail::write_archive\n");
    return;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub send_mail_out {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Send a email message out to people
    #
    #           Before sending the mail, make sure the
    #           X-Reply-To header is set so that we can somewhat
    #           control where replies to this mail go.

    &ddebug("Entering Rust_Mail::send_mail_out\n");

    my ($caller, $mail_type, $queue_index, $mail, $rust_info) = @_;

    my ($from_line, $alias_dist, $temp, $new_subject, $alias_title,
	$alias_email_addr, $all_email_addr, $each_user, $each_email,
	$each_queue, $found, $date, @message, $orig_to, $orig_from,
	$orig_cc, $orig_subject);
    my ($tag) = &extract_element('tag',$queue_index);
    my ($alias_name) = &extract_element('alias_name',$queue_index);
    my ($rfc_date) = &rfc_822_date;
    my ($date) = main::ctime($^T);
    chomp($date);

    # We can get away with this here because this isn't supposed to be
    # run setgid by anyone.

    $ENV{'PATH'} = "/bin";

    &debug("Preparing to send mail out\n");

    # Construct the "From:" line.  It will have the originator's username, but 
    # will have the RUST queue mail address.  This is so that all replies
    # are *hopefully* sent to the rustmail server.

    $mail_from = $mail->get('From:');    
    $from_phrase = (Mail::Address->parse($mail_from))[0]->phrase;
    if (!$from_phrase) {
	$from_phrase = (Mail::Address->parse($mail_from))[0]->name;
    }
    if (!$from_phrase) {
	$from_phrase = $headers{'from_username'};
    }
    if (!$from_phrase) {
	$from_phrase = "RUST Mail System";
    }

    $alias_email_addr = &extract_element('alias_email_addr',$queue_index);
    $alias_title = &extract_element('alias_title', $queue_index);
    
    if (&extract_element('send_from_username',$queue_index)) {
	$from_line = join('', "$from_phrase", " \<", $alias_email_addr, "\>");
    } else {
	$from_line = join('', "\"$alias_title\" ", "\<", $alias_email_addr, "\>");
    }

    $alias_dist = &extract_element('alias_dist',$queue_index);

    # Construct the subject line, which will be "$tag $subject"
    # If $mail_type = 7, it is a new ticket.  Otherwise, tack on a
    # "Re:" at the front of the subject.  If the mail made a
    # new ticket, the tag is already in the subject ($mail_type == 7)

    if ($mail_type == 10) {
	$new_subject = join(' ','RUST ERROR:',$headers{'email_subject'});
    } elsif ($mail_type != 7) {
	$new_subject = join(' ','Re:',sprintf($tag, 
					      $headers{'email_ticket_number'},
					      $headers{'email_subject'}));
    } else {
	$new_subject = $headers{'email_subject'};
    }

    @message = ();

    push(@message, "From $alias_email_addr $rfc_date\n",
	 "From: $from_line\n",
	 "Sender: $from_line\n",
	 "Reply-To: $alias_email_addr\n",
	 "Date: $rfc_date\n",
	 "To: $orig_to\n",
	 "Subject: $new_subject\n\n");
	 
    push(@message, "\n");

    $old_message_body = $mail->body();
    foreach $each (@{$old_message_body}) {
	push(@message, $each);
    }

    push(@message, "\n\n",
	 "========================================\n",
	 "MESSAGE INFORMATION\n",
	 "========================================\n",
	 "* From: ",$headers{'original_from'},"\n");

    if ($headers{'comment_only'}) {
	push(@message,"* This message DID NOT get sent to any user\n");

    } elsif ($rust_info) {
	$ticket_user = $rust_info->get_value('user');
	$ticket_email = $rust_info->get_value('email');
	$ticket_queues = $rust_info->get_value('other_queues');

	push(@message, "* Ticket Email List: $ticket_user, $ticket_email\n");
	
	if ($ticket_queues) {
	    push(@message, "* Ticket Other Queues: $ticket_queues\n");
	} 
    }
    push(@message, "\n");
    
    $outgoing_mail = Mail::Internet->new(\@message);

    # Now append a "signature" file.  There will be future expansion of
    # this, but for now, it just uses a constant file

    $outgoing_mail->sign($globals->{'signature_file'});
#$outgoing_mail->add_signature($globals->{'signature_file'});

    # If there was an error in the RUST System, send the email message
    # to the admin people

    if ($mail_type == 10) {
	$admin_mail = $globals->{'admin'};
	$outgoing_mail->replace('Reply-to:',$alias_email_addr, 'To:', $admin_mail);
	&debug("Sending mail to $admin_mail\n");
	&smtpsend($outgoing_mail, $alias_email_addr);
	unlink($globals->{'signature_file'}) if (-f $globals->{'signature_file'});
	return 0
    }

    # No matter what to do, the mail needs to get sent to the humans on the
    # queue, if it is configured that it is wanted.  Use the sendmail
    # program to do this so that the alias-dist email address can remain
    # hidden.  You can't hide it if you use Net::smtpsend.

    if (&extract_element('send_to_humans',$queue_index)) {
        &debug("Sending mail to $alias_dist\n");
	$outgoing_mail->replace('Reply-to:',$alias_email_addr, 
				'To:',$alias_email_addr);
	&send_via_sendmail($outgoing_mail, $alias_dist, $alias_email_addr);
    }

    # No matter what to do, the mail needs to go to any other RUST
    # queue which appeared in the headers of the original mail

    @other_queues_email = ();  
    if ($rust_info->get_value('other_queues')) {
	foreach $each (split(',',$rust_info->get_value('other_queues'))) {
	    $count = 0;
	    foreach $each_queue (split(':',$globals->{'alias_name'})) {
		push(@other_queues_email, &extract_element('alias_dist',$count))
		    if ($each_queue eq $each);
		$count++;
	    }
	}
    }

    if (@other_queues_email) {
        &debug("Sending mail to other RUST queues: ",
			  join(',',@other_queues_email), "\n");
	  
	  $mail_subject = $outgoing_mail->get('Subject:');
	  chomp($mail_subject);
	  $staff_subject = join(' ','QUEUE',$alias_name,':',
				$mail_subject);
	  $outgoing_mail->replace('Subject:',$staff_subject);
	  $outgoing_mail->replace('To:', $alias_email_addr);

	  foreach $each_queue_email (@other_queues_email) {
	      &send_via_sendmail($outgoing_mail, $each_queue_email, $alias_email_addr);
	  }
	  $outgoing_mail->replace('Subject:',$mail_subject);
    }
    
    # If $mail_type = 9, then send the mail to the "user" of the ticket
    # and CC it to the "email" of the ticket.  

    if (($mail_type == 9) && (!($headers{'comment_only'}))) {

	if ($headers{'email_send_to'} && $headers{'email_cc_to'}) {
	    &debug("Sending mail to ",
		   $headers{'email_send_to'}," and ",
		   $headers{'email_cc_to'},"\n");
	    $outgoing_mail->replace('To:',$headers{'email_send_to'});
	    $outgoing_mail->replace('CC:',$headers{'email_cc_to'});
	    &smtpsend($outgoing_mail, $alias_email_addr);
	} elsif ($headers{'email_send_to'}) {
	    &debug("Sending mail to ",
		   $headers{'email_send_to'},"\n");
	    $outgoing_mail->replace('To:',$headers{'email_send_to'});
	    &smtpsend($outgoing_mail, $alias_email_addr);
	}
    }

    # If $mail_type = 8, then send the mail to all those who are on the "email"
    # of the ticket, but didn't get the email message
    # Also, 

    if ($mail_type == 8) {
	if ($headers{'email_send_to'}) {
	    &debug("Sending mail to ",
		   $headers{'email_send_to'},"\n");
	    $outgoing_mail->replace('To:', $headers{'email_send_to'});
	    &smtpsend($outgoing_mail, $alias_email_addr);
	}

	my $owner;
	if( $owner = $rust_info->get_value('owner') ) {
	    &debug("Sending mail to ticket owner: $owner\n");
	    $outgoing_mail->replace('Reply-to:',$alias_email_addr, 
				    'To:',$owner);
	    &send_via_sendmail($outgoing_mail, $owner, $alias_email_addr);
	}
    }

    # Clean up after ourselves by removing the signature file

    unlink($globals->{'signature_file'}) if (-f $globals->{'signature_file'});

    &ddebug("Leaving Rust_Mail::send_out_message\n");
    return 0;
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub create_signature {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Create a signature file to be appended to the
    #           outgoing mail.  This will eventually be used to
    #           send status out to the user when a reply is sent
    #           from the administrators to the user.

    &ddebug("Entering Rust_Mail::create_signature\n");

    my ($type, $queue_index) = @_;

    my ($signature_file) = $globals->{'signature_file'};
    my ($alias_email) = &extract_element('alias_email_addr',$queue_index);
    my ($real_name) = $from_username;

    if ($type == 14) {  
	if (&check_caller($headers{'signature_name'}, "", $queue_index)) {
	    $real_name = &get_real_name($queue_index, $headers{'signature_name'});
	    $real_name = $headers{'signature_name'} if ($real_name eq 'unknown'); 
	}
    }

    &debug("Creating a signature to use for outgoing mail\n");

    
    $signature_file = Rust_Lib::untaint_obj($signature_file);
    if (open(SIGNATURE, ">$signature_file")) {
	print SIGNATURE "=" x 70, "\n";
	print SIGNATURE "This mail was sent from the RUST Mail System\n";

	if ($type == 11) {
	    print SIGNATURE "Please direct all replies to ",$alias_email, "\n";
	    print SIGNATURE "Please include the current subject line in your reply.\n";
	} elsif ($type == 12) {
	    print SIGNATURE "This message is not a RUST ticket.\n";
	} elsif ($type == 13) {
	    print SIGNATURE ("This message could not be processed by the ",$alias_email,"\n",
			     "RUST queue.  The message is being sent to the RUST admin so\n",
			     "that it does not get lost\n");
	} elsif ($type == 14) {
	    print SIGNATURE "This ticket is now being taken care of by ",$real_name, "\n";
	    print SIGNATURE "Please direct all replies to ",$alias_email, "\n";
	    print SIGNATURE "Please include the current subject line in your reply.\n";
	} elsif ($type == 15) {
	    print SIGNATURE "This ticket has been resolved.\n";
	}

	print SIGNATURE "=" x 70, "\n";
	close(SIGNATURE);
    }

    &ddebug("Leaving Rust_Mail::create_signature\n");
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub do_xrust {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Do the things specified in the X-Rust mail
    #           header.
    #
    #           X-Rust headers can include any of these:
    #
    #               resolve
    #               assign <user>
    #               set <header> <value>
    #               set priority <value>
    #               
    #           This function assumes that there are x-rust
    #           headers (ie it is checked BEFORE this function)

    &ddebug("Entering Rust_Mail::do_xrust\n");

    my ($mail, $rust_info) = @_;

    my (@errors, $auth_okay);
    my ($signature_done) = 0;
    my ($queue_index) = $rust_info->get_value('queue_index');
    my ($ticket_number) = $rust_info->get_value('number');
    my ($alias_name) = &extract_element('alias_name', $queue_index);
    my ($path_to_auth) = $globals->{'path_to_auth'};
    my (@xrust_commands) = split(',',$headers{'x-rust'});
    my ($from_user) = $headers{'from_username'};
    my (@auth_info, $count, $no_password);  
    my ($password_file) = "$path_to_auth/$from_user";
    
    &debug("The x-rust header is ",$headers{'x-rust'},"\n");

    # If we only have a "comment" X-Rust header, then
    # no password is needed, so auth is okay

    if (($#xrust_commands == 0) && ($headers{'comment_only'})) {
        $auth_okay = 1;

    } else {

	$auth_okay = 0;

	# Check password for specified user.

	&debug("Reading $password_file to extract password\n");
	$password_file = &untaint_obj($password_file);

	if (open(AUTH, "<$password_file")) {
	    
	    while (<AUTH>) {
		next if /^#/;
		next if /^\s*$/;
		chomp;

		if ($_ =~ /(PASSWORD)/) {
		    $user_password = (split('=',$_))[1];
		    if ($headers{'x-rust-password'} eq $user_password) {
			&debug("X-Rust password checked out\n");
			$auth_okay = 1;  
			last;
		    }
		}
	    }

	    close(AUTH);
	}
    }

    if (!$auth_okay) {
        &debug("Password check failed for ",$headers{'from_username'}," username.",
			  "Please check $password_file\n");
	return (31);
    }

    # $headers{'auth_okay'} was checked before coming into do_xrust
    # and $auth_okay was just checked, so no more checks needed.

    foreach $each (@xrust_commands) {

	&debug("Performing X-Rust command $each\n");
	  @command_contents = split(' ',$each);

	# Resolve the ticket
	if ($command_contents[0] eq 'resolve') {
	    @errors = Rust_Action::do_action($headers{'from_username'}, 0, 
					     (split(',',$ticket_number))[0],
					     'status', "", 'resolved', 
					     $queue_index);
	    &create_signature(15, $queue_index);
	    $signature_done = 1;
	}
	
	# Assign the ticket
	if ($command_contents[0] eq 'assign') {
	    @errors = &assign_via_mail($headers{'from_username'}, (split(',',$ticket_number))[0],
				 $command_contents[1], $queue_index,);
	    $headers{'signature_name'} = $command_contents[1];
	    &create_signature(14, $queue_index);
	    $signature_done = 1;
	}
	
	# Setting a header to a value or change the priority of the ticket
	if (($command_contents[0] eq 'set') || 
	    ($command_contents[0] eq 'priority')) {
	    @errors = &do_action($headers{'from_username'}, 0,
				 (split(',',$ticket_number))[0],
				 $command_contents[1], "",
				 $command_contents[2], $queue_index);
	}
	
    }

    &ddebug("Leaving Rust_Mail::do_xrust\n");

    return($errors[0], $signature_done);
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub do_commands {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Do the things specified in the X-Rust mail
    #           header, treating them as actions.
    #
    #           The rest of the email message is ignored
    #           completely.
    #
    #           X-Rust headers can include any of these:
    #
    #               resolve
    #               assign <user>
    #               set <header> <value>
    #               set priority <value>
    #               
    #           This function assumes that there are x-rust
    #           headers (ie it is checked BEFORE this function)

    &ddebug("Entering Rust_Mail::do_commands\n");

    my (@errors, $auth_okay);
    my ($queue_index) = $headers{'subject_queue_index'};
    my ($ticket_number) = $headers{'ticket_number'};
    my ($alias_name) = &extract_element('alias_name', $queue_index);
    my ($path_to_auth) = $globals->{'path_to_auth'};
    my ($from_user) = $headers{'from_username'};
    my ($password_file) = "$path_to_auth/$from_user";
    my (@xrust_commands) = split(',',$headers{'x-rust'});
    my (@auth_info, $count, $no_password);  
    
    &debug("The x-rust header is ",$headers{'x-rust'},"\n");

    # Check password for specified user.

    $auth_okay = 0;
    
    &debug("Reading $password_file to extract password\n");
    $auth_file = &untaint_obj($password_file);

    if (open(AUTH, "<$password_file")) {
	    
	while (<AUTH>) {
	    next if /^#/;
	    next if /^\s*$/;
	    chomp;
	    
	    if ($_ =~ /(PASSWORD)/) {
		$user_password = (split('=',$_))[1];
		if ($headers{'x-rust-password'} eq $user_password) {
		    &debug("X-Rust password checked out\n");
		    $auth_okay = 1;  
		    last;
		}
	    }
	}

	close(AUTH);
    }

    if (!$auth_okay) {
        &debug("Password check failed for ",$headers{'from_username'}," username.",
			  "Please check $password_file\n");
	return (31);
    }

    # $headers{'auth_okay'} was checked before coming into do_commands
    # and $auth_okay was just checked, so no more checks needed.

    foreach $each (@xrust_commands) {

	&debug("Performing X-Rust command $each\n");
	@command_contents = split(' ',$each);

	# Resolve the ticket
	if ($command_contents[0] eq 'resolve') {
	    @errors = &do_action($headers{'from_username'}, 0, 
				 (split(',',$ticket_number))[0],
				 'status', "", 'resolved', 
				 $queue_index);
	}

	# Assign the ticket
	if ($command_contents[0] eq 'assign') {
	    @errors = &assign_via_mail($headers{'from_username'}, (split(',',$ticket_number))[0],
				 $command_contents[1], $queue_index);
	}
	
	# Setting a header to a value or change the priority of the ticket
	if (($command_contents[0] eq 'set') || 
	    ($command_contents[0] eq 'priority')) {
	    @errors = &do_action($headers{'from_username'}, 0,
				 (split(',',$ticket_number))[0],
				 $command_contents[1], "",
				 $command_contents[2], $queue_index);
	}
	
    }

    &ddebug("Leaving Rust_Mail::do_command\n");

    return($errors[0]);

}
    
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub received_autoreply {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Generate an autoreply message and send it to
    #           the user of the new ticket.  Do this *only*
    #           if the user isn't someone on the RUST queue

    &ddebug("Entering Rust_Mail::received_autoreply\n");

    my ($mail, $rust_info) = @_;
    
    my ($queue_index) = $rust_info->get_value('queue_index');
    my ($user)= $rust_info->get_value('user');
    my ($subject) = $rust_info->get_value('subject');
    my ($substring) = $rust_info->get_value('substring');
    my ($alias_title) = &extract_element('alias_title',$queue_index);
    my ($alias_name) = &extract_element('alias_name',$queue_index);
    my ($okay_to_send) = (!&check_for_staff($user, $queue_index));
    my ($rfc_date) = &rfc_822_date;
    my ($date) = main::ctime($^T);
    chomp($date);

    if (!$okay_to_send) {
	foreach $each (Mail::Address->parse($user)) {
	    $okay_to_send = 1 if (!&check_for_staff($each->address, $queue_index));
	}
    }

    $okay_to_send = 0 if (!&extract_element('do_initial_autoreply',$queue_index));

    if ($okay_to_send) {
	
	&debug("Preparing to send an auto-generated message to $user\n");
	&debug("Creating the message and sending it\n");
	@message = ();

	$alias_email = &extract_element('alias_email_addr',$queue_index);
	$subject = 'no subject' if (!$subject);
	$new_subject = join('',$substring, $subject);
 	push(@message, 
	     ("From $alias_email $rfc_date\n",
	      "From: $alias_email\n",
	      "Sender: $alias_email\n",
	      "Reply-To: $alias_email\n",
	      "Date: $rfc_date\n",
	      "To: $user\n",
	      "Subject: $new_subject\n\n",
	      "Greetings.  \(This is an automated response.  ",
	      "There is no need to reply.\)\n\n",
	      "Your message regarding: \n",
	      "  \"$subject\"\n",
	      "has been received by the $alias_title.\n\n",
	      "In order to help us track the progress of your request, ",
	      "we ask that you\n",
	      "include the string:\n",
	      "  \"$new_subject\"\n", 
	      "in the subject line of any further mail about this ",	      
	      "particular request.\n\n",
	      "You can do this by simply replying to this email.\n\n" ));
	if( $alias_name eq "condor-admin" ) {  
	    push(@message, 
		 ("While you are waiting for a reply, please look at the ",
		  "Condor Manual:\n",
		  "  http://www.cs.wisc.edu/condor/manual/\n",
		  "for full documentation of Condor.  Your problem ",
		  "may have already\nbeen solved or explained.\n\n",
		  "Support for Condor through the condor-admin list is ",
		  "free of charge.\n",
		  "We will make a best effort to respond in a timely fashion, ",
		  "but please\n",
		  "keep in mind that our resources are limited.\n\n",
		  "We offer a higher level of support for a fee.  If you are ",
		  "interested in\n",
		  "this, please send a message to condor-support\@cs.wisc.edu.\n\n",
		  "If possible, we encourage you to try to experiment a little ",
		  "to see if\n",
		  "you can solve the problem yourself.\n\n" ));
	}
	push(@message, 
	     ("                        Thank You,\n",
	      "                        - ", $alias_title ,"\n"));

        if (&extract_element('include_orig', $queue_index)) {
	    push(@message,"\nThe original message body follows.\n",
		 "===================================================================\n\n");
	    $old_message_body = $mail->body();
	    foreach $each (@{$old_message_body}) {
		push(@message, $each);
	    }
	}

	$autoreply_mail = Mail::Internet->new(\@message);
	&smtpsend($autoreply_mail, $alias_email);
    } else {
	&debug("Did not send autogenerated reply out\n");
    }
    
    &ddebug("Leaving Rust_Mail::received_autoreply\n");
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub restricted_autoreply {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Return mail back to the sender, because they
    #           are sending it from someplace that shouldn't
    #           send mail to the specified RUST queue.  This is
    #           determined based on Internet domain

    &ddebug("Entering Rust_Mail::restricted_autoreply\n");

    my ($mail, $queue_index) = @_;

    my ($old_message_body, $each, $alias_email, $alias_titie, $subject,
	@message, $autoreply_mail, $orig_subject, $internet_domain);

    &debug("Preparing to send restricted autogenerated message to", 
		      $headers{'from_email'},"\n");
    &debug("Processed email message cannot be made into a ticket\n");
    @message = ();

    $internet_domain = (split('@',$headers{'from_email'}))[1];
    $alias_email = &extract_element('alias_email_addr',$queue_index);
    $alias_title = &extract_element('alias_title',$queue_index);
    $rust_admin = $globals->{'admin'};
    $orig_subject = $headers{'subject'};
    $subject = join('',"Returned Mail: ", $orig_subject);
    push(@message, ("From: $rust_admin\n",
		    "Sender: $rust_admin\n",
		    "Reply-To: $rust_admin\n",
		    "To: $from_email\n",
		    "Subject: $subject\n\n",
		    "Your mail regarding \"$orig_subject\", which was sent to\n",
		    "$alias_email, is being returned to you.\n\n",
		    "The reason for this is because you tried to send mail to a mailing\n",
		    "list which has restrictions on who can send mail to it.  Any\n",
		    "electronic mail that comes from $internet_domain will be\n",
		    "rejected by the $alias_email mailing list.  Please direct any\n",
		    "questions you may have about this to $rust_admin\n\n",
		    "\-$alias_title\n\n",
		    "The original message body follows.\n",
		    "===================================================================\n\n"));

    $old_message_body = $mail->body();
    foreach $each (@{$old_message_body}) {
	push(@message, $each);
    }

    $autoreply_mail = Mail::Internet->new(\@message);
    &smtpsend($autoreply_mail, $rust_admin);
        
    &ddebug("Leaving Rust_Mail::restricted_autoreply\n");
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub send_logfile {
    #
    # Type: Can be called by external scripts
    #
    # Abstract: Mail a ticket logfile to a user.  This is used
    #           mainly when you have RUST configured NOT to send
    #           the humans every new RUST ticket.  When a person
    #           gets assigned a ticket, this function is used
    #           to send the logfile to the person who got assigned
    #           the ticket.

    &ddebug("Entering Rust_Mail::send_logfile\n");

    my ($caller, $opt_user, $opt_num, $queue_index) = @_;

    my (@ticket_log, @message, $alias_email_addr, $tag, $new_subject, $from_line,
	$count);

    my ($rfc_date) = &rfc_822_date;
    my ($date) = main::ctime($^T);
    chomp($date);

    @ticket_log = Rust_Query::get_ticket_log($caller, "",$opt_num, $queue_index);
    if (!$ticket_log[0]) {
	$ticket_subject = $ticket_log[7];
	$alias_email_addr = &extract_element('alias_email_addr',$queue_index);
	$tag = &extract_element('tag',$queue_index);
   	$new_subject =  join(' ','Re:',sprintf($tag, $opt_num, $ticket_subject));
	$from_line = join('',"\"$caller\" ", "\<", $alias_email_addr, "\>");
	@message = ();

 	push(@message, "From $alias_email_addr $rfc_date\n",
	     "From: $from_line\n",
	     "Sender: $alias_email_addr\n",
	     "Reply-To: $alias_email_addr\n",	
	     "Date: $rfc_date\n",
	     "To: $opt_user\n",
	     "Subject: $new_subject\n\n");

	$count = 0;
	while ($count <= $#ticket_log) {

	    if ($count == 0) {
		push(@message, "=" x 75, "\n",
		"TICKET INFORMATION\n",
		"=" x 75, "\n");
	    } elsif (($count > 0) && ($count < 11)) {
		push(@message, "Ticket Queue: ",$ticket_log[1],"\n",
		     'Ticket Number: ', $ticket_log[2],"\n",
		     'Ticket Creation: ', $ticket_log[3],"\n",
		     'Ticket Updated: ', $ticket_log[4],"\n",
		     'Ticket Notification: ', $ticket_log[5],"\n",
		     'Ticket Category: ', $ticket_log[6],"\n",
		     'Ticket Subject: ', $ticket_log[7],"\n",
		     'Ticket Type: ', $ticket_log[8],"\n",
		     'Ticket User(s): ', $ticket_log[9],"\n",
		     'Ticket Owner: ', $ticket_log[10],"\n",
		     'Ticket Status: ', $ticket_log[11],"\n",
		     'Ticket Priority: ', $ticket_log[12],"\n",
		     'Ticket ETA: ', $ticket_log[13],"\n");
		$count = 13;

	    } elsif ($count ==14) {
		push(@message, "=" x 75, "\n",
		     "Ticket LOGFILE\n",
		     "=" x 75, "\n",
		     $ticket_log[14]);
	    } else {
		push(@message, $ticket_log[$count]);
	    }

	    $count++;
	}
	     
	$send_ticket = Mail::Internet->new(\@message);
	&smtpsend($send_ticket, $alias_email_addr);

    }

    &ddebug("Leaving Rust_Mail::send_logfile\n");
    if ($ticket_log[0]) {
	return ($ticket_log[0], "Received errorcode $ticket_log[0] in Rust_Mail::send_logfile\n");
    } else {
	return ($ticket_log[0], "RUST Ticket logfile has been mailed to $opt_user\n");
    }
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub assign_via_mail {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Assign a ticket to a given person.  This is
    #           synopsys to Rust_Action::do_assign, except that
    #           this one has been custom taylored to do it when
    #           mail is processed, ie non interactively.  At first
    #           I just modified Rust_Mail::assign_via_mail, but thought
    #           it easier and cleaner to just write a seperate function
    #           to do assigning via mail

  &debug("Entering Rust_Mail::assign_via_mail\n");

    my ($caller, $opt_num, $queue_index, $opt_assign) = @_;
      
    my ($type, $error, @errors, $date, $from);
    my ($locked_files) = new Lock;

    @errors = &read_file($caller, $locked_files, "", $opt_num, $queue_index);
    if ($errors[0]) {
	return $errors[0];
    }
    
    $rust_info = $errors[1];
    $queue_index = $rust_info->get_value('queue_index');
    $opt_num = (split(',',$rust_info->get_value('number')))[0];
    $date = $rust_info->get_value('current_date');
    $from = $headers{'from_username'};

    # Check caller permissions here just as a fail-safe thing.  If caller
    # permissions don't check out here, then there is probably something
    # fishy about whoever is calling this function.
    if (&check_caller($caller, $rust_info->get_value('owner'), $queue_index)) {

	&debug("Assigning ticket number $opt_num to $opt_assign\n");

	$type = &prep_assign($opt_assign, $rust_info);

	if (($type == 0) || ($type == 2)) {
	    $error = 12 if $type == 0;
	    $error = 7 if $type == 2;
	    &ddebug("Leaving Rust_Mail::assign_via_mail with errorcode $error\n");
	    $locked_files->unlock_all;
	    return $error;

	} elsif ($type == 3) {
	    &debug("Assigning the ticket to another RUST queue\n");
	    $error = Rust_Action::do_move($caller, $locked_files, $opt_assign, $rust_info);
	    &ddebug("Leaving Rust_Mail::assign_via_mail\n");
	    $rust_info->write_headers;
	    $locked_files->unlock_all;
	    return $error;

	} elsif ($type == 1) {
	    if ($opt_assign eq "none") {
	        &debug("Unassigning the ticket\n");
		@action_list = ("Unassigned by $caller\n");
		$log_message = "$opt_num : unassigned by $from. $date\n";
		$rust_info->set_value('owner','');
	    } else {
	        &debug("Assigning the ticket to a person\n");
		@action_list = ("Assigned to $opt_assign by $from\n");
		$log_message = "$opt_num : assigned to $opt_assign by $from. $date\n";
		$stdout_message = "$opt_num has been assigned to $opt_assign\n";
		$rust_info->set_value('owner', $opt_assign);
	    }
	    	    
	    $error = &write_to_rust_log(1, $rust_info, @action_list);
	    if ($error) {
		&ddebug("Leaving Rust_Mail::assign_via_mail\n");
		$locked_files->unlock_all;
		return $error;
	    }

	    $error = &write_log(1,$log_message,$queue_index);
	    if ($error) {
		&ddebug("Leaving Rust_Mail::assign_via_mail\n");
		$locked_files->unlock_all;
		return $error;
	    }

	    $error = Rust_Mail::send_logfile($caller, $opt_assign, $opt_num, $queue_index);
	} elsif ($type == 4) {
	    $locked_files->unlock_all;
	    return 20;
	}
    } else {
	
	&ddebug("Leaving Rust_Mail::assign_via_mail\n");
	$locked_files->unlock_all;
	return 1;
    }

    &ddebug("Leaving Rust_Mail::assign_via_mail\n");
    $rust_info->write_headers;
    $locked_files->unlock_all;
    return 0;
}    

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub send_admin_mail {
    #
    # Abstract: Send mail to rust-admin if there were any errors.

    &ddebug("Entering Rust_Mail::send_admin_mail\n");

    my ($queue_index, $error, $mail) = @_;

    my ($alias_email, $alais_title, $rust_admin, $error_message, @message);

    &debug("=" x 70, "\n", "=" x 70, "\n",
		      "There has been an error in Rust_Mail.pm\n",
		      "The error # is $error.\n",
		      "Mail is being sent to rust-admin reporting the problem",
		      "\n","=" x 70, "\n", "=" x 70, "\n");

    $error_message = &handle_error(1, $error);
    $alias_email = &extract_element('alias_email_addr',$queue_index);
    $alias_title = &extract_element('alias_title',$queue_index);
    $rust_admin = $globals->{'admin'};
    $subject = "RUST ERROR: Error \# $error";
    $pid = $$;

    push(@message, ("From: $alias_email\n",
		    "Sender: $alias_email\n",
		    "Reply-To: $alias_email\n",
		    "To: $rust_admin\n",
		    "Subject: $subject\n\n",
		    "The RUST Mail System has encountered an error while parsing\n",
		    "an email message.  The error # is $error.  The error message is\n",
		    "$error_message\n",
		    "The mail was sent to $alias_email, and is now being sent to\n",
		    "the rust-admin list.  Below is the included message.  Please\n",
		    "investigate to see why you got the error mentioned above.\n",
		    "Any debug files pretaining to the problem being reported by\n",
		    "this mail will have the PID number of $pid as the last part of\n",
		    "of the debug filename.\n\n",
		    "\-RUST Mail System\n\n",
		    "The original message follows.\n",
		    "===================================================================\n\n"));

    $old_message_headers = $mail->header();
    $old_message_body = $mail->body();

    foreach $each (@{$old_message_headers}) {
	  push(@message, $each);
    }
    foreach $each (@{$old_message_body}) {
	push(@message, $each);
    }

    $error_mail = Mail::Internet->new(\@message);
    &smtpsend($error_mail, $alias_email);
        
    &ddebug("Leaving Rust_Mail::send_admin_mail\n");
  }

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub smtpsend {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Replaces the smtpsend call in Mail::Internet because
    #           it was sooooo slooowwwww.
    #
    #           The slowness problem isn't entirely due to
    #           Mail::Internet smtpsend.  I haven't quite
    #           figured it out yet.  But I think that I am
    #           going
    #           

    my $src  = shift;
    my ($from_email_addr) = shift;
    my ($mail,$smtp,@hosts);
    my ($smtp_host) = $globals->{'smtp_server'};
    my ($rfc_date) = &rfc_822_date;
    my ($date) = main::ctime($^T);
    chomp($date);

    $smtp = Net::SMTP->new($smtp_host);

    # This call takes a while to complete (sometimes) !!!
    $from_email_addr = mailaddress() if (!$from_email_addr);

    die "Cannot initiate a SMTP connection" unless(defined $smtp);
    
    $smtp->hello( hostname() );
    $mail = $src->dup;
    
#    $mail->delete('From '); # Just in case :-)
    $mail->replace('From ', join(' ',$from_email_addr, $rfc_date));

    $mail->replace('X-Mailer', "Perl5 MailTools v1.09");
    
    # An original message should not have any Recieved lines
    
    $mail->delete('Recieved');
    
    # Who is it to
    
    my @rcpt = ($mail->get('To', 'Cc', 'Bcc'));
    my @addr = map($_->address, Mail::Address->parse(@rcpt));
    
    return () unless(@addr);
    
    $mail->delete('Bcc'); # Remove blind Cc's
    $mail->header;
    
    # Send it
    
    my $ok = $smtp->mail($from_email_addr) &&
	$smtp->to(@addr) &&
            $smtp->data(join("", @{$mail->header},"\n",@{$mail->body}));
    
    $smtp->quit;
    
    $ok ? @addr : ();
}

#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
sub send_via_sendmail {
    #
    # Type: Not to be called by external scripts
    #
    # Abstract: Send a message out using sendmail directly.  This
    #           is used so that I can hide the alias-dist email
    #           address.  The problem was becoming that some
    #           mailers (elm) would, on a reply to mail that was
    #           sent to alias-dist, would tack alias-dist on the
    #           CC line (even though alias_email_addr was on the
    #           Reply-To: header).  This was causing problems.

  &ddebug("Entering Rust_Mail::send_via_sendmail\n");
    
    my ($outgoing_mail, $alias_dist, $alias_email_addr) = @_;

    my ($sendmail) = $globals->{'sendmail_prog'};

    $message_headers = $outgoing_mail->header();
    $message_body = $outgoing_mail->body();

    if (open(SENDMAIL,"|$sendmail -f$alias_email_addr $alias_dist")) {
	foreach $each (@{$message_headers}) {
	    print SENDMAIL $each;
	}
	foreach $each (@{$message_body}) {
	    print SENDMAIL $each;
	}
	close(SENDMAIL);

    } else {
        &ddebug("Leaving Rust_Mail::send_via_sendmail\n");
	return 32;
    }

    &ddebug("Leaving Rust_Mail::send_via_sendmail\n");
    return 0;
}

    

}
1;

