rt 4.2.13 ticket#13852
[freeside.git] / rt / share / html / Elements / ShowTransactionAttachments
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2016 Best Practical Solutions, LLC
6 %#                                          <sales@bestpractical.com>
7 %#
8 %# (Except where explicitly superseded by other copyright notices)
9 %#
10 %#
11 %# LICENSE:
12 %#
13 %# This work is made available to you under the terms of Version 2 of
14 %# the GNU General Public License. A copy of that license should have
15 %# been provided with this software, but in any event can be snarfed
16 %# from www.gnu.org.
17 %#
18 %# This work is distributed in the hope that it will be useful, but
19 %# WITHOUT ANY WARRANTY; without even the implied warranty of
20 %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 %# General Public License for more details.
22 %#
23 %# You should have received a copy of the GNU General Public License
24 %# along with this program; if not, write to the Free Software
25 %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 %# 02110-1301 or visit their web page on the internet at
27 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 %#
29 %#
30 %# CONTRIBUTION SUBMISSION POLICY:
31 %#
32 %# (The following paragraph is not intended to limit the rights granted
33 %# to you to modify and distribute this software under the terms of
34 %# the GNU General Public License and is only of importance to you if
35 %# you choose to contribute your changes and enhancements to the
36 %# community by submitting them to Best Practical Solutions, LLC.)
37 %#
38 %# By intentionally submitting any modifications, corrections or
39 %# derivatives to this work, or any other work intended for use with
40 %# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 %# you are the copyright holder for those contributions and you grant
42 %# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 %# royalty-free, perpetual, license to use, copy, create derivative
44 %# works based on those contributions, and sublicense and distribute
45 %# those contributions and any derivatives thereof.
46 %#
47 %# END BPS TAGGED BLOCK }}}
48 <%PERL>
49 # Find all the attachments which have parent $Parent
50 # For each of these attachments
51 foreach my $message ( @{ $Attachments->{ $Parent || 0 } || [] } ) {
52     $m->comp( 'ShowMessageHeaders',
53               WarnUnsigned   => $WarnUnsigned,
54               Message        => $message,
55               DisplayHeaders => \@DisplayHeaders,
56             );
57
58     my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
59     my $should_render_download = $message->ContentLength || $name;
60
61     $m->callback(CallbackName => 'BeforeAttachment', ARGSRef => \%ARGS, Object => $Object, Transaction => $Transaction, Attachment => $message, Name => $name, ShouldRenderDownload => \$should_render_download);
62
63     if ($should_render_download) {
64 </%PERL>
65 <div class="downloadattachment">
66 <a href="<% $AttachmentPath %>/<% $Transaction->Id %>/<% $message->Id %>/<% $name | un%>"><&|/l&>Download</&> <% length $name ? $name : loc('(untitled)') %></a>\
67 % if ( $DownloadableHeaders && ! length $name && $message->ContentType =~ /text/  ) {
68  / <a href="<% $AttachmentPath %>/WithHeaders/<% $message->Id %>"><% loc('with headers') %></a>
69 % }
70 % $m->callback(CallbackName => 'AfterDownloadLinks', ARGSRef => \%ARGS, Object => $Object, Transaction => $Transaction, Attachment => $message);
71 <br />
72 <span class="downloadcontenttype"><% $message->ContentType %> <% $message->FriendlyContentLength %></span>
73 </div>
74 %   }
75 %# If there is sub-messages, open a dedicated div
76 % if ( $Attachments->{ $message->id } ) {
77 <div class="messageattachments">
78 % } else {
79 <div class="messagebody">
80 % }
81 <%PERL>
82
83 $render_attachment->( $message );
84
85 $m->comp(
86     $m->current_comp,
87     %ARGS,
88     Parent    => $message->id,
89     ParentObj => $message,
90
91     displayed_inline => $displayed_inline,
92 );
93
94 </%PERL>
95 </div>
96 % }
97 <%ARGS>
98 $Transaction
99 $Object => $Transaction->Object
100 $ShowHeaders => 0
101 $DownloadableHeaders => 1
102 $AttachmentPath => undef
103 $Attachments => {}
104 $AttachmentContent => {}
105 $Parent => 0
106 $ParentObj => undef
107 $WarnUnsigned => 0
108
109 # Keep track of CID images we display inline
110 $displayed_inline => {}
111 </%ARGS>
112 <%INIT>
113 my @DisplayHeaders=qw(_all);
114 if ( $Transaction->Type =~ /EmailRecord$/ ) {
115     @DisplayHeaders = qw(To Cc Bcc);
116 }
117
118 # If the transaction has anything attached to it at all
119 elsif (!$ShowHeaders)  {
120     @DisplayHeaders = qw(To From RT-Send-Cc Cc Bcc Date Subject);
121     push @DisplayHeaders, 'RT-Send-Bcc' if RT->Config->Get('ShowBccHeader');
122 }
123
124 $m->callback(CallbackName => 'MassageDisplayHeaders', DisplayHeaders => \@DisplayHeaders, Transaction => $Transaction, ShowHeaders => $ShowHeaders);
125
126 my $render_attachment = sub {
127     my $message = shift;
128     my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
129
130     my $content_type = lc $message->ContentType;
131
132     # if it has a content-disposition: attachment, don't show inline
133     my $disposition = $message->GetHeader('Content-Disposition');
134
135     if ( $disposition && $disposition =~ /^\s*attachment/i ) {
136         $disposition = 'attachment';
137     } else {
138         $disposition = 'inline';
139     }
140
141     # If it's text
142     if ( $content_type =~ m{^(text|message)/} ) {
143         my $max_size = RT->Config->Get( 'MaxInlineBody', $session{'CurrentUser'} );
144         if ( $disposition ne 'inline' ) {
145             $m->out('<p>'. loc( 'Message body is not shown because sender requested not to inline it.' ) .'</p>');
146             return;
147         }
148         elsif ( length $name && RT->Config->Get('SuppressInlineTextFiles', $session{'CurrentUser'} ) ) {
149             $m->out('<p>'. loc( 'Text file is not shown because it is disabled in preferences.' ) .'</p>');
150             return;
151         }
152         elsif ( $max_size && $message->ContentLength > $max_size ) {
153             $m->out('<p>'. loc( 'Message body is not shown because it is too large.' ) .'</p>');
154             return;
155         }
156
157         if (
158
159             # it's a toplevel object
160             !$ParentObj
161
162             # or its parent isn't a multipart alternative
163             || ( $ParentObj->ContentType !~ m{^multipart/(?:alternative|related)$}i )
164
165             # or it's of our prefered alterative type
166             || (
167                 (
168                     RT->Config->Get('PreferRichText', $session{CurrentUser})
169                     && ( $content_type =~ m{^text/(?:html|enriched)$} )
170                 )
171                 || ( !RT->Config->Get('PreferRichText', $session{CurrentUser})
172                     && ( $content_type !~ m{^text/(?:html|enriched)$} )
173                 )
174             )
175         ) {
176
177             my $content;
178             # If we've cached the content, use it from there
179             if (my $x = $AttachmentContent->{ $Transaction->id }->{$message->id}) {
180                 $content = $x->Content;
181             }
182             else {
183                 $content = $message->Content;
184             }
185
186             $RT::Logger->debug(
187                 "Rendering attachment #". $message->id
188                 ." of '$content_type' type"
189             );
190
191             # if it's a text/html clean the body and show it
192             if ( $content_type eq 'text/html' ) {
193                 $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
194
195                 if (RT->Config->Get('ShowTransactionImages')) {
196                     my @rewritten = RT::Interface::Web::RewriteInlineImages(
197                         Content         => \$content,
198                         Attachment      => $message,
199                         # Not technically correct to search all parts of the
200                         # MIME structure, but it saves having to go to the
201                         # database again and is unlikely to break display.
202                         Related         => [ map { @$_ } values %$Attachments ],
203                         AttachmentPath  => $AttachmentPath,
204                     );
205                     $displayed_inline->{$_}++ for @rewritten;
206                 }
207
208                 $m->comp(
209                     '/Elements/MakeClicky',
210                     content => \$content,
211                     html    => 1,
212                     object  => $Object,
213                 );
214
215                 if ( !length $name && RT->Config->Get( 'QuoteFolding', $session{CurrentUser} ) ) {
216                     eval {
217                         require HTML::Quoted;
218                         $content = HTML::Quoted->extract($content)
219                     };
220                     if ($@) {
221                         RT->Logger->error(
222                             "HTML::Quoted couldn't process attachment #@{[$message->id]}: $@."
223                           . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
224                     }
225                 }
226
227                 $m->comp(
228                     'ShowMessageStanza',
229                     Message     => $content,
230                     Transaction => $Transaction,
231                     ContentType => 'text/html',
232                 );
233             }
234
235             elsif ( $content_type eq 'text/enriched' ) {
236                 $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
237                 $m->out( $content );
238             }
239
240             # It's a text type we don't have special handling for
241             else {
242                 if ( !length $name && RT->Config->Get( 'QuoteFolding', $session{CurrentUser} ) ) {
243                     eval {
244                         require Text::Quoted;
245                         Text::Quoted::set_quote_characters(undef);
246                         $content = Text::Quoted::extract($content);
247                     };
248                     if ($@) {
249                         RT->Logger->error(
250                             "Text::Quoted couldn't process attachment #@{[$message->id]}: $@."
251                           . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
252                     }
253                 }
254
255                 $m->comp(
256                     'ShowMessageStanza',
257                     Message     => $content,
258                     Transaction => $Transaction,
259                     ContentType => 'text/plain',
260                 );
261             }
262         }
263     }
264
265     # if it's an image, show it as an image
266     elsif ( $content_type =~ m{^image/} ) {
267         if (not RT->Config->Get('ShowTransactionImages')) {
268             $m->out('<p><i>'. loc( 'Image not shown because display is disabled in system configuration.' ) .'</i></p>');
269             return;
270         }
271         elsif ( $displayed_inline->{$message->Id} ) {
272             $m->out('<p><i>'. loc( 'Image displayed inline above' ) .'</i></p>');
273             return;
274         }
275         elsif ( $disposition ne 'inline' ) {
276             $m->out('<p>'. loc( 'Image not shown because sender requested not to inline it.' ) .'</p>');
277             return;
278         }
279
280         my $filename = length $name ? $name : loc('(untitled)');
281         my $efilename = $m->interp->apply_escapes( $filename, 'h' );
282         $m->out(
283             qq{<img alt="$efilename" title="$efilename"}
284             . ' src="'. $AttachmentPath .'/'. $Transaction->Id .'/'. $message->Id .'/'
285                 . $m->interp->apply_escapes( $filename, 'u', 'h' )
286             . '" />'
287         );
288     }
289     elsif ( $message->ContentLength && $message->ContentLength > 0 ) {
290         $m->out( '<p>' .
291             loc( 'Message body not shown because it is not plain text.' ) .
292             '</p>'
293         );
294     }
295 };
296
297 </%INIT>