X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FEmailParser.pm;h=8ed810c561ca8dd4f1c8e4c98a02bcfbaa198f46;hb=34647c32b50ce3b8ee1b6d3d7aef4ba9d0297bdb;hp=e9a00f16c03c7dc0247bc9d2c71e7703162f187b;hpb=c582e92888b4a5553e1b4e5214cf35217e4a0cf0;p=freeside.git diff --git a/rt/lib/RT/EmailParser.pm b/rt/lib/RT/EmailParser.pm index e9a00f16c..8ed810c56 100644 --- a/rt/lib/RT/EmailParser.pm +++ b/rt/lib/RT/EmailParser.pm @@ -1,8 +1,14 @@ -# BEGIN LICENSE BLOCK +# {{{ BEGIN BPS TAGGED BLOCK # -# Copyright (c) 1996-2003 Jesse Vincent +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC +# # -# (Except where explictly superceded by other copyright notices) +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: # # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have @@ -14,13 +20,29 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# # +# CONTRIBUTION SUBMISSION POLICY: # -# END LICENSE BLOCK +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# }}} END BPS TAGGED BLOCK package RT::EmailParser; @@ -151,11 +173,62 @@ sub CheckForAutoGenerated { # }}} + +=head2 SmartParseMIMEEntityFromScalar { Message => SCALAR_REF, Decode => BOOL } + +Parse a message stored in a scalar from scalar_ref + + +=cut + +sub SmartParseMIMEEntityFromScalar { + my $self = shift; + my %args = ( Message => undef, Decode => 1, @_ ); + + my ( $fh, $temp_file ); + eval { + + for ( 1 .. 10 ) { + + # on NFS and NTFS, it is possible that tempfile() conflicts + # with other processes, causing a race condition. we try to + # accommodate this by pausing and retrying. + last + if ( $fh, $temp_file ) = + eval { File::Temp::tempfile( undef, UNLINK => 0 ) }; + sleep 1; + } + if ($fh) { + + #thank you, windows + binmode $fh; + $fh->autoflush(1); + print $fh $args{'Message'}; + close($fh); + if ( -f $temp_file ) { + + # We have to trust the temp file's name -- untaint it + $temp_file =~ /(.*)/; + $self->ParseMIMEEntityFromFile( $1, $args{'Decode'} ); + unlink($1); + } + } + }; + + #If for some reason we weren't able to parse the message using a temp file + # try it with a scalar + if ( $@ || !$self->Entity ) { + $self->ParseMIMEEntityFromScalar( $args{'Message'}, $args{'Decode'} ); + } + +} + # {{{ sub ParseMIMEEntityFromSTDIN sub ParseMIMEEntityFromSTDIN { my $self = shift; - return $self->ParseMIMEEntityFromFileHandle(\*STDIN); + my $postprocess = (@_ ? shift : 1); + return $self->ParseMIMEEntityFromFileHandle(\*STDIN, $postprocess); } # }}} @@ -174,11 +247,11 @@ Returns false if it loses. sub ParseMIMEEntityFromScalar { my $self = shift; my $message = shift; - - $self->_DoParse('parse_data', $message); - + my $postprocess = (@_ ? shift : 1); + $self->_ParseMIMEEntity($message,'parse_data', $postprocess); } + # {{{ ParseMIMEEntityFromFilehandle *FH =head2 ParseMIMEEntityFromFilehandle *FH @@ -190,9 +263,8 @@ Parses a mime entity from a filehandle passed in as an argument sub ParseMIMEEntityFromFileHandle { my $self = shift; my $filehandle = shift; - - $self->_DoParse('parse', $filehandle); - + my $postprocess = (@_ ? shift : 1); + $self->_ParseMIMEEntity($filehandle,'parse', $postprocess); } # }}} @@ -207,27 +279,19 @@ Parses a mime entity from a filename passed in as an argument sub ParseMIMEEntityFromFile { my $self = shift; - my $file = shift; - $self->_DoParse('parse_open', $file); + my $postprocess = (@_ ? shift : 1); + $self->_ParseMIMEEntity($file,'parse_open',$postprocess); } # }}} - -# {{{ _DoParse - -=head2 _DoParse PARSEMETHOD CONTENT - - -A helper for the various parsers to turn around and do the dispatch to the actual parser - -=cut - -sub _DoParse { +# +# {{{ _ParseMIMEEntity { +sub _ParseMIMEEntity { my $self = shift; + my $message = shift; my $method = shift; - my $file = shift; - + my $postprocess = shift; # Create a new parser object: my $parser = MIME::Parser->new(); @@ -235,22 +299,23 @@ sub _DoParse { # TODO: XXX 3.0 we really need to wrap this in an eval { } - - unless ( $self->{'entity'} = $parser->$method($file) ) { - + unless ( $self->{'entity'} = $parser->$method($message) ) { + $RT::Logger->crit("Couldn't parse MIME stream and extract the submessages"); # Try again, this time without extracting nested messages $parser->extract_nested_messages(0); - unless ( $self->{'entity'} = $parser->$method($file) ) { + unless ( $self->{'entity'} = $parser->$method($message) ) { $RT::Logger->crit("couldn't parse MIME stream"); return ( undef); } } - $self->_PostProcessNewEntity(); - return (1); + if ($postprocess) { + $self->_PostProcessNewEntity() ; + } + } -# }}} +# }}} # {{{ _PostProcessNewEntity @@ -402,6 +467,8 @@ sub ParseAddressFromHeader { my $self = shift; my $Addr = shift; + # Perl 5.8.0 breaks when doing regex matches on utf8 + Encode::_utf8_off($Addr) if $] == 5.008; my @Addresses = Mail::Address->parse($Addr); my $AddrObj = $Addresses[0]; @@ -593,7 +660,7 @@ A private instance method which sets up a mime parser to do its job sub _SetupMIMEParser { my $self = shift; my $parser = shift; - + # Set up output directory for files: my $tmpdir = File::Temp::tempdir( TMPDIR => 1, CLEANUP => 1 ); @@ -612,6 +679,15 @@ sub _SetupMIMEParser { # do _not_ store each msg as in-core scalar; $parser->output_to_core(0); + + # From the MIME::Parser docs: + # "Normally, tmpfiles are created when needed during parsing, and destroyed automatically when they go out of scope" + # Turns out that the default is to recycle tempfiles + # Temp files should never be recycled, especially when running under perl taint checking + + $parser->tmp_recycling(0); + + } # }}}