[Rt-commit] r9655 - in rt/branches/3.6-EXPERIMENTAL-CATEGORIES: . html/Search lib lib/RT lib/RT/Action

falcone at bestpractical.com falcone at bestpractical.com
Tue Nov 13 13:06:41 EST 2007


Author: falcone
Date: Tue Nov 13 13:06:38 2007
New Revision: 9655

Modified:
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/   (props changed)
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Elements/MyRT
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Search/Chart
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT.pm.in
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Action/SendEmail.pm
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Attachment_Overlay.pm
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/I18N.pm
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Record.pm
   rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Transaction_Overlay.pm

Log:
merge down 3.6-release into the cateogories branch

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Elements/MyRT
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Elements/MyRT	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Elements/MyRT	Tue Nov 13 13:06:38 2007
@@ -48,7 +48,7 @@
 <table border="0" width="100%">
 <tr valign="top">
 
-<td class="boxcontainer" width="70%" <% $summary? 'width="70%"': '' %>>
+<td class="boxcontainer" <% $summary? 'width="70%"': '' |n %>>
 % $show_cb->($_) foreach @$body;
 </td>
 

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Search/Chart
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Search/Chart	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/html/Search/Chart	Tue Nov 13 13:06:38 2007
@@ -86,6 +86,26 @@
 $chart->set_values_font( $font, 9 ) if $chart->can('set_values_font');
 $chart->set_value_font( $font, 9 ) if $chart->can('set_value_font');
 
+# Pie charts don't like having no input, so we show a special image
+# that indicates an error message. Because this is used in an <img>
+# context, it can't be a simple error message. Without this check,
+# the chart will just be a non-loading image.
+if ($tix->Count == 0) {
+    my $plot = GD::Image->new(600 => 400);
+    $plot->colorAllocate(255, 255, 255); # background
+    my $black = $plot->colorAllocate(0, 0, 0);
+
+    require GD::Text::Wrap;
+    my $error = GD::Text::Wrap->new($plot,
+        color => $black,
+        text  => loc("No tickets found."),
+    );
+    $error->set_font( $font, 12 );
+    $error->draw(0, 0);
+
+    $m->comp( 'SELF:Plot', plot => $plot, %ARGS );
+}
+
 if ($chart_class eq "GD::Graph::bars") {
     $chart->set(
         x_label => $tix->Label( $PrimaryGroupBy ),
@@ -143,17 +163,26 @@
 
 
 my $plot = $chart->plot( [ [@sorted_keys], [@sorted_values] ] ) or die $chart->error;
+$m->comp( 'SELF:Plot', plot => $plot, %ARGS );
+</%init>
 
-if ( $plot->can('png') ) {
-    $r->content_type('image/png');
-    $m->out( $plot->png );
-}
-elsif ( $plot->can('gif') ) {
-    $r->content_type('image/gif');
-    $m->out( $plot->gif );
+<%METHOD Plot>
+<%ARGS>
+$plot => undef
+</%ARGS>
+<%INIT>
+my @types = ('png', 'gif');
+
+for my $type (@types) {
+    $plot->can($type)
+        or next;
+
+    $r->content_type("image/$type");
+    $m->out( $plot->$type );
+    $m->abort();
 }
-else { 
-    die "Your GD library appears to support neither PNG nor GIF";
-}
-$m->abort();
-</%init>
+
+die "Your GD library appears to support none of the following image types: " . join(', ', @types);
+</%INIT>
+
+</%METHOD>

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT.pm.in
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT.pm.in	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT.pm.in	Tue Nov 13 13:06:38 2007
@@ -459,6 +459,8 @@
 
 =cut
 
+eval "require RT_Vendor";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT_Vendor.pm});
 eval "require RT_Local";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT_Local.pm});
 

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Action/SendEmail.pm
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Action/SendEmail.pm	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Action/SendEmail.pm	Tue Nov 13 13:06:38 2007
@@ -164,16 +164,24 @@
     # We should never have to set the MIME-Version header
     $self->SetHeader( 'MIME-Version', '1.0' );
 
-    # try to convert message body from utf-8 to $RT::EmailOutputEncoding
-    $self->SetHeader( 'Content-Type', 'text/plain; charset="utf-8"' );
-
     # fsck.com #5959: Since RT sends 8bit mail, we should say so.
     $self->SetHeader( 'Content-Transfer-Encoding','8bit');
 
+    # For security reasons, we only send out textual mails.
+    my @parts = $MIMEObj;
+    while (my $part = shift @parts) {
+        if ($part->is_multipart) {
+            push @parts, $part->parts;
+        }
+        else {
+            $part->head->mime_attr( "Content-Type" => 'text/plain' )
+                unless RT::I18N::IsTextualContentType($part->mime_type);
+            $part->head->mime_attr( "Content-Type.charset" => 'utf-8' );
+        }
+    }
+
 
