# SpamAssassin - Debug logging plugin
#
# <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>
#
###########################################################################

=head1 NAME

LogScannedMessages - SpamAssassin plugin to log every message scanned.

=head1 SYNOPSIS

  loadplugin LogScannedMessages /etc/mail/spamassassin/LogScannedMessages.pm

=head1 DESCRIPTION

This plugin will write a copy of every mail scanned to the
C</tmp/spamassassin_scanned_msgs> directory (creating that dir if it
doesn't already exist).  This may be very useful when attempting to debug
certain error conditions that only manifest with certain input messages.

To activate, add the above "loadplugin" line to a file in your
C</etc/mail/spamassassin> directory.  The plugin will remain quiescent until
you create a file called C</tmp/spamassassin_scanned_msgs/collect>, at which
point, timestamped files will start appearing; each file is the message being
scanned by SpamAssassin at that time.  If the
C</tmp/spamassassin_scanned_msgs/collect> file is then deleted, collection will
cease again.

Since the files are named according to the time at start of scanning, and the
process ID of the spamd process performing the scan, it is easy to correlate
lines in the syslog output with the message they concern.

=cut

package LogScannedMessages;

# directory where the logs are written, and where the "collect" flag goes.
my $logdir = "/tmp/spamassassin_scanned_msgs";

# ---------------------------------------------------------------------------

use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Logger;
use POSIX qw(strftime);

our @ISA = qw(Mail::SpamAssassin::Plugin);

our $counter = 'aaa';

sub new {
  my ($class, $mailsa) = @_;
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsa);
  bless ($self, $class);
  return $self;
}

sub post_message_parse {
  my ($self, $opts) = @_;

  # we do nothing unless the "collect" flag file exists
  if (!-f "$logdir/collect") {
    info("LogScannedMessages: no '$logdir/collect' flag, skipping");
    return;
  }

  my $now = time;
  $counter =~ /(...)$/; $counter = $1;  # ensure it's only 3 chars
  my $fname = sprintf("%s/%s_%05d_%03s.eml",
        $logdir,
        strftime("%Y%m%d-%H%M%S", localtime $now),
        $$,
        $counter++);

  if (!open (OUT, ">$fname")) {         # maybe the logdir doesn't exist?
    mkdir($logdir, 01777);
    chmod(01777, $logdir);
    if (!open (OUT, ">$fname")) {       # really broken this time
      warn "failed to write to $fname: $!";
      return;
    }
  }

  # write a little helpful metadata, too
  print OUT "X-LogScannedMessages-UID-GID: $> $)\n".
        "X-LogScannedMessages-GMTime: ".(scalar gmtime $now)."\n".
        "X-LogScannedMessages-LocalTime: ".(scalar localtime $now)."\n".
        $opts->{message}->get_pristine();
  close OUT or warn "failed to write to $fname: $!";
  info ("logged current message to: $fname");
}

1;
