#!/usr/bin/perl
##---------------------------------------------------------------------------##
##  File:
##	$Id: mha-p7m,v 1.1 2011/01/02 11:14:55 ehood Exp $
##  Author:
##      Earl Hood       earl@earlhood.com
##  Description:
##      Front-end to mhonarc to support processing application/x-pkcs7-mime
##      signed messages.
##
##      More Info:
##      <http://www.mhonarc.org/archive/cgi-bin/mesg.cgi?a=mhonarc-users&i=4c798002.c61fe70a.1893.5ea8%40mx.google.com>
##---------------------------------------------------------------------------##
##    Copyright (C) 2010	Earl Hood, earl@earlhood.com
##    This program is free software; you can redistribute it and/or modify
##    it under the same terms as MHonArc itself.
##---------------------------------------------------------------------------##

# Modify the following to specify pathname to mhonarc libraries.
use lib qw( /usr/lib/MHonArc );

use Symbol;
use File::Temp;

# Set to pathname of openssl executable.
my $openssl = 'openssl';

my @argv = @ARGV;
require 'mhamain.pl' || die qq/ERROR: Unable to require "mhamain.pl"\n/;

# Variable that holds the raw header text of the current message
my $current_header_txt = '';

#$mhonarc::Debug = 1;
&mhonarc::initialize();

# Message head callback function to capture raw header text.
# This is needed so we can print it out to temp file when openssl
# is used to extract signed message
#
$mhonarc::CBMessageHeadRead = sub {
  my $fields = shift;
  $current_header_txt = shift;
  $current_header_txt .= "\n";
};

# Raw message body read callback: If application/x-pkcs7-mime signed
# data, openssl used to extract contents and then we replace
# body variable to extracted contents for mhonarc to parse and archive.
#
$mhonarc::CBRawMessageBodyRead = sub {
  my $fields = shift;
  my $data_ref = shift;
  my $ctype = $fields->{'content-type'}[0];

  # If not signed-data, we return immediately
  if (!$ctype || $ctype !~ m{application/x-pkcs7-mime} ||
      $ctype !~ m{signed-data}) {
    return 1;
  }

  # Get here, use openssl to extract main data.

  # Write input data to temp file for use by openssl.
  my $tmp = new File::Temp();
  syswrite($tmp, $current_header_txt);  # openssl requires mail headers
  syswrite($tmp, $$data_ref);

  # Open pipe to openssl to extract the data: The command-line
  # options to make this work is non-intuitive.  Luckily, I found
  # a page on the web that listed the right options for extracting
  # the content w/o the need to validate the signature.
  my $handle = gensym;
  mhonarc::cmd_pipe_open($handle,
                $openssl, 'smime',
                '-verify',
                '-in', $tmp->filename,
                '-noverify');
  my $new_data = join('', <$handle>);
  close($handle);
  close($tmp);

  # Parse the sub-header from extracted data and update
  # main fields to use them over original fields.
  my($sub_header, $txt) = readmail::MAILread_header(\$new_data);
  foreach my $key (keys %$sub_header) {
    $fields->{$key} = $sub_header->{$key};
  }
  if ($sub_header->{'content-type'}) {
    # Make sure update mhonarc's meta field for content-type
    my $ctype = $sub_header->{'content-type'}[0];
    if ($ctype =~ m%^\s*([\w\-\./]+)%) {
      $fields->{'x-mha-content-type'} = $1;
    }
  }
  # IMPORTANT: Make sure CTE is adjusted to reflect extracted data
  if (!$sub_header->{'content-transfer-encoding'}) {
    $fields->{'content-transfer-encoding'} = [ '7bit' ];
  }

  # Replace message data to what was extracted and let mhonarc parse it.
  $$data_ref = $new_data;

  return 1;
};

&mhonarc::process_input(@argv);
