RT 4.2.11, ticket#13852
[freeside.git] / rt / share / html / Elements / ShowTransactionAttachments
diff --git a/rt/share/html/Elements/ShowTransactionAttachments b/rt/share/html/Elements/ShowTransactionAttachments
new file mode 100644 (file)
index 0000000..7aeded6
--- /dev/null
@@ -0,0 +1,293 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
+%#                                          <sales@bestpractical.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/licenses/old-licenses/gpl-2.0.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
+%# 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 }}}
+<%PERL>
+# Find all the attachments which have parent $Parent
+# For each of these attachments
+foreach my $message ( @{ $Attachments->{ $Parent || 0 } || [] } ) {
+    $m->comp( 'ShowMessageHeaders',
+              WarnUnsigned   => $WarnUnsigned,
+              Message        => $message,
+              DisplayHeaders => \@DisplayHeaders,
+            );
+
+    my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
+    if ( $message->ContentLength or $name ) {
+</%PERL>
+<div class="downloadattachment">
+<a href="<% $AttachmentPath %>/<% $Transaction->Id %>/<% $message->Id %>/<% $name | u%>"><&|/l&>Download</&> <% length $name ? $name : loc('(untitled)') %></a>\
+% if ( $DownloadableHeaders && ! length $name && $message->ContentType =~ /text/  ) {
+ / <a href="<% $AttachmentPath %>/WithHeaders/<% $message->Id %>"><% loc('with headers') %></a>
+% }
+% $m->callback(CallbackName => 'AfterDownloadLinks', ARGSRef => \%ARGS, Object => $Object, Transaction => $Transaction, Attachment => $message);
+<br />
+<span class="downloadcontenttype"><% $message->ContentType %> <% $message->FriendlyContentLength %></span>
+</div>
+%   }
+%# If there is sub-messages, open a dedicated div
+% if ( $Attachments->{ $message->id } ) {
+<div class="messageattachments">
+% } else {
+<div class="messagebody">
+% }
+<%PERL>
+
+$render_attachment->( $message );
+
+$m->comp(
+    $m->current_comp,
+    %ARGS,
+    Parent    => $message->id,
+    ParentObj => $message,
+
+    displayed_inline => $displayed_inline,
+);
+
+</%PERL>
+</div>
+% }
+<%ARGS>
+$Transaction
+$Object => $Transaction->Object
+$ShowHeaders => 0
+$DownloadableHeaders => 1
+$AttachmentPath => undef
+$Attachments => {}
+$AttachmentContent => {}
+$Parent => 0
+$ParentObj => undef
+$WarnUnsigned => 0
+
+# Keep track of CID images we display inline
+$displayed_inline => {}
+</%ARGS>
+<%INIT>
+my @DisplayHeaders=qw(_all);
+if ( $Transaction->Type =~ /EmailRecord$/ ) {
+    @DisplayHeaders = qw(To Cc Bcc);
+}
+
+# If the transaction has anything attached to it at all
+elsif (!$ShowHeaders)  {
+    @DisplayHeaders = qw(To From RT-Send-Cc Cc Bcc Date Subject);
+    push @DisplayHeaders, 'RT-Send-Bcc' if RT->Config->Get('ShowBccHeader');
+}
+
+$m->callback(CallbackName => 'MassageDisplayHeaders', DisplayHeaders => \@DisplayHeaders, Transaction => $Transaction, ShowHeaders => $ShowHeaders);
+
+my $render_attachment = sub {
+    my $message = shift;
+    my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
+
+    my $content_type = lc $message->ContentType;
+
+    # if it has a content-disposition: attachment, don't show inline
+    my $disposition = $message->GetHeader('Content-Disposition');
+
+    if ( $disposition && $disposition =~ /^\s*attachment/i ) {
+        $disposition = 'attachment';
+    } else {
+        $disposition = 'inline';
+    }
+
+    # If it's text
+    if ( $content_type =~ m{^(text|message)/} ) {
+        my $max_size = RT->Config->Get( 'MaxInlineBody', $session{'CurrentUser'} );
+        if ( $disposition ne 'inline' ) {
+            $m->out('<p>'. loc( 'Message body is not shown because sender requested not to inline it.' ) .'</p>');
+            return;
+        }
+        elsif ( length $name && RT->Config->Get('SuppressInlineTextFiles', $session{'CurrentUser'} ) ) {
+            $m->out('<p>'. loc( 'Text file is not shown because it is disabled in preferences.' ) .'</p>');
+            return;
+        }
+        elsif ( $max_size && $message->ContentLength > $max_size ) {
+            $m->out('<p>'. loc( 'Message body is not shown because it is too large.' ) .'</p>');
+            return;
+        }
+
+        if (
+
+            # it's a toplevel object
+            !$ParentObj
+
+            # or its parent isn't a multipart alternative
+            || ( $ParentObj->ContentType !~ m{^multipart/(?:alternative|related)$}i )
+
+            # or it's of our prefered alterative type
+            || (
+                (
+                    RT->Config->Get('PreferRichText', $session{CurrentUser})
+                    && ( $content_type =~ m{^text/(?:html|enriched)$} )
+                )
+                || ( !RT->Config->Get('PreferRichText', $session{CurrentUser})
+                    && ( $content_type !~ m{^text/(?:html|enriched)$} )
+                )
+            )
+        ) {
+
+            my $content;
+            # If we've cached the content, use it from there
+            if (my $x = $AttachmentContent->{ $Transaction->id }->{$message->id}) {
+                $content = $x->Content;
+            }
+            else {
+                $content = $message->Content;
+            }
+
+            $RT::Logger->debug(
+                "Rendering attachment #". $message->id
+                ." of '$content_type' type"
+            );
+
+            # if it's a text/html clean the body and show it
+            if ( $content_type eq 'text/html' ) {
+                $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
+
+                if (RT->Config->Get('ShowTransactionImages')) {
+                    my @rewritten = RT::Interface::Web::RewriteInlineImages(
+                        Content         => \$content,
+                        Attachment      => $message,
+                        # Not technically correct to search all parts of the
+                        # MIME structure, but it saves having to go to the
+                        # database again and is unlikely to break display.
+                        Related         => [ map { @$_ } values %$Attachments ],
+                        AttachmentPath  => $AttachmentPath,
+                    );
+                    $displayed_inline->{$_}++ for @rewritten;
+                }
+
+                $m->comp(
+                    '/Elements/MakeClicky',
+                    content => \$content,
+                    html    => 1,
+                    object  => $Object,
+                );
+
+                if ( !length $name && RT->Config->Get( 'QuoteFolding', $session{CurrentUser} ) ) {
+                    eval {
+                        require HTML::Quoted;
+                        $content = HTML::Quoted->extract($content)
+                    };
+                    if ($@) {
+                        RT->Logger->error(
+                            "HTML::Quoted couldn't process attachment #@{[$message->id]}: $@."
+                          . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
+                    }
+                }
+
+                $m->comp(
+                    'ShowMessageStanza',
+                    Message     => $content,
+                    Transaction => $Transaction,
+                    ContentType => 'text/html',
+                );
+            }
+
+            elsif ( $content_type eq 'text/enriched' ) {
+                $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
+                $m->out( $content );
+            }
+
+            # It's a text type we don't have special handling for
+            else {
+                if ( !length $name && RT->Config->Get( 'QuoteFolding', $session{CurrentUser} ) ) {
+                    eval {
+                        require Text::Quoted;
+                        Text::Quoted::set_quote_characters(undef);
+                        $content = Text::Quoted::extract($content);
+                    };
+                    if ($@) {
+                        RT->Logger->error(
+                            "Text::Quoted couldn't process attachment #@{[$message->id]}: $@."
+                          . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
+                    }
+                }
+
+                $m->comp(
+                    'ShowMessageStanza',
+                    Message     => $content,
+                    Transaction => $Transaction,
+                    ContentType => 'text/plain',
+                );
+            }
+        }
+    }
+
+    # if it's an image, show it as an image
+    elsif ( $content_type =~ m{^image/} ) {
+        if (not RT->Config->Get('ShowTransactionImages')) {
+            $m->out('<p><i>'. loc( 'Image not shown because display is disabled in system configuration.' ) .'</i></p>');
+            return;
+        }
+        elsif ( $displayed_inline->{$message->Id} ) {
+            $m->out('<p><i>'. loc( 'Image displayed inline above' ) .'</i></p>');
+            return;
+        }
+        elsif ( $disposition ne 'inline' ) {
+            $m->out('<p>'. loc( 'Image not shown because sender requested not to inline it.' ) .'</p>');
+            return;
+        }
+
+        my $filename = length $name ? $name : loc('(untitled)');
+        my $efilename = $m->interp->apply_escapes( $filename, 'h' );
+        $m->out(
+            qq{<img alt="$efilename" title="$efilename"}
+            . ' src="'. $AttachmentPath .'/'. $Transaction->Id .'/'. $message->Id .'/'
+                . $m->interp->apply_escapes( $filename, 'u', 'h' )
+            . '" />'
+        );
+    }
+    elsif ( $message->ContentLength && $message->ContentLength > 0 ) {
+        $m->out( '<p>' .
+            loc( 'Message body not shown because it is not plain text.' ) .
+            '</p>'
+        );
+    }
+};
+
+</%INIT>