Merge branch 'master' of https://github.com/jgoodman/Freeside
[freeside.git] / rt / share / html / Ticket / Elements / ShowTransactionAttachments
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2014 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 ( grep $_->__Value('Parent') == $Parent, @$Attachments ) {
52
53     if (RT->Config->Get('GnuPG')->{'Enable'}) {
54         $m->comp( 'ShowGnuPGStatus', Attachment => $message, WarnUnsigned => $WarnUnsigned );
55     }
56
57     $m->comp( 'ShowMessageHeaders',
58               Message        => $message,
59               DisplayHeaders => \@DisplayHeaders,
60             );
61
62     my $size = $message->ContentLength;
63     my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
64     if ( $size ) {
65 </%PERL>
66 <div class="downloadattachment">
67 <a href="<% $AttachPath %>/<% $Transaction->Id %>/<% $message->Id %>/<% $name | u%>"><&|/l&>Download</&> <% length $name ? $name : loc('(untitled)') %></a>\
68 % if ( $DownloadableHeaders && ! length $name && $message->ContentType =~ /text/  ) {
69  / <a href="<% $AttachPath %>/WithHeaders/<% $message->Id %>"><% loc('with headers') %></a>
70 % }
71 % $m->callback(CallbackName => 'AfterDownloadLinks', ARGSRef => \%ARGS, Ticket => $Ticket, Transaction => $Transaction, Attachment => $message);
72 <br />
73 <span class="downloadcontenttype"><% $message->ContentType %> <% $size_to_str->( $size ) %></span>
74 </div>
75 %   }
76 %# If there is sub-messages, open a dedicated div
77 % if ( scalar ( grep $_->__Value('Parent') == $message->id, @$Attachments ) ) {
78 <div class="messageattachments">
79 % } else {
80 <div class="messagebody">
81 % }
82 <%PERL>
83
84 $render_attachment->( $message );
85
86 $m->comp(
87     $m->current_comp,
88     %ARGS,
89     Parent    => $message->id,
90     ParentObj => $message
91 );
92
93 </%PERL>
94 </div>
95 % }
96 <%ARGS>
97 $Ticket => undef
98 $Transaction => undef
99 $ShowHeaders => 0
100 $Collapsed => undef
101 $DownloadableHeaders => 1
102 $ShowTitleBarCommands => 1
103 $RowNum => 1
104 $AttachPath => RT->Config->Get('WebPath')."/Ticket/Attachment"
105 $UpdatePath => RT->Config->Get('WebPath')."/Ticket/Update.html"
106 $EmailRecordPath => RT->Config->Get('WebPath')."/Ticket/ShowEmailRecord.html"
107 $Attachments => undef
108 $AttachmentContent => {}
109 $ShowBody => 1
110 $Parent => 0
111 $ParentObj => undef
112 $WarnUnsigned => 0
113 </%ARGS>
114 <%INIT>
115 my @DisplayHeaders=qw(_all);
116 if ( $Transaction->Type =~ /EmailRecord$/ ) {
117     @DisplayHeaders = qw(To Cc Bcc);
118 }
119
120 # If the transaction has anything attached to it at all
121 elsif (!$ShowHeaders)  {
122     @DisplayHeaders = qw(To From RT-Send-Cc Cc Bcc Date Subject);
123     push @DisplayHeaders, 'RT-Send-Bcc' if RT->Config->Get('ShowBccHeader');
124 }
125
126 $m->callback(CallbackName => 'MassageDisplayHeaders', DisplayHeaders => \@DisplayHeaders, Transaction => $Transaction);
127
128 my $size_to_str = sub {
129     my $size = shift;
130     # show a download link
131     if ( $size > 1024*1024 ) {
132         $size = loc( "[_1]m", int( $size / 1024 / 102.4 ) / 10 );
133     }
134     elsif ( $size > 1024 ) {
135         $size = loc( "[_1]k", int( $size / 102.4 ) / 10 );
136     }
137     else {
138         $size = loc( "[_1]b", $size );
139     }
140     return $size;
141 };
142
143 my $render_attachment = sub {
144     my $message = shift;
145     my $name = defined $message->Filename && length $message->Filename ?  $message->Filename : '';
146
147     my $content_type = lc $message->ContentType;
148
149     # if it has a content-disposition: attachment, don't show inline
150     my $disposition = $message->GetHeader('Content-Disposition');
151
152     if ( $disposition && $disposition =~ /^\s*attachment/i ) {
153         $disposition = 'attachment';
154     } else {
155         $disposition = 'inline';
156     }
157
158     # If it's text
159     if ( $content_type =~ m{^(text|message)/} ) {
160         my $max_size = RT->Config->Get( 'MaxInlineBody', $session{'CurrentUser'} );
161         if ( $disposition ne 'inline' ) {
162             $m->out('<p>'. loc( 'Message body is not shown because sender requested not to inline it.' ) .'</p>');
163             return;
164         }
165         elsif ( length $name && RT->Config->Get('SuppressInlineTextFiles', $session{'CurrentUser'} ) ) {
166             $m->out('<p>'. loc( 'Text file is not shown because it is disabled in preferences.' ) .'</p>');
167             return;
168         }
169         elsif ( $max_size && $message->ContentLength > $max_size ) {
170             $m->out('<p>'. loc( 'Message body is not shown because it is too large.' ) .'</p>');
171             return;
172         }
173
174         if (
175
176             # it's a toplevel object
177             !$ParentObj
178
179             # or its parent isn't a multipart alternative
180             || ( $ParentObj->ContentType !~ m{^multipart/(?:alternative|related)$}i )
181
182             # or it's of our prefered alterative type
183             || (
184                 (
185                     RT->Config->Get('PreferRichText')
186                     && ( $content_type =~ m{^text/(?:html|enriched)$} )
187                 )
188                 || ( !RT->Config->Get('PreferRichText')
189                     && ( $content_type !~ m{^text/(?:html|enriched)$} )
190                 )
191             )
192         ) {
193
194             my $content;
195             # If we've cached the content, use it from there
196             if (my $x = $AttachmentContent->{ $Transaction->id }->{$message->id}) {
197                 $content = $x->Content;
198             }
199             else {
200                 $content = $message->Content;
201             }
202
203             $RT::Logger->debug(
204                 "Rendering attachment #". $message->id
205                 ." of '$content_type' type"
206             );
207
208             # if it's a text/html clean the body and show it
209             if ( $content_type eq 'text/html' ) {
210                 $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
211
212                 $m->comp(
213                     '/Elements/MakeClicky',
214                     content => \$content,
215                     html    => 1,
216                     ticket  => $Ticket,
217                 );
218
219                 unless (length $name) {
220                     eval {
221                         require HTML::Quoted;
222                         $content = HTML::Quoted->extract($content)
223                     };
224                     if ($@) {
225                         RT->Logger->error(
226                             "HTML::Quoted couldn't process attachment #@{[$message->id]}: $@."
227                           . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
228                     }
229                 }
230
231                 $m->comp(
232                     'ShowMessageStanza',
233                     Message     => $content,
234                     Transaction => $Transaction,
235                     ContentType => 'text/html',
236                 );
237             }
238
239             elsif ( $content_type eq 'text/enriched' ) {
240                 $content = $m->comp( '/Elements/ScrubHTML', Content => $content );
241                 $m->out( $content );
242             }
243
244             # It's a text type we don't have special handling for
245             else {
246                 unless ( length $name ) {
247                     eval {
248                         require Text::Quoted;
249                         # XXX: Deprecate ->can check in 4.2 and simply bump version requirement.
250                         Text::Quoted::set_quote_characters(undef) # only use >
251                             if Text::Quoted->can("set_quote_characters");
252                         $content = Text::Quoted::extract($content);
253                     };
254                     if ($@) {
255                         RT->Logger->error(
256                             "Text::Quoted couldn't process attachment #@{[$message->id]}: $@."
257                           . "  This is a bug, please report it to rt-bugs\@bestpractical.com.");
258                     }
259                 }
260
261                 $m->comp(
262                     'ShowMessageStanza',
263                     Message     => $content,
264                     Transaction => $Transaction,
265                     ContentType => 'text/plain',
266                 );
267             }
268         }
269     }
270
271     # if it's an image, show it as an image
272     elsif ( RT->Config->Get('ShowTransactionImages') and  $content_type =~ m{^image/} ) {
273         if ( $disposition ne 'inline' ) {
274             $m->out('<p>'. loc( 'Message body is not shown because sender requested not to inline it.' ) .'</p>');
275             return;
276         }
277
278         my $filename =  length $name ? $name : loc('(untitled)');
279         my $efilename = $m->interp->apply_escapes( $filename, 'h' );
280         $m->out('<img'
281               . ' alt="'
282               . $efilename
283               . '"' 
284               . ' title="'
285               . $efilename
286               . '"' 
287               . ' src="'
288               . $AttachPath . '/'
289               . $Transaction->Id . '/'
290               . $message->Id
291               . '/" />' );
292     }
293     elsif ( $message->ContentLength && $message->ContentLength > 0 ) {
294         $m->out( '<p>' .
295             loc( 'Message body not shown because it is not plain text.' ) .
296             '</p>'
297         );
298     }
299 };
300
301 </%INIT>