[Rt-commit] rt branch, 4.0/base64-in-rescue-outlook, created. rt-4.0.5-118-ge41b841

Jim Brandt jbrandt at bestpractical.com
Tue May 1 12:28:18 EDT 2012


The branch, 4.0/base64-in-rescue-outlook has been created
        at  e41b84178ad42ff37ade8442b8a537bdd89c1a0c (commit)

- Log -----------------------------------------------------------------
commit 6d20fa4954be37d67fc0c96d92eb61fb789859d4
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Tue May 1 10:45:35 2012 -0400

    Add DECRYPTION_INFO to ignore_keywords.
    
    GnuPG added DECRYPTION_INFO in version 1.4.12.
    
    https://gitorious.org/gnupg-org/gnupg/commit/cfb193a1de2f0553ee65a19a417a885938539225

diff --git a/lib/RT/Crypt/GnuPG.pm b/lib/RT/Crypt/GnuPG.pm
index ab444d0..c5fb12b 100644
--- a/lib/RT/Crypt/GnuPG.pm
+++ b/lib/RT/Crypt/GnuPG.pm
@@ -1683,6 +1683,7 @@ my %ignore_keyword = map { $_ => 1 } qw(
     BEGIN_ENCRYPTION SIG_ID VALIDSIG
     ENC_TO BEGIN_DECRYPTION END_DECRYPTION GOODMDC
     TRUST_UNDEFINED TRUST_NEVER TRUST_MARGINAL TRUST_FULLY TRUST_ULTIMATE
+    DECRYPTION_INFO
 );
 
 sub ParseStatus {

commit e41b84178ad42ff37ade8442b8a537bdd89c1a0c
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Tue May 1 10:57:24 2012 -0400

    Enable Outlook newline cleanup on base64 email.
    
    Move the RescueOutlook call to come after email is decoded.
    
    Allow double newline cleanup on base64 email. Trigger
    based on a config option and some headers that should
    be MS-specific.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 50b46c3..a97227d 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -459,6 +459,22 @@ Set($ExtractSubjectTagNoMatch, ( ${RT::EmailSubjectTagRegex}
        ? qr/\[(?:${RT::EmailSubjectTagRegex}) #\d+\]/
        : qr/\[\Q$RT::rtname\E #\d+\]/));
 
+=item C<$CleanMailDoubleNewlines>
+
+Some email clients create a plain text version of HTML-formatted
+email to help other clients that read only plain text.
+Unfortunately, the plain text parts sometimes end up with
+doubled newlines and these can then end up in RT. This
+is most often seen in MS Outlook.
+
+Enable this option to have RT attempt to clean up double
+newlines in email from MS Outlook. Note that it may
+clean up intentional double newlines as well.
+
+=cut
+
+Set( $CleanMailDoubleNewlines, 0);
+
 =back
 
 
diff --git a/lib/RT/EmailParser.pm b/lib/RT/EmailParser.pm
index 4cf4184..b66761c 100644
--- a/lib/RT/EmailParser.pm
+++ b/lib/RT/EmailParser.pm
@@ -131,8 +131,6 @@ sub SmartParseMIMEEntityFromScalar {
         }
     };
 
-    $self->RescueOutlook;
-
     #If for some reason we weren't able to parse the message using a temp file
     # try it with a scalar
     if ( $@ || !$self->Entity ) {
@@ -568,50 +566,81 @@ return 1 if it does find the problem in the entity and get it fixed.
 sub RescueOutlook {
     my $self = shift;
     my $mime = $self->Entity();
-    return unless $mime;
-
-    my $mailer = $mime->head->get('X-Mailer');
-    # 12.0 is outlook 2007, 14.0 is 2010
-    if ( $mailer && $mailer =~ /Microsoft(?:.*?)Outlook 1[2-4]\./ ) {
-        my $text_part;
-        if ( $mime->head->get('Content-Type') =~ m{multipart/mixed} ) {
-            my $first = $mime->parts(0);
-            if ( $first->head->get('Content-Type') =~ m{multipart/alternative} )
-            {
-                my $inner_first = $first->parts(0);
-                if ( $inner_first->head->get('Content-Type') =~ m{text/plain} )
-                {
-                    $text_part = $inner_first;
-                }
-            }
-        }
-        elsif ( $mime->head->get('Content-Type') =~ m{multipart/alternative} ) {
-            my $first = $mime->parts(0);
-            if ( $first->head->get('Content-Type') =~ m{text/plain} ) {
-                $text_part = $first;
-            }
-        }
 
-        if ($text_part) {
-
-            # use the unencoded string
-            my $content = $text_part->bodyhandle->as_string;
-            if ( $content =~ s/\n\n/\n/g ) {
-                # only write only if we did change the content
-                if ( my $io = $text_part->open("w") ) {
-                    $io->print($content);
-                    $io->close;
-                    return 1;
-                }
-                else {
-                    $RT::Logger->error("can't write to body");
-                }
-            }
-        }
+    return unless $mime && $self->LooksLikeMSEmail($mime);
+
+    my $text_part;
+    if ( $mime->head->get('Content-Type') =~ m{multipart/mixed} ) {
+      my $first = $mime->parts(0);
+      if ( $first->head->get('Content-Type') =~ m{multipart/alternative} ) {
+	my $inner_first = $first->parts(0);
+	if ( $inner_first->head->get('Content-Type') =~ m{text/plain} ) {
+	  $text_part = $inner_first;
+	}
+      }
+    } elsif ( $mime->head->get('Content-Type') =~ m{multipart/alternative} ) {
+      my $first = $mime->parts(0);
+      if ( $first->head->get('Content-Type') =~ m{text/plain} ) {
+	$text_part = $first;
+      }
+    }
+
+    # Add base64 since we've seen examples of double newlines with
+    # this type too. Need an example of a multi-part base64 to
+    # handle that permutation if it exists.
+    elsif ( $mime->head->get('Content-Transfer-Encoding') =~ m{base64} ) {
+      $text_part = $mime;     # Assuming single part, already decoded.
     }
+
+    if ($text_part) {
+      # use the unencoded string
+      my $content = $text_part->bodyhandle->as_string;
+      if ( $content =~ s/\n\n/\n/g ) {
+	# only write only if we did change the content
+	if ( my $io = $text_part->open("w") ) {
+	  $io->print($content);
+	  $io->close;
+	  $RT::Logger->debug("Removed extra newlines from MS Outlook message.");
+	  return 1;
+	} else {
+	  $RT::Logger->error("Can't write to body to fix newlines");
+	}
+      }
+    }
+
     return;
 }
 
+=head1 LooksLikeMSEmail
+
+Try to determine if the current email may have
+come from MS Outlook or gone through Exchange, and therefore
+may have extra newlines added.
+
+=cut
+
+sub LooksLikeMSEmail {
+  my $self = shift;
+  my $mime = shift;
+
+  my $mailer = $mime->head->get('X-Mailer');
+
+  # 12.0 is outlook 2007, 14.0 is 2010
+  return 1 if ( $mailer && $mailer =~ /Microsoft(?:.*?)Outlook 1[2-4]\./ );
+
+  if ( RT->Config->Get('CleanMailDoubleNewlines') ){
+
+    # Check for some headers that might
+    # indicate this came from Outlook or through Exchange.
+    # A sample we received had the headers X-MS-Has-Attach: and
+    # X-MS-Tnef-Correlator: and both had no value.
+
+    my @tags = $mime->head->tags();
+    return 1 if grep { /^X-MS-/ } @tags;
+  }
+
+  return 0; # Doesn't look like MS email.
+}
 
 sub DESTROY {
     my $self = shift;
diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index 909a9f4..47d0add 100644
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -1399,6 +1399,7 @@ sub Gateway {
     }
     @mail_plugins = grep !$skip_plugin{"$_"}, @mail_plugins;
     $parser->_DecodeBodies;
+    $parser->RescueOutlook;
     $parser->_PostProcessNewEntity;
 
     my $head = $Message->head;
diff --git a/t/mail/outlook.t b/t/mail/outlook.t
index 00bbc94..694a8b2 100644
--- a/t/mail/outlook.t
+++ b/t/mail/outlook.t
@@ -1,41 +1,41 @@
 #!/usr/bin/perl -w
 # BEGIN BPS TAGGED BLOCK {{{
-# 
+#
 # COPYRIGHT:
-#  
-# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC
 #                                          <jesse.com>
-# 
+#
 # (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
 # been provided with this software, but in any event can be snarfed
 # from www.gnu.org.
-# 
+#
 # This work 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 this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301 or visit their web page on the internet at
 # http://www.gnu.org/copyleft/gpl.html.
-# 
-# 
+#
+#
 # CONTRIBUTION SUBMISSION POLICY:
-# 
+#
 # (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
@@ -44,19 +44,25 @@
 # 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 }}}
 
 =head1 NAME
 
-rt-mailgate - Mail interface to RT3.
+outlook.t
+
+=head1 DESCRIPTION
+
+Tests for custom routines to work with email from Outlook.
 
 =cut
 
 use strict;
 use warnings;
 
-use RT::Test tests => 42;
+use RT::Test tests => 60;
+
+RT->Config->Set('CleanMailDoubleNewlines', 1);
 
 # 12.0 is outlook 2007, 14.0 is 2010
 for my $mailer ( 'Microsoft Office Outlook 12.0', 'Microsoft Outlook 14.0' ) {
@@ -199,8 +205,75 @@ EOF
         test_email( $text, $content,
             $mailer . ' with only text/plain, \n\n are not replaced' );
     }
+
+    diag "Test mail with with outlook, content type is base64";
+    {
+        my $text = <<EOF;
+From: root\@localhost
+X-Mailer: $mailer
+To: rt\@@{[RT->Config->Get('rtname')]}
+Subject: outlook basic test
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+VGhpcyBpcyB0aGUgYm9keSBvZiBhbiBlbWFpbC4KCkl0IGhhcyBtdWx0aXBs
+ZSBleHRyYSBuZXdsaW5lcy4KCgoKTGlrZSBhIG1hbmdsZWQgT3V0bG9vayBt
+ZXNzYWdlIG1pZ2h0LgoKCgpKb2huIFNtaXRoCgpTb21lIENvbXBhbnkKCmVt
+YWlsQHNvbWVjby5jb20KCg==
+EOF
+
+        my $content = <<EOF;
+This is the body of an email.
+It has multiple extra newlines.
+
+Like a mangled Outlook message might.
+
+John Smith
+Some Company
+email\@someco.com
+EOF
+        test_email( $text, $content,
+            $mailer . ' with base64, \n\n are replaced' );
+    }
 }
 
+# In a sample we received, the two X-MS- headers included
+# below were both present and had no values. For now, using
+# the existence of these headers as evidence of MS Outlook
+# or Exchange.
+
+diag "Test mail with with outlook, no X-Mailer, content type is base64";
+{
+        my $text = <<EOF;
+From: root\@localhost
+To: rt\@@{[RT->Config->Get('rtname')]}
+Subject: outlook basic test
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: base64
+X-MS-Has-Attach:
+X-MS-Tnef-Correlator:
+
+VGhpcyBpcyB0aGUgYm9keSBvZiBhbiBlbWFpbC4KCkl0IGhhcyBtdWx0aXBs
+ZSBleHRyYSBuZXdsaW5lcy4KCgoKTGlrZSBhIG1hbmdsZWQgT3V0bG9vayBt
+ZXNzYWdlIG1pZ2h0LgoKCgpKb2huIFNtaXRoCgpTb21lIENvbXBhbnkKCmVt
+YWlsQHNvbWVjby5jb20KCg==
+EOF
+
+        my $content = <<EOF;
+This is the body of an email.
+It has multiple extra newlines.
+
+Like a mangled Outlook message might.
+
+John Smith
+Some Company
+email\@someco.com
+EOF
+	test_email( $text, $content,
+		    ' with base64, no X-Mailer, \n\n are replaced' );
+}
+
+
 diag "Test mail with with multipart/alternative but x-mailer is not outlook ";
 {
     my $text = <<EOF;

-----------------------------------------------------------------------


More information about the Rt-commit mailing list