The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Email::Outlook::Message::Attachment;
=head1 NAME

Email::Outlook::Message::Attachment - Handle attachment data in .msg files

=head1 DESCRIPTION

This is an internal module of Email::Outlook::Message. It is a subclass of
Email::Outlook::Message::Base.

=head1 METHODS

=over 8

=item B<new($pps, $verbosity)>

Create a new attachment object, using $pps as data source. Overrides the base
method by setting some default values.

=item B<to_email_mime()>

Convert the attachment to an Email::MIME object.

=back

=head1 AUTHOR

Matijs van Zuijlen, C<matijs@matijs.net>

=head1 COPYRIGHT AND LICENSE

Copyright 2002--2014 by Matijs van Zuijlen

This module is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
use strict;
use warnings;
use Carp;
use Email::MIME::ContentType;
use base 'Email::Outlook::Message::Base';

our $MAP_ATTACHMENT_FILE = {
  '3701' => "DATA",        # Data
  '3704' => "SHORTNAME",   # Short file name
  '3707' => "LONGNAME",    # Long file name
  '370E' => "MIMETYPE",    # mime type
  '3712' => "CONTENTID",   # content-id
  '3716' => "DISPOSITION", # disposition
};

sub new {
  my ($class, $pps, $verbosity) = @_;
  my $self = $class->SUPER::new($pps, $verbosity);
  bless $self, $class;
  $self->{MIMETYPE} ||= 'application/octet-stream';
  $self->{ENCODING} ||= 'base64';
  $self->{DISPOSITION} ||= 'attachment';
  if ($self->{MIMETYPE} eq 'multipart/signed') {
    $self->{ENCODING} = '8bit';
  }
  return $self;
}

sub to_email_mime {
  my $self = shift;

  my $mt = parse_content_type($self->{MIMETYPE});
  my $m = Email::MIME->create(
    attributes => {
      content_type => "$mt->{discrete}/$mt->{composite}",
      %{$mt->{attributes}},
      encoding => $self->{ENCODING},
      filename => $self->{LONGNAME} || $self->{SHORTNAME},
      name => $self->{LONGNAME} || $self->{LONGNAME},
      disposition => $self->{DISPOSITION},
    },
    header => [ 'Content-ID' => $self->{CONTENTID} ],
    body => $self->{DATA});
  return $m
}

sub _property_map {
  return $MAP_ATTACHMENT_FILE;
}

sub _process_subdirectory {
  my ($self, $pps) = @_;
  my $name = $self->_get_pps_name($pps);
  my ($property, $encoding) = $self->_parse_item_name($name);

  if ($property eq '3701') { # Nested msg file
    my $is_msg = 1;
    foreach my $child (@{$pps->{Child}}) {
      unless ($self->_get_pps_name($child) =~ / ^ ( __recip | __attach
        | __substg1 | __nameid | __properties ) /x
      ) {
        $is_msg = 0;
        last;
      }
    }
    if ($is_msg) {
      my $msgp = Email::Outlook::Message->_empty_new();
      $msgp->_set_verbosity($self->{VERBOSE});
      $msgp->_process_pps($pps);

      $self->{DATA} = $msgp->to_email_mime->as_string;
      $self->{MIMETYPE} = 'message/rfc822';
      $self->{ENCODING} = '8bit';
    } else {
      foreach my $child (@{$pps->{Child}}) {
        if (eval { $child->isa('OLE::Storage_Lite::PPS::File')}) {
          foreach my $prop ("Time1st", "Time2nd") {
            $child->{$prop} = undef;
          }
        }
      }
      my $nPps = OLE::Storage_Lite::PPS::Root->new(
        $pps->{Time1st}, $pps->{Time2nd}, $pps->{Child});
      my $data;
      my $io = IO::String->new($data);
      binmode($io);
      $nPps->save($io, 1);
      $self->{DATA} = $data;
    }
  } else {
    $self->_warn_about_unknown_directory($pps);
  }
  return;
}

sub _property_stream_header_length { return 8; }

1;