-    RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding,
-        'mime_words_ok' );
-    $self->SetHeader( 'Content-Type', 'text/plain; charset="' . $RT::EmailOutputEncoding . '"' );
+    RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding, 'mime_words_ok' );
 
     # Build up a MIME::Entity that looks like the original message.
     $self->AddAttachments() if ( $MIMEObj->head->get('RT-Attach-Message') );
@@ -398,7 +406,7 @@
         # Don't attach anything blank
         next unless ( $attach->ContentLength );
 
-# We want to make sure that we don't include the attachment that's being sued as the "Content" of this message"
+# We want to make sure that we don't include the attachment that's being used as the "Content" of this message.
         next
           if ( $transaction_content_obj
             && $transaction_content_obj->Id == $attach->Id

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Attachment_Overlay.pm
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Attachment_Overlay.pm	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Attachment_Overlay.pm	Tue Nov 13 13:06:38 2007
@@ -276,8 +276,8 @@
 sub OriginalContent {
   my $self = shift;
 
-  return $self->Content unless (
-     $self->ContentType =~ qr{^(text/plain|message/rfc822)$}i) ;
+  return $self->Content unless RT::I18N::IsTextualContentType($self->ContentType);
+
   my $enc = $self->OriginalEncoding;
 
   my $content;
@@ -286,12 +286,15 @@
   } elsif ( $self->ContentEncoding eq 'base64' ) {
       $content = MIME::Base64::decode_base64($self->_Value('Content', decode_utf8 => 0));
   } elsif ( $self->ContentEncoding eq 'quoted-printable' ) {
-      return MIME::QuotedPrint::decode($self->_Value('Content', decode_utf8 => 0));
+      $content = MIME::QuotedPrint::decode($self->_Value('Content', decode_utf8 => 0));
   } else {
       return( $self->loc("Unknown ContentEncoding [_1]", $self->ContentEncoding));
   }
 
-   Encode::_utf8_on($content);
+  # Turn *off* the SvUTF8 bits here so decode_utf8 and from_to below can work.
+  local $@;
+  Encode::_utf8_off($content);
+
   if (!$enc || $enc eq '' ||  $enc eq 'utf8' || $enc eq 'utf-8') {
     # If we somehow fail to do the decode, at least push out the raw bits
     eval {return( Encode::decode_utf8($content))} || return ($content);
@@ -356,7 +359,7 @@
 
     # TODO: Handle Multipart/Mixed (eventually fix the link in the
     # ShowHistory web template?)
-    if ($self->ContentType =~ m{^(text/plain|message)}i) {
+    if (RT::I18N::IsTextualContentType($self->ContentType)) {
 	$body=$self->Content;
 
 	# Do we need any preformatting (wrapping, that is) of the message?

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/I18N.pm
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/I18N.pm	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/I18N.pm	Tue Nov 13 13:06:38 2007
@@ -153,7 +153,7 @@
 
 =head2 SetMIMEEntityToUTF8 $entity
 
-An utility method which will try to convert entity body into utf8.
+An utility function which will try to convert entity body into utf8.
 It's now a wrap-up of SetMIMEEntityToEncoding($entity, 'utf-8').
 
 =cut
@@ -164,16 +164,37 @@
 
 # }}}
 
+# {{{ IsTextualContentType
+
+=head2 IsTextualContentType $type
+
+An utility function that determines whether $type is I<textual>, meaning
+that it can sensibly be converted to Unicode text.
+
+Currently, it returns true iff $type matches this regular expression
+(case-insensitively):
+
+    ^(?:text/(?:plain|html)|message/rfc822)\b
+
+# }}}
+
+=cut
+
+sub IsTextualContentType {
+    my $type = shift;
+    ($type =~ m{^(?:text/(?:plain|html)|message/rfc822)\b}i) ? 1 : 0;
+}
+
 # {{{ SetMIMEEntityToEncoding
 
 =head2 SetMIMEEntityToEncoding $entity, $encoding
 
-An utility method which will try to convert entity body into specified
+An utility function which will try to convert entity body into specified
 charset encoding (encoded as octets, *not* unicode-strings).  It will
 iterate all the entities in $entity, and try to convert each one into
 specified charset if whose Content-Type is 'text/plain'.
 
-This method doesn't return anything meaningful.
+This function doesn't return anything meaningful.
 
 =cut
 
@@ -205,11 +226,9 @@
 
     # If this is a textual entity, we'd need to preserve its original encoding
     $head->add( "X-RT-Original-Encoding" => $charset )
-	if $head->mime_attr('content-type.charset') or $head->mime_type =~ /^text/;
-
+	if $head->mime_attr('content-type.charset') or IsTextualContentType($head->mime_type);
 
-    return unless ( $head->mime_type =~ qr{^(text/plain|message/rfc822)$}i  );
-    
+    return unless IsTextualContentType($head->mime_type);
 
     my $body = $entity->bodyhandle;
 

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Record.pm
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Record.pm	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Record.pm	Tue Nov 13 13:06:38 2007
@@ -862,7 +862,7 @@
     elsif ( $ContentEncoding && $ContentEncoding ne 'none' ) {
         return ( $self->loc( "Unknown ContentEncoding [_1]", $ContentEncoding ) );
     }
-    if ( $ContentType eq 'text/plain' ) {
+    if ( RT::I18N::IsTextualContentType($ContentType) ) {
        $Content = Encode::decode_utf8($Content) unless Encode::is_utf8($Content);
     }
         return ($Content);

Modified: rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Transaction_Overlay.pm
==============================================================================
--- rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Transaction_Overlay.pm	(original)
+++ rt/branches/3.6-EXPERIMENTAL-CATEGORIES/lib/RT/Transaction_Overlay.pm	Tue Nov 13 13:06:38 2007
@@ -78,7 +78,7 @@
 use strict;
 no warnings qw(redefine);
 
-use vars qw( %_BriefDescriptions );
+use vars qw( %_BriefDescriptions $PreferredContentType );
 
 use RT::Attachments;
 use RT::Scrips;
@@ -271,18 +271,23 @@
 
 =head2 Content PARAMHASH
 
-If this transaction has attached mime objects, returns the first text/plain part.
-Otherwise, returns undef.
+If this transaction has attached mime objects, returns the body of the first
+textual part (as defined in RT::I18N::IsTextualContentType).  Otherwise,
+returns undef.
 
 Takes a paramhash.  If the $args{'Quote'} parameter is set, wraps this message 
 at $args{'Wrap'}.  $args{'Wrap'} defaults to 70.
 
+If $args{'Type'} is set to C<text/html>, plain texts are upgraded to HTML.
+Otherwise, HTML texts are downgraded to plain text.  If $args{'Type'} is
+missing, it defaults to the value of C<$RT::Transaction::PreferredContentType>.
 
 =cut
 
 sub Content {
     my $self = shift;
     my %args = (
+        Type  => $PreferredContentType,
         Quote => 0,
         Wrap  => 70,
         @_
@@ -293,9 +298,28 @@
         $content = $content_obj->Content;
 
 	if ($content_obj->ContentType =~ m{^text/html$}i) {
-        $content = HTML::FormatText->new(leftmargin => 0, rightmargin => 78)->format(  HTML::TreeBuilder->new_from_content( $content));
+            $content =~ s/<p>--\s+<br \/>.*?$//s if $args{'Quote'};
 
+            if ($args{Type} ne 'text/html') {
+                $content = HTML::FormatText->new(
+                    leftmargin  => 0,
+                    rightmargin => 78,
+                )->format(
+                    HTML::TreeBuilder->new_from_content( $content )
+                );
+            }
 	}
+        else {
+            $content =~ s/\n-- \n.*?$//s if $args{'Quote'};
+
+            if ($args{Type} eq 'text/html') {
+                # Extremely simple text->html converter
+                $content =~ s/&/&#38;/g;
+                $content =~ s/</&lt;/g;
+                $content =~ s/>/&gt;/g;
+                $content = "<pre>$content</pre>";
+            }
+        }
     }
 
     # If all else fails, return a message that we couldn't find any content
@@ -305,9 +329,6 @@
 
     if ( $args{'Quote'} ) {
 
-        # Remove quoted signature.
-        $content =~ s/\n-- \n(.*?)$//s;
-
         # What's the longest line like?
         my $max = 0;
         foreach ( split ( /\n/, $content ) ) {
@@ -355,18 +376,17 @@
     # Get the set of toplevel attachments to this transaction.
     my $Attachment = $self->Attachments->First();
 
-    # If it's a message or a plain part, just return the
-    # body.
-    if ( $Attachment->ContentType() =~ '^(?:text/plain$|text/html|message/)' ) {
+    # If it's a textual part, just return the body.
+    if ( RT::I18N::IsTextualContentType($Attachment->ContentType) ) {
         return ($Attachment);
     }
 
-    # If it's a multipart object, first try returning the first
-    # text/plain part.
+    # If it's a multipart object, first try returning the first part with preferred
+    # MIME type ('text/plain' by default).
 
     elsif ( $Attachment->ContentType() =~ '^multipart/' ) {
         my $plain_parts = $Attachment->Children();
-        $plain_parts->ContentType( VALUE => 'text/plain' );
+        $plain_parts->ContentType( VALUE => ($PreferredContentType || 'text/plain') );
 
         # If we actully found a part, return its content
         if ( $plain_parts->First && $plain_parts->First->Content ne '' ) {
@@ -374,13 +394,12 @@
         }
 
 
-        # If that fails, return the  first text/plain or message/ part
-        # which has some content.
+        # If that fails, return the first textual part which has some content.
 
         else {
             my $all_parts = $self->Attachments();
             while ( my $part = $all_parts->Next ) {
-                if (( $part->ContentType() =~ '^(text/plain$|message/)' ) &&  $part->Content()  ) {
+                if ( ( RT::I18N::IsTextualContentType($part->ContentType) ) and ( $part->Content() ne '' ) ) {
                     return ($part);
                 }
             }


More information about the Rt-commit mailing list