Bugfix
[squirrelmail.git] / src / download.php
1 <?php
2
3 /**
4 * download.php
5 *
6 * Copyright (c) 1999-2002 The SquirrelMail Project Team
7 * Licensed under the GNU GPL. For full terms see the file COPYING.
8 *
9 * Handles attachment downloads to the users computer.
10 * Also allows displaying of attachments when possible.
11 *
12 * $Id$
13 */
14
15 require_once('../src/validate.php');
16 require_once('../functions/imap.php');
17 require_once('../functions/mime.php');
18 require_once('../functions/date.php');
19 require_once('../functions/html.php');
20
21 header('Pragma: ');
22 header('Cache-Control: cache');
23
24 function viewText($color, $body, $id, $entid, $mailbox, $type1, $wrap_at, $imapConnection) {
25 global $where, $what, $charset;
26 global $startMessage;
27
28 displayPageHeader($color, 'None');
29
30 if ($where && $what) {
31 // from a search
32 $message_link_str = "<a href=\"read_body.php?mailbox=".urlencode($mailbox)."&passed_id=$id&where=".urlencode($where)."&what=".urlencode($what)."\">". _("View message") . "</a>";
33 } else {
34 $message_link_str = "<a href=\"read_body.php?mailbox=".urlencode($mailbox)."&passed_id=$id&startMessage=$startMessage&show_more=0\">". _("View message") . "</a>";
35 }
36 $urlmailbox = urlencode($mailbox);
37
38 echo '<br>' .
39 html_tag( 'table',
40 html_tag( 'tr',
41 html_tag( 'td',
42 '<b><center>' .
43 _("Viewing a text attachment") . ' - ' . $message_link_str . '</b></center>',
44 'left', $color[0] )
45 ) .
46 html_tag( 'tr',
47 html_tag( 'td',
48 '<center>' .
49 "<A HREF=\"../src/download.php?absolute_dl=true&passed_id=$id&passed_ent_id=$entid&mailbox=$urlmailbox\">".
50 _("Download this as a file").
51 "</A></CENTER><BR>",
52 'left' )
53 ),
54 'center', '', 'width="100%" border="0" cellspacing="0" cellpadding="2"' );
55
56 if ($type1 == 'html') {
57 $msg = sqimap_get_message($imapConnection, $id, $mailbox);
58 $body = MagicHTML( $body, $id, $msg );
59 } else {
60 translateText($body, $wrap_at, $charset);
61 }
62
63 flush();
64
65 //"<TABLE WIDTH=\"98%\" BORDER=0 CELLSPACING=0 CELLPADDING=2 ALIGN=CENTER><TR><TD BGCOLOR=\"$color[0]\">".
66 //"<TR><TD BGCOLOR=\"$color[4]\"><TT>";
67
68 html_tag( 'table',
69 html_tag( 'tr',
70 html_tag( 'td', '<tt>' . $body . '</tt>', 'left', $color[4] )
71 ) ,
72 'center', '', 'width="98%" border="0" cellspacing="0" cellpadding="2"' );
73 }
74
75 function viewMessage($imapConnection, $id, $mailbox, $ent_id, $color, $wrap_at, $extracted) {
76 global $startMessage;
77
78
79 $msg = sqimap_get_message($imapConnection, $id, $mailbox);
80 $msg = getEntity($msg, $ent_id);
81
82 $header = sqimap_get_ent_header($imapConnection,$id,$mailbox,$ent_id);
83 $header->id = $id;
84 $msg->header = $header;
85
86 $ent_ar = findDisplayEntity($msg, 0);
87 $body = '';
88 for ($i = 0; $i < count($ent_ar); $i++) {
89 $body .= formatBody($imapConnection, $msg, $color, $wrap_at, $ent_ar[$i], false);
90 }
91
92 $bodyheader = viewHeader($header, $color);
93 displayPageHeader($color, 'None');
94
95 echo '<br>' .
96 html_tag( 'table', '', 'center', '', 'width="100%" border="0" cellspacing="0" cellpadding="2"' );
97
98 if ($extracted) {
99 echo html_tag( 'tr',
100 html_tag( 'td', '<center><h1>Message succesfully extracted</h1></center>', 'left', '', 'width="100%"' )
101 );
102 }
103
104 $td_str = "<b><center>". _("Viewing a message attachment") . " - ";
105 $td_str .= "<a href=\"read_body.php?mailbox=".urlencode($mailbox)."&passed_id=$id&startMessage=$startMessage&show_more=0\">". _("View message") . "</a></b></center>";
106 echo html_tag( 'tr',
107 html_tag( 'td', $td_str, 'left', $color[0] )
108 );
109
110 $urlmailbox = urlencode($mailbox);
111 $td_str = "<center><b><A HREF=\"../src/download.php?absolute_dl=true&passed_id=$id&passed_ent_id=$ent_id&mailbox=$urlmailbox\">".
112 _("Download this as a file").
113 "</A><BR>".
114 "</b></center>";
115 echo html_tag( 'tr',
116 html_tag( 'td', $td_str, 'left' )
117 ) .
118
119 "</TABLE>\n" .
120 html_tag( 'table',
121 html_tag( 'tr',
122 html_tag( 'td', $bodyheader, 'left', $color[4] )
123 ) ,
124 'center', '', 'width="100%" border="0" cellspacing="0" cellpadding="2"' ) . "\n" .
125 html_tag( 'table',
126 html_tag( 'tr',
127 html_tag( 'td', '<tt><br>' . $body . '</tt>', 'left', $color[4] )
128 ) ,
129 'center', '', 'width="98%" border="0" cellspacing="0" cellpadding="2"' ) . "<br>\n";
130
131 echo html_tag( 'table', '', '', '', 'width="100%"' ) .
132 html_tag( 'tr' ) .
133 html_tag( 'td', '', 'center', $color[9], 'width="100%"' ) .
134 '<form action="download.php" method="post"><small>'.
135 "<input type=\"hidden\" name=\"passed_id\" value=\"$id\">".
136 "<input type=\"hidden\" name=\"mailbox\" value=\"".$mailbox."\">".
137 "<input type=\"hidden\" name=\"startMessage\" value=\"$startMessage\">".
138 "<input type=\"hidden\" name=\"passed_ent_id\" value=\"$ent_id\">".
139 "<input type=\"hidden\" name=\"extract_message\" value=\"1\">".
140 _("Save to:") .
141 ' <select name="targetMailbox">';
142 get_extract_to_target_list($imapConnection);
143 echo '</select> '.'&nbsp'.
144 '<input type="submit" value="' . _("Extract") . '">'.
145 '</small>'.
146 '</form>'.
147 '</td></tr></table>';
148
149 }
150
151 function get_extract_to_target_list($imapConnection) {
152
153 $boxes = sqimap_mailbox_list($imapConnection);
154 for ($i = 0; $i < count($boxes); $i++) {
155 if (!in_array('noselect', $boxes[$i]['flags'])) {
156 $box = $boxes[$i]['unformatted'];
157 $box2 = str_replace(' ', '&nbsp;', $boxes[$i]['unformatted-disp']);
158 if ( $box2 == 'INBOX' ) {
159 $box2 = _("INBOX");
160 }
161 echo "<option value=\"$box\">$box2</option>\n";
162 }
163 }
164 }
165
166
167 function viewHeader($header,$color) {
168
169 $bodyheader = '';
170
171 /** FORMAT THE FROM STRING **/
172 $from_name = decodeHeader(htmlspecialchars($header->from));
173 if(isset($from_name) && $from_name !='') {
174 $bodyheader .= makeTableEntry($from_name,_("From"), $color);
175 }
176
177 $subject_string = decodeHeader(htmlspecialchars($header->subject));
178 if(isset($subject_string) && $subject_string !='') {
179 $bodyheader .= makeTableEntry($subject_string,_("Subject:"), $color);
180 }
181 /** FORMAT THE TO STRING **/
182 $to = formatRecipientString($header->to, "to");
183 $to_string = $to['str'];
184 $url_to_string = $to['url_str'];
185 if(isset($to_string) && $to_string !='') {
186 $bodyheader .= makeTableEntry($to_string,_("To:"), $color);
187 }
188
189 /** FORMAT THE DATE STRING **/
190 $dateString = getLongDateString($header->date);
191 if(isset($dateString) && $dateString !='') {
192 $bodyheader .= makeTableEntry($dateString,_("Date:"), $color);
193 }
194
195 /** FORMAT THE CC STRING **/
196 $cc = formatRecipientString($header->cc, "cc");
197 $cc_string = $cc['str'];
198 $url_cc_string = $cc['url_str'];
199 if(isset($cc_string) && $cc_string !='') {
200 $bodyheader .= makeTableEntry($cc_string,_("Cc:"), $color);
201 }
202
203 /** FORMAT THE BCC STRING **/
204 $bcc = formatRecipientString($header->bcc, "bcc");
205 $bcc_string = $bcc['str'];
206 $url_bcc_string = $bcc['url_str'];
207 if(isset($bcc_string) && $bcc_string !='') {
208 $bodyheader .= makeTableEntry($bcc_string,_("Bcc:"), $color);
209 }
210
211 return $bodyheader;
212 }
213
214 function makeTableEntry($str, $str_name, $color) {
215 $entry = html_tag( 'tr',
216 html_tag( 'td', $str_name, 'right', $color[0], 'valign="top"' ) .
217 html_tag( 'td', '<b>' . $str .'</b>&nbsp;', 'left', $color[0], 'valign="top" colspan="2"' )
218 );
219 return $entry;
220 }
221
222 function formatRecipientString($recipients, $item ) {
223 global $base_uri, $passed_id, $startMessage, $show_more_cc, $show_more, $show_more_bcc, $passed_ent_id;
224 global $where, $what, $mailbox, $sort;
225
226 /** TEXT STRINGS DEFINITIONS **/
227 $echo_more = _("more");
228 $echo_less = _("less");
229
230 if (!isset($show_more_cc)) {
231 $show_more_cc = FALSE;
232 }
233 if (!isset($show_more_bcc)) {
234 $show_more_bcc = FALSE;
235 }
236
237
238 $urlMailbox = urlencode($mailbox);
239 $i = 0;
240 $url_string = '';
241
242 if (isset ($recipients[0]) && trim($recipients[0])) {
243 $string = '';
244 $ary = explode(",",$recipients[0]);
245
246 switch ($item) {
247 case 'to':
248 $show = "&amp;show_more=1&amp;show_more_cc=$show_more_cc&amp;show_more_bcc=$show_more_bcc";
249 $show_n = "&amp;show_more=0&amp;show_more_cc=$show_more_cc&amp;show_more_bcc=$show_more_bcc";
250 break;
251 case 'cc':
252 $show = "&amp;show_more=$show_more&amp;show_more_cc=1&amp;show_more_bcc=$show_more_bcc";
253 $show_n = "&amp;show_more=$show_more&amp;show_more_cc=0&amp;show_more_bcc=$show_more_bcc";
254 $show_more = $show_more_cc;
255 break;
256 case 'bcc':
257 $show = "&amp;show_more=$show_more&amp;show_more_cc=$show_more_cc&amp;show_more_bcc=1";
258 $show_n = "&amp;show_more=$show_more&amp;show_more_cc=$show_more_cc&amp;show_more_bcc=0";
259 $show_more = $show_more_bcc;
260 break;
261 default:
262 $break;
263 }
264
265 while ($i < count($ary)) {
266 $ary[$i] = htmlspecialchars(decodeHeader($ary[$i]));
267 $url_string .= $ary[$i];
268 if ($string) {
269 $string = "$string<BR>$ary[$i]";
270 } else {
271 $string = "$ary[$i]";
272 }
273
274 $i++;
275 if (count($ary) > 1) {
276 if ($show_more == false) {
277 if ($i == 1) {
278
279 $string .= '&nbsp;(<A HREF="' . $base_uri .
280 "src/download.php?mailbox=$urlMailbox&amp;passed_id=$passed_id&amp;";
281 if (isset($where) && isset($what)) {
282 $string .= 'what=' . urlencode($what)."&amp;where=".urlencode($where)."&amp;passed_ent_id=$passed_ent_id$show\">$echo_more</A>)";
283 } else {
284 $string .= "sort=$sort&amp;startMessage=$startMessage"."&amp;passed_ent_id=$passed_ent_id$show\">$echo_more</A>)";
285 }
286 $i = count($ary);
287 }
288 } else if ($i == 1) {
289
290 $string .= '&nbsp;(<A HREF="' . $base_uri .
291 "src/download.php?mailbox=$urlMailbox&amp;passed_id=$passed_id&amp;";
292 if (isset($where) && isset($what)) {
293 $string .= 'what=' . urlencode($what)."&amp;where=".urlencode($where)."&amp;passed_ent_id=$passed_ent_id$show_n\">$echo_less</A>)";
294 } else {
295 $string .= "sort=$sort&amp;startMessage=$startMessage"."&amp;passed_ent_id=$passed_ent_id$show_n\">$echo_less</A>)";
296 }
297 }
298 }
299
300 }
301 }
302 else {
303 $string = '';
304 }
305 $url_string = urlencode($url_string);
306 $result = array();
307 $result['str'] = $string;
308 $result['url_str'] = $url_string;
309 return $result;
310
311 }
312
313
314 $imapConnection = sqimap_login($username, $key, $imapServerAddress, $imapPort, 0);
315 sqimap_mailbox_select($imapConnection, $mailbox);
316
317 $extracted = false;
318 if (isset($extract_message) && $extract_message) {
319 $cmd = "FETCH $passed_id BODY[$passed_ent_id]";
320 $read = sqimap_run_command ($imapConnection, $cmd, true, $response, $message);
321 $cnt = count($read);
322 $body = '';
323 $length = 0;
324 for ($i=1;$i<$cnt;$i++) {
325 $length = $length + strlen($read[$i]);
326 $body .= $read[$i];
327 }
328 if (isset($targetMailbox) && $length>0) {
329 sqimap_append ($imapConnection, $targetMailbox, $length);
330 fputs($imapConnection,$body);
331 sqimap_append_done ($imapConnection);
332 $extracted = true;
333 }
334 }
335
336 if (isset($showHeaders)) {
337 $top_header = sqimap_get_message_header ($imapConnection, $passed_id, $mailbox);
338 }
339 /*
340 * lets redefine message as this particular entity that we wish to display.
341 * it should hold only the header for this entity. We need to fetch the body
342 * yet before we can display anything.
343 */
344
345 $header = sqimap_get_mime_ent_header ($imapConnection, $passed_id, $mailbox, $passed_ent_id);
346 $header->entity_id = $passed_ent_id;
347 $header->mailbox = $mailbox;
348
349 $charset = $header->charset;
350 $type0 = $header->type0;
351 $type1 = $header->type1;
352 if (isset($override_type0)) {
353 $type0 = $override_type0;
354 }
355 if (isset($override_type1)) {
356 $type1 = $override_type1;
357 }
358 $filename = decodeHeader($header->filename);
359 if (!$filename) {
360 $filename = decodeHeader($header->name);
361 }
362
363 if (strlen($filename) < 1) {
364 if ($type1 == 'plain' && $type0 == 'text') {
365 $suffix = 'txt';
366 } else if ($type1 == 'richtext' && $type0 == 'text') {
367 $suffix = 'rtf';
368 } else if ($type1 == 'postscript' && $type0 == 'application') {
369 $suffix = 'ps';
370 } else if ($type1 == 'rfc822' && $type0 == 'message') {
371 $suffix = 'eml';
372 } else {
373 $suffix = $type1;
374 }
375
376 $filename = "untitled$passed_ent_id.$suffix";
377 }
378
379
380 /*
381 * Note:
382 * The following sections display the attachment in different
383 * ways depending on how they choose. The first way will download
384 * under any circumstance. This sets the Content-type to be
385 * applicatin/octet-stream, which should be interpreted by the
386 * browser as "download me".
387 * The second method (view) is used for images or other formats
388 * that should be able to be handled by the browser. It will
389 * most likely display the attachment inline inside the browser.
390 * And finally, the third one will be used by default. If it
391 * is displayable (text or html), it will load them up in a text
392 * viewer (built in to squirrelmail). Otherwise, it sets the
393 * content-type as application/octet-stream
394 */
395 if (isset($absolute_dl) && $absolute_dl == 'true') {
396 switch($type0) {
397 case 'text':
398 DumpHeaders($type0, $type1, $filename, 1);
399 $body = mime_fetch_body($imapConnection, $passed_id, $passed_ent_id);
400 $body = decodeBody($body, $header->encoding);
401 if ($type1 == 'plain' && isset($showHeaders)) {
402 echo _("Subject") . ": " . decodeHeader($top_header->subject) . "\n".
403 " " . _("From") . ": " . decodeHeader($top_header->from) . "\n".
404 " " . _("To") . ": " . decodeHeader(getLineOfAddrs($top_header->to)) . "\n".
405 " " . _("Date") . ": " . getLongDateString($top_header->date) . "\n\n";
406 } elseif ($type1 == 'html' && isset($showHeaders)) {
407 echo html_tag( 'table',
408 html_tag( 'tr',
409 html_tag( 'th', _("Subject") . ':', 'right' ) .
410 html_tag( 'th', decodeHeader($top_header->subject), 'left' ) . "\n" .
411 html_tag( 'th', _("From") . ':', 'right' ) .
412 html_tag( 'th', decodeHeader($top_header->from), 'left' ) . "\n" .
413 html_tag( 'th', _("To") . ':', 'right' ) .
414 html_tag( 'th', decodeHeader(getLineOfAddrs($top_header->to)), 'left' ) . "\n" .
415 html_tag( 'th', _("Date") . ':', 'right' ) .
416 html_tag( 'th', getLongDateString($top_header->date), 'left' ) . "\n"
417 )
418 ) . "\n<hr>\n";
419 }
420 echo $body;
421 break;
422
423 default:
424 DumpHeaders($type0, $type1, $filename, 1);
425 mime_print_body_lines ($imapConnection, $passed_id, $passed_ent_id, $header->encoding);
426 break;
427 }
428 } else {
429 switch ($type0) {
430 case 'text':
431 if ($type1 == 'plain' || $type1 == 'html') {
432 $body = mime_fetch_body($imapConnection, $passed_id, $passed_ent_id);
433 $body = decodeBody($body, $header->encoding);
434 viewText($color, $body, $passed_id, $passed_ent_id, $mailbox, $type1, $wrap_at, $imapConnection);
435 } else {
436 DumpHeaders($type0, $type1, $filename, 0);
437 $body = mime_fetch_body($imapConnection, $passed_id, $passed_ent_id);
438 $body = decodeBody($body, $header->encoding);
439 echo $body;
440 }
441 break;
442 case 'message':
443 if ($type1 == 'rfc822' ) {
444 viewMessage($imapConnection, $passed_id, $mailbox, $passed_ent_id, $color, $wrap_at, $extracted);
445 } else {
446 $body = mime_fetch_body($imapConnection, $passed_id, $passed_ent_id);
447 $body = decodeBody($body, $msgheader->encoding);
448 viewText($color, $body, $passed_id, $passed_ent_id, $mailbox, $type1, $wrap_at, $imapConnection);
449 }
450 break;
451 default:
452 DumpHeaders($type0, $type1, $filename, 0);
453 mime_print_body_lines ($imapConnection, $passed_id, $passed_ent_id, $header->encoding);
454 break;
455 }
456 }
457
458
459 /*
460 * This function is verified to work with Netscape and the *very latest*
461 * version of IE. I don't know if it works with Opera, but it should now.
462 */
463 function DumpHeaders($type0, $type1, $filename, $force) {
464 global $HTTP_USER_AGENT;
465
466 $isIE = 0;
467
468 if (strstr($HTTP_USER_AGENT, 'compatible; MSIE ') !== false &&
469 strstr($HTTP_USER_AGENT, 'Opera') === false) {
470 $isIE = 1;
471 }
472
473 if (strstr($HTTP_USER_AGENT, 'compatible; MSIE 6') !== false &&
474 strstr($HTTP_USER_AGENT, 'Opera') === false) {
475 $isIE6 = 1;
476 }
477
478 $filename = ereg_replace('[^-a-zA-Z0-9\.]', '_', $filename);
479
480 // A Pox on Microsoft and it's Office!
481 if (! $force) {
482 // Try to show in browser window
483 header("Content-Disposition: inline; filename=\"$filename\"");
484 header("Content-Type: $type0/$type1; name=\"$filename\"");
485 } else {
486 // Try to pop up the "save as" box
487 // IE makes this hard. It pops up 2 save boxes, or none.
488 // http://support.microsoft.com/support/kb/articles/Q238/5/88.ASP
489 // But, accordint to Microsoft, it is "RFC compliant but doesn't
490 // take into account some deviations that allowed within the
491 // specification." Doesn't that mean RFC non-compliant?
492 // http://support.microsoft.com/support/kb/articles/Q258/4/52.ASP
493 //
494 // The best thing you can do for IE is to upgrade to the latest
495 // version
496 if ($isIE && !isset($isIE6)) {
497 // http://support.microsoft.com/support/kb/articles/Q182/3/15.asp
498 // Do not have quotes around filename, but that applied to
499 // "attachment"... does it apply to inline too?
500 //
501 // This combination seems to work mostly. IE 5.5 SP 1 has
502 // known issues (see the Microsoft Knowledge Base)
503 header("Content-Disposition: inline; filename=$filename");
504
505 // This works for most types, but doesn't work with Word files
506 header("Content-Type: application/download; name=\"$filename\"");
507
508 // These are spares, just in case. :-)
509 //header("Content-Type: $type0/$type1; name=\"$filename\"");
510 //header("Content-Type: application/x-msdownload; name=\"$filename\"");
511 //header("Content-Type: application/octet-stream; name=\"$filename\"");
512 } else {
513 header("Content-Disposition: attachment; filename=\"$filename\"");
514 // application/octet-stream forces download for Netscape
515 header("Content-Type: application/octet-stream; name=\"$filename\"");
516 }
517 }
518 }
519 ?>