4 +-----------------------------------------------------------------------+
5 | program/steps/mail/func.inc |
7 | This file is part of the RoundCube Webmail client |
8 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland |
9 | Licensed under the GNU GPL |
12 | Provide webmail functionality and GUI objects |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com> |
16 +-----------------------------------------------------------------------+
18 $Id: func.inc 1255 2008-04-05 12:49:21Z thomasb $
22 require_once('lib/html2text.inc');
23 require_once('lib/enriched.inc');
24 require_once('include/rcube_smtp.inc');
27 $EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i';
29 if (empty($_SESSION['mbox']))
30 $_SESSION['mbox'] = $IMAP->get_mailbox_name();
32 // set imap properties and session vars
33 if ($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC))
34 $IMAP->set_mailbox(($_SESSION['mbox'] = $mbox));
36 if (!empty($_GET['_page']))
37 $IMAP->set_page(($_SESSION['page'] = intval($_GET['_page'])));
39 // set mailbox to INBOX if not set
40 if (empty($_SESSION['mbox']))
41 $_SESSION['mbox'] = $IMAP->get_mailbox_name();
43 // set default sort col/order to session
44 if (!isset($_SESSION['sort_col']))
45 $_SESSION['sort_col'] = $CONFIG['message_sort_col'];
46 if (!isset($_SESSION['sort_order']))
47 $_SESSION['sort_order'] = $CONFIG['message_sort_order'];
49 // set message set for search result
50 if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']]))
52 $IMAP->set_search_set($_SESSION['search'][$_REQUEST['_search']]);
53 $OUTPUT->set_env('search_request', $_REQUEST['_search']);
54 $OUTPUT->set_env('search_text', $_SESSION['last_text_search']);
58 // define url for getting message parts
59 if (strlen($_GET['_uid']))
60 $GET_URL = rcmail_url('get', array('_mbox'=>$IMAP->get_mailbox_name(), '_uid'=>get_input_value('_uid', RCUBE_INPUT_GET)));
63 // set current mailbox in client environment
64 $OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name());
65 $OUTPUT->set_env('quota', $IMAP->get_capability('quota'));
67 if ($CONFIG['trash_mbox'])
68 $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
69 if ($CONFIG['drafts_mbox'])
70 $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
71 if ($CONFIG['junk_mbox'])
72 $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']);
74 if (!$OUTPUT->ajax_call)
75 rcube_add_label('checkingmail', 'deletemessage', 'movemessagetotrash');
78 if (empty($_action) || $_action == 'list')
79 $OUTPUT->set_pagetitle(rcmail_localize_foldername($IMAP->get_mailbox_name()));
83 // return the message list as HTML table
84 function rcmail_message_list($attrib)
86 global $IMAP, $CONFIG, $COMM_PATH, $OUTPUT;
88 $skin_path = $CONFIG['skin_path'];
89 $image_tag = '<img src="%s%s" alt="%s" border="0" />';
91 // check to see if we have some settings for sorting
92 $sort_col = $_SESSION['sort_col'];
93 $sort_order = $_SESSION['sort_order'];
95 // add some labels to client
96 rcube_add_label('from', 'to');
98 // get message headers
99 $a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order);
101 // add id to message list table if not specified
102 if (!strlen($attrib['id']))
103 $attrib['id'] = 'rcubemessagelist';
105 // allow the following attributes to be added to the <table> tag
106 $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
108 $out = '<table' . $attrib_str . ">\n";
111 // define list of cols to be displayed
112 $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
113 $a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
115 $mbox = $IMAP->get_mailbox_name();
117 // show 'to' instead of from in sent messages
118 if (($mbox==$CONFIG['sent_mbox'] || $mbox==$CONFIG['drafts_mbox']) && ($f = array_search('from', $a_show_cols))
119 && !array_search('to', $a_show_cols))
120 $a_show_cols[$f] = 'to';
122 // add col definition
123 $out .= '<colgroup>';
124 $out .= '<col class="icon" />';
126 foreach ($a_show_cols as $col)
127 $out .= sprintf('<col class="%s" />', $col);
129 $out .= '<col class="icon" />';
130 $out .= "</colgroup>\n";
133 $out .= "<thead><tr>\n<td class=\"icon\"> </td>\n";
136 foreach ($a_show_cols as $col)
139 $col_name = Q(rcube_label($col));
143 if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols))
145 // have buttons configured
146 if (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))
148 $sort = ' ';
151 if (!empty($attrib['sortascbutton']))
153 $sort .= $OUTPUT->button(array(
155 'prop' => $col.'_ASC',
156 'image' => $attrib['sortascbutton'],
157 'align' => 'absmiddle',
158 'title' => 'sortasc'));
162 if (!empty($attrib['sortdescbutton']))
164 $sort .= $OUTPUT->button(array(
166 'prop' => $col.'_DESC',
167 'image' => $attrib['sortdescbutton'],
168 'align' => 'absmiddle',
169 'title' => 'sortdesc'));
172 // just add a link tag to the header
176 '<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
179 rcube_label('sortby'),
184 $sort_class = $col==$sort_col ? " sorted$sort_order" : '';
186 // put it all together
187 $out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n";
190 $out .= '<td class="icon">'.($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '')."</td>\n";
191 $out .= "</tr></thead>\n<tbody>\n";
193 // no messages in this mailbox
194 if (!sizeof($a_headers))
195 $OUTPUT->show_message('nomessagesfound', 'notice');
198 $a_js_message_arr = array();
200 // create row for each message
201 foreach ($a_headers as $i => $header) //while (list($i, $header) = each($a_headers))
203 $message_icon = $attach_icon = '';
204 $js_row_arr = array();
205 $zebra_class = $i%2 ? 'even' : 'odd';
207 // set messag attributes to javascript array
208 if ($header->deleted)
209 $js_row_arr['deleted'] = true;
211 $js_row_arr['unread'] = true;
212 if ($header->answered)
213 $js_row_arr['replied'] = true;
215 if ($attrib['deletedicon'] && $header->deleted)
216 $message_icon = $attrib['deletedicon'];
217 else if ($attrib['unreadicon'] && !$header->seen)
218 $message_icon = $attrib['unreadicon'];
219 else if ($attrib['repliedicon'] && $header->answered)
220 $message_icon = $attrib['repliedicon'];
221 else if ($attrib['messageicon'])
222 $message_icon = $attrib['messageicon'];
224 // set attachment icon
225 if ($attrib['attachmenticon'] && preg_match("/multipart\/[mr]/i", $header->ctype))
226 $attach_icon = $attrib['attachmenticon'];
228 $out .= sprintf('<tr id="rcmrow%d" class="message%s%s %s">'."\n",
230 $header->seen ? '' : ' unread',
231 $header->deleted ? ' deleted' : '',
234 $out .= sprintf("<td class=\"icon\">%s</td>\n", $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : '');
237 foreach ($a_show_cols as $col)
239 if ($col=='from' || $col=='to')
240 $cont = Q(rcmail_address_string($header->$col, 3, $attrib['addicon']), 'show');
241 else if ($col=='subject')
243 $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
244 $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
245 $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
246 if (empty($cont)) $cont = Q(rcube_label('nosubject'));
247 $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont);
249 else if ($col=='size')
250 $cont = show_bytes($header->$col);
251 else if ($col=='date')
252 $cont = format_date($header->date);
254 $cont = Q($header->$col);
256 $out .= '<td class="'.$col.'">' . $cont . "</td>\n";
259 $out .= sprintf("<td class=\"icon\">%s</td>\n", $attach_icon ? sprintf($image_tag, $skin_path, $attach_icon, '') : '');
262 if (sizeof($js_row_arr))
263 $a_js_message_arr[$header->uid] = $js_row_arr;
266 // complete message table
267 $out .= "</tbody></table>\n";
270 $message_count = $IMAP->messagecount();
273 $OUTPUT->add_gui_object('mailcontframe', 'mailcontframe');
274 $OUTPUT->add_gui_object('messagelist', $attrib['id']);
275 $OUTPUT->set_env('messagecount', $message_count);
276 $OUTPUT->set_env('current_page', $IMAP->list_page);
277 $OUTPUT->set_env('pagecount', ceil($message_count/$IMAP->page_size));
278 $OUTPUT->set_env('sort_col', $sort_col);
279 $OUTPUT->set_env('sort_order', $sort_order);
281 if ($attrib['messageicon'])
282 $OUTPUT->set_env('messageicon', $skin_path . $attrib['messageicon']);
283 if ($attrib['deletedicon'])
284 $OUTPUT->set_env('deletedicon', $skin_path . $attrib['deletedicon']);
285 if ($attrib['unreadicon'])
286 $OUTPUT->set_env('unreadicon', $skin_path . $attrib['unreadicon']);
287 if ($attrib['repliedicon'])
288 $OUTPUT->set_env('repliedicon', $skin_path . $attrib['repliedicon']);
289 if ($attrib['attachmenticon'])
290 $OUTPUT->set_env('attachmenticon', $skin_path . $attrib['attachmenticon']);
292 $OUTPUT->set_env('messages', $a_js_message_arr);
293 $OUTPUT->set_env('coltypes', $a_show_cols);
295 $OUTPUT->include_script('list.js');
301 // return javascript commands to add rows to the message list
302 function rcmail_js_message_list($a_headers, $insert_top=FALSE)
304 global $CONFIG, $IMAP, $OUTPUT;
306 $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
307 $mbox = $IMAP->get_mailbox_name();
309 // show 'to' instead of from in sent messages
310 if (($mbox == $CONFIG['sent_mbox'] || $mbox == $CONFIG['drafts_mbox'])
311 && (($f = array_search('from', $a_show_cols)) !== false) && array_search('to', $a_show_cols) === false)
312 $a_show_cols[$f] = 'to';
314 $OUTPUT->command('set_message_coltypes', $a_show_cols);
316 // loop through message headers
317 foreach ($a_headers as $n => $header)
319 $a_msg_cols = array();
320 $a_msg_flags = array();
325 // format each col; similar as in rcmail_message_list()
326 foreach ($a_show_cols as $col)
328 if ($col=='from' || $col=='to')
329 $cont = Q(rcmail_address_string($header->$col, 3), 'show');
330 else if ($col=='subject')
332 $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
333 $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
334 $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
335 if (!$cont) $cont = Q(rcube_label('nosubject'));
336 $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont);
338 else if ($col=='size')
339 $cont = show_bytes($header->$col);
340 else if ($col=='date')
341 $cont = format_date($header->date);
343 $cont = Q($header->$col);
345 $a_msg_cols[$col] = $cont;
348 $a_msg_flags['deleted'] = $header->deleted ? 1 : 0;
349 $a_msg_flags['unread'] = $header->seen ? 0 : 1;
350 $a_msg_flags['replied'] = $header->answered ? 1 : 0;
351 $OUTPUT->command('add_message_row',
355 preg_match("/multipart\/m/i", $header->ctype),
361 // return an HTML iframe for loading mail content
362 function rcmail_messagecontent_frame($attrib)
366 if (empty($attrib['id']))
367 $attrib['id'] = 'rcmailcontentwindow';
369 // allow the following attributes to be added to the <iframe> tag
370 $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height', 'frameborder'));
371 $framename = $attrib['id'];
373 $out = sprintf('<iframe name="%s"%s></iframe>'."\n",
377 $OUTPUT->set_env('contentframe', $framename);
378 $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/blank.gif');
384 function rcmail_messagecount_display($attrib)
386 global $IMAP, $OUTPUT;
389 $attrib['id'] = 'rcmcountdisplay';
391 $OUTPUT->add_gui_object('countdisplay', $attrib['id']);
393 // allow the following attributes to be added to the <span> tag
394 $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
397 $out = '<span' . $attrib_str . '>';
398 $out .= rcmail_get_messagecount_text();
404 function rcmail_quota_display($attrib)
406 global $OUTPUT, $COMM_PATH;
409 $attrib['id'] = 'rcmquotadisplay';
411 $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
413 // allow the following attributes to be added to the <span> tag
414 $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
416 $out = '<span' . $attrib_str . '>';
417 $out .= rcmail_quota_content($attrib['display']);
423 function rcmail_quota_content($display)
425 global $IMAP, $COMM_PATH;
427 if (!$IMAP->get_capability('QUOTA'))
428 $quota_text = rcube_label('unknown');
429 else if ($quota = $IMAP->get_quota())
431 $quota_text = sprintf("%s / %s (%.0f%%)",
432 show_bytes($quota["used"] * 1024),
433 show_bytes($quota["total"] * 1024),
436 // show quota as image (by Brett Patterson)
437 if ($display == 'image' && function_exists('imagegif'))
439 $attrib = array('width' => 100, 'height' => 14);
440 $quota_text = sprintf('<img src="./bin/quotaimg.php?u=%s&q=%d&w=%d&h=%d" width="%d" height="%d" alt="%s" title="%s / %s" />',
441 $quota['used'], $quota['total'],
442 $attrib['width'], $attrib['height'],
443 $attrib['width'], $attrib['height'],
445 show_bytes($quota["used"] * 1024),
446 show_bytes($quota["total"] * 1024));
450 $quota_text = rcube_label('unlimited');
456 function rcmail_get_messagecount_text($count=NULL, $page=NULL)
458 global $IMAP, $MESSAGE;
460 if (isset($MESSAGE['index']))
462 return rcube_label(array('name' => 'messagenrof',
463 'vars' => array('nr' => $MESSAGE['index']+1,
464 'count' => $count!==NULL ? $count : $IMAP->messagecount())));
468 $page = $IMAP->list_page;
470 $start_msg = ($page-1) * $IMAP->page_size + 1;
471 $max = $count!==NULL ? $count : $IMAP->messagecount();
474 $out = rcube_label('mailboxempty');
476 $out = rcube_label(array('name' => 'messagesfromto',
477 'vars' => array('from' => $start_msg,
478 'to' => min($max, $start_msg + $IMAP->page_size - 1),
485 /* Stolen from Squirrelmail */
486 function sq_deent(&$attvalue, $regex, $hex=false)
489 preg_match_all($regex, $attvalue, $matches);
490 if (is_array($matches) && sizeof($matches[0]) > 0)
493 for ($i = 0; $i < sizeof($matches[0]); $i++)
495 $numval = $matches[1][$i];
497 $numval = hexdec($numval);
498 $repl{$matches[0][$i]} = chr($numval);
500 $attvalue = strtr($attvalue, $repl);
508 /* Stolen verbatim from Squirrelmail */
509 function sq_defang(&$attvalue)
511 /* Skip this if there aren't ampersands or backslashes. */
512 if ((strpos($attvalue, '&') === false) &&
513 (strpos($attvalue, '\\') === false))
519 $m = $m || sq_deent($attvalue, '/\�*(\d+);*/s');
520 $m = $m || sq_deent($attvalue, '/\�*((\d|[a-f])+);*/si', true);
521 $m = $m || sq_deent($attvalue, '/\\\\(\d+)/s', true);
522 } while ($m == true);
523 $attvalue = stripslashes($attvalue);
527 function rcmail_html_filter($html)
529 preg_match_all('/<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|\'.*?\'|[^\'">\s]+))?)+\s*|\s*)\/?>/', $html, $tags);
531 /* From Squirrelmail: Translate all dangerous Unicode or Shift_JIS characters which are accepted by
532 * IE as regular characters. */
533 $replace = array(array('ʟ', 'ʟ', /* L UNICODE IPA Extension */
534 'ʀ', 'ʀ', /* R UNICODE IPA Extension */
535 'ɴ', 'ɴ', /* N UNICODE IPA Extension */
536 'E', 'E', /* Unicode FULLWIDTH LATIN CAPITAL LETTER E */
537 'e', 'e', /* Unicode FULLWIDTH LATIN SMALL LETTER E */
538 'X', 'X', /* Unicode FULLWIDTH LATIN CAPITAL LETTER X */
539 'x', 'x', /* Unicode FULLWIDTH LATIN SMALL LETTER X */
540 'P', 'P', /* Unicode FULLWIDTH LATIN CAPITAL LETTER P */
541 'p', 'p', /* Unicode FULLWIDTH LATIN SMALL LETTER P */
542 'R', 'R', /* Unicode FULLWIDTH LATIN CAPITAL LETTER R */
543 'r', 'r', /* Unicode FULLWIDTH LATIN SMALL LETTER R */
544 'S', 'S', /* Unicode FULLWIDTH LATIN CAPITAL LETTER S */
545 's', 's', /* Unicode FULLWIDTH LATIN SMALL LETTER S */
546 'I', 'I', /* Unicode FULLWIDTH LATIN CAPITAL LETTER I */
547 'i', 'i', /* Unicode FULLWIDTH LATIN SMALL LETTER I */
548 'O', 'O', /* Unicode FULLWIDTH LATIN CAPITAL LETTER O */
549 'o', 'o', /* Unicode FULLWIDTH LATIN SMALL LETTER O */
550 'N', 'N', /* Unicode FULLWIDTH LATIN CAPITAL LETTER N */
551 'n', 'n', /* Unicode FULLWIDTH LATIN SMALL LETTER N */
552 'L', 'L', /* Unicode FULLWIDTH LATIN CAPITAL LETTER L */
553 'l', 'l', /* Unicode FULLWIDTH LATIN SMALL LETTER L */
554 'U', 'U', /* Unicode FULLWIDTH LATIN CAPITAL LETTER U */
555 'u', 'u', /* Unicode FULLWIDTH LATIN SMALL LETTER U */
556 'ⁿ', 'ⁿ' , /* Unicode SUPERSCRIPT LATIN SMALL LETTER N */
557 "\xEF\xBC\xA5", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER E */
558 /* in unicode this is some Chinese char range */
559 "\xEF\xBD\x85", /* Shift JIS FULLWIDTH LATIN SMALL LETTER E */
560 "\xEF\xBC\xB8", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER X */
561 "\xEF\xBD\x98", /* Shift JIS FULLWIDTH LATIN SMALL LETTER X */
562 "\xEF\xBC\xB0", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER P */
563 "\xEF\xBD\x90", /* Shift JIS FULLWIDTH LATIN SMALL LETTER P */
564 "\xEF\xBC\xB2", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER R */
565 "\xEF\xBD\x92", /* Shift JIS FULLWIDTH LATIN SMALL LETTER R */
566 "\xEF\xBC\xB3", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER S */
567 "\xEF\xBD\x93", /* Shift JIS FULLWIDTH LATIN SMALL LETTER S */
568 "\xEF\xBC\xA9", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER I */
569 "\xEF\xBD\x89", /* Shift JIS FULLWIDTH LATIN SMALL LETTER I */
570 "\xEF\xBC\xAF", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER O */
571 "\xEF\xBD\x8F", /* Shift JIS FULLWIDTH LATIN SMALL LETTER O */
572 "\xEF\xBC\xAE", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER N */
573 "\xEF\xBD\x8E", /* Shift JIS FULLWIDTH LATIN SMALL LETTER N */
574 "\xEF\xBC\xAC", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER L */
575 "\xEF\xBD\x8C", /* Shift JIS FULLWIDTH LATIN SMALL LETTER L */
576 "\xEF\xBC\xB5", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER U */
577 "\xEF\xBD\x95", /* Shift JIS FULLWIDTH LATIN SMALL LETTER U */
578 "\xE2\x81\xBF", /* Shift JIS FULLWIDTH SUPERSCRIPT N */
579 "\xCA\x9F", /* L UNICODE IPA Extension */
580 "\xCA\x80", /* R UNICODE IPA Extension */
581 "\xC9\xB4"), /* N UNICODE IPA Extension */
582 array('l', 'l', 'r', 'r', 'n', 'n', 'E', 'E', 'e', 'e', 'X', 'X', 'x', 'x',
583 'P', 'P', 'p', 'p', 'R', 'R', 'r', 'r', 'S', 'S', 's', 's', 'I', 'I',
584 'i', 'i', 'O', 'O', 'o', 'o', 'N', 'N', 'n', 'n', 'L', 'L', 'l', 'l',
585 'U', 'U', 'u', 'u', 'n', 'n', 'E', 'e', 'X', 'x', 'P', 'p', 'R', 'r',
586 'S', 's', 'I', 'i', 'O', 'o', 'N', 'n', 'L', 'l', 'U', 'u', 'n', 'l', 'r', 'n'));
587 if ((count($tags)>3) && (count($tags[3])>0))
588 foreach ($tags[3] as $nr=>$value)
590 /* Remove comments */
591 $newvalue = preg_replace('/(\/\*.*\*\/)/','$2',$value);
592 /* Translate dangerous characters */
593 $newvalue = str_replace($replace[0], $replace[1], $newvalue);
594 sq_defang($newvalue);
595 /* Rename dangerous CSS */
596 $newvalue = preg_replace('/expression/i', 'idiocy', $newvalue);
597 $newvalue = preg_replace('/url/i', 'idiocy', $newvalue);
598 $newattrs = preg_replace('/'.preg_quote($value, '/').'$/', $newvalue, $tags[1][$nr]);
599 $newtag = preg_replace('/'.preg_quote($tags[1][$nr], '/').'/', $newattrs, $tags[0][$nr]);
600 $html = preg_replace('/'.preg_quote($tags[0][$nr], '/').'/', $newtag, $html);
606 function rcmail_print_body($part, $safe=FALSE, $plain=FALSE)
608 global $IMAP, $REMOTE_OBJECTS;
610 $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body;
612 // convert html to text/plain
613 if ($part->ctype_secondary=='html' && $plain)
615 $txt = new html2text($body, false, true);
616 $body = $txt->get_text();
617 $part->ctype_secondary = 'plain';
621 if ($part->ctype_secondary=='html')
623 // remove charset specification in HTML message
624 $body = preg_replace('/charset=[a-z0-9\-]+/i', '', $body);
626 if (!$safe) // remove remote images and scripts
628 $remote_patterns = array('/<img\s+(.*)src=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
629 '/(src|background)=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
630 '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
631 '/(<link.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
632 '/url\s*\(["\']?([hftps]{3,5}:\/{2}[^"\'\s]+)["\']?\)/i',
633 '/url\s*\(["\']?([\.\/]+[^"\'\s]+)["\']?\)/i',
634 '/<script.+<\/script>/Umis');
636 $remote_replaces = array('<img \\1src=\\2./program/blocked.gif\\4',
644 // set flag if message containes remote obejcts that where blocked
645 foreach ($remote_patterns as $pattern)
647 if (preg_match($pattern, $body))
649 $REMOTE_OBJECTS = TRUE;
654 $body = preg_replace($remote_patterns, $remote_replaces, $body);
657 return Q(rcmail_html_filter($body), 'show', FALSE);
661 if ($part->ctype_secondary=='enriched')
663 return Q(enriched_to_html($body), 'show');
667 // make links and email-addresses clickable
668 $convert_patterns = $convert_replaces = $replace_strings = array();
670 $url_chars = 'a-z0-9_\-\+\*\$\/&%=@#:;';
671 $url_chars_within = '\?\.~,!';
673 $convert_patterns[] = "/([\w]+):\/\/([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
674 $convert_replaces[] = "rcmail_str_replacement('<a href=\"\\1://\\2\" target=\"_blank\">\\1://\\2</a>', \$replace_strings)";
676 $convert_patterns[] = "/([^\/:]|\s)(www\.)([a-z0-9\-]{2,}[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
677 $convert_replaces[] = "rcmail_str_replacement('\\1<a href=\"http://\\2\\3\" target=\"_blank\">\\2\\3</a>', \$replace_strings)";
679 $convert_patterns[] = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/ie';
680 $convert_replaces[] = "rcmail_str_replacement('<a href=\"mailto:\\1\" onclick=\"return ".JS_OBJECT_NAME.".command(\'compose\',\'\\1\',this)\">\\1</a>', \$replace_strings)";
682 if ($part->ctype_parameters['format'] != 'flowed')
683 $body = wordwrap(trim($body), 80);
685 $body = preg_replace($convert_patterns, $convert_replaces, $body);
687 // split body into single lines
688 $a_lines = preg_split('/\r?\n/', $body);
691 // colorize quoted parts
692 for($n=0; $n<sizeof($a_lines); $n++)
694 $line = $a_lines[$n];
698 if (preg_match('/^(>+\s*)+/', $line, $regs))
700 $q = strlen(preg_replace('/\s/', '', $regs[0]));
701 $line = substr($line, strlen($regs[0]));
703 if ($q > $quote_level)
704 $quotation = str_repeat('<blockquote>', $q - $quote_level);
705 else if ($q < $quote_level)
706 $quotation = str_repeat("</blockquote>", $quote_level - $q);
708 else if ($quote_level > 0)
709 $quotation = str_repeat("</blockquote>", $quote_level);
712 $a_lines[$n] = $quotation . Q($line, 'replace', FALSE);
715 // insert the links for urls and mailtos
716 $body = preg_replace("/##string_replacement\{([0-9]+)\}##/e", "\$replace_strings[\\1]", join("\n", $a_lines));
718 return "<div class=\"pre\">".$body."\n</div>";
724 // add a string to the replacement array and return a replacement string
725 function rcmail_str_replacement($str, &$rep)
728 $rep[$count] = stripslashes($str);
729 return "##string_replacement{".($count++)."}##";
733 function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE)
736 static $sa_inline_objects = array();
738 // arguments are: (bool)$prefer_html, (string)$get_url
741 $a_attachments = array();
742 $a_return_parts = array();
745 $message_ctype_primary = strtolower($structure->ctype_primary);
746 $message_ctype_secondary = strtolower($structure->ctype_secondary);
748 // show message headers
749 if ($recursive && is_array($structure->headers) && isset($structure->headers['subject']))
752 $c->type = 'headers';
753 $c->headers = &$structure->headers;
754 $a_return_parts[] = $c;
757 // print body if message doesn't have multiple parts
758 if ($message_ctype_primary=='text')
760 $structure->type = 'content';
761 $a_return_parts[] = &$structure;
764 // message contains alternative parts
765 else if ($message_ctype_primary=='multipart' && $message_ctype_secondary=='alternative' && is_array($structure->parts))
767 // get html/plaintext parts
768 $plain_part = $html_part = $print_part = $related_part = NULL;
770 foreach ($structure->parts as $p => $sub_part)
772 $rel_parts = $attachmnts = null;
773 $sub_ctype_primary = strtolower($sub_part->ctype_primary);
774 $sub_ctype_secondary = strtolower($sub_part->ctype_secondary);
776 // check if sub part is
777 if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='plain')
779 else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='html')
781 else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='enriched')
783 else if ($sub_ctype_primary=='multipart' && ($sub_ctype_secondary=='related' || $sub_ctype_secondary=='mixed'))
787 // parse related part (alternative part could be in here)
788 if ($related_part!==NULL)
790 list($rel_parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE);
791 $a_attachments = array_merge($a_attachments, $attachmnts);
794 // merge related parts if any
795 if ($rel_parts && $prefer_html && !$html_part)
796 $a_return_parts = array_merge($a_return_parts, $rel_parts);
798 // choose html/plain part to print
799 else if ($html_part!==NULL && $prefer_html)
800 $print_part = &$structure->parts[$html_part];
801 else if ($enriched_part!==NULL)
802 $print_part = &$structure->parts[$enriched_part];
803 else if ($plain_part!==NULL)
804 $print_part = &$structure->parts[$plain_part];
807 if (is_object($print_part))
809 $print_part->type = 'content';
810 $a_return_parts[] = $print_part;
812 // show plaintext warning
813 else if ($html_part!==NULL && empty($a_return_parts))
816 $c->type = 'content';
817 $c->body = rcube_label('htmlmessage');
818 $c->ctype_primary = 'text';
819 $c->ctype_secondary = 'plain';
821 $a_return_parts[] = $c;
824 // add html part as attachment
825 if ($html_part!==NULL && $structure->parts[$html_part]!==$print_part)
827 $html_part = &$structure->parts[$html_part];
828 $html_part->filename = rcube_label('htmlmessage');
829 $html_part->mimetype = 'text/html';
831 $a_attachments[] = $html_part;
835 // message contains multiple parts
836 else if (is_array($structure->parts) && !empty($structure->parts))
838 for ($i=0; $i<count($structure->parts); $i++)
840 $mail_part = &$structure->parts[$i];
841 $primary_type = strtolower($mail_part->ctype_primary);
842 $secondary_type = strtolower($mail_part->ctype_secondary);
844 // multipart/alternative
845 if ($primary_type=='multipart')
847 list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
849 $a_return_parts = array_merge($a_return_parts, $parts);
850 $a_attachments = array_merge($a_attachments, $attachmnts);
853 // part text/[plain|html] OR message/delivery-status
854 else if (($primary_type=='text' && ($secondary_type=='plain' || $secondary_type=='html') && $mail_part->disposition!='attachment') ||
855 ($primary_type=='message' && ($secondary_type=='delivery-status' || $secondary_type=='disposition-notification')))
857 $mail_part->type = 'content';
858 $a_return_parts[] = $mail_part;
862 else if ($primary_type=='message')
864 list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
866 $a_return_parts = array_merge($a_return_parts, $parts);
867 $a_attachments = array_merge($a_attachments, $attachmnts);
870 // ignore "virtual" protocol parts
871 else if ($primary_type=='protocol')
874 // part is file/attachment
875 else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] ||
876 (empty($mail_part->disposition) && $mail_part->filename))
878 // skip apple resource forks
879 if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile')
882 // part belongs to a related message
883 if ($message_ctype_secondary=='related' && $mail_part->headers['content-id'])
885 $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
886 $sa_inline_objects[] = $mail_part;
888 // is regular attachment
891 if (!$mail_part->filename)
892 $mail_part->filename = 'Part '.$mail_part->mime_id;
893 $a_attachments[] = $mail_part;
898 // if this was a related part try to resolve references
899 if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects))
901 $a_replaces = array();
903 foreach ($sa_inline_objects as $inline_object)
904 $a_replaces['cid:'.$inline_object->content_id] = htmlspecialchars(sprintf($get_url, $inline_object->mime_id));
906 // add replace array to each content part
907 // (will be applied later when part body is available)
908 for ($i=0; $i<count($a_return_parts); $i++)
910 if ($a_return_parts[$i]->type=='content')
911 $a_return_parts[$i]->replaces = $a_replaces;
916 // message is single part non-text
917 else if ($structure->filename)
918 $a_attachments[] = $structure;
920 return array($a_return_parts, $a_attachments);
926 // return table with message headers
927 function rcmail_message_headers($attrib, $headers=NULL)
929 global $IMAP, $OUTPUT, $MESSAGE;
932 // keep header table attrib
933 if (is_array($attrib) && !$sa_attrib)
934 $sa_attrib = $attrib;
935 else if (!is_array($attrib) && is_array($sa_attrib))
936 $attrib = $sa_attrib;
939 if (!isset($MESSAGE))
942 // get associative array of headers object
944 $headers = is_object($MESSAGE['headers']) ? get_object_vars($MESSAGE['headers']) : $MESSAGE['headers'];
948 // allow the following attributes to be added to the <table> tag
949 $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
950 $out = '<table' . $attrib_str . ">\n";
952 // show these headers
953 $standard_headers = array('subject', 'from', 'organization', 'to', 'cc', 'bcc', 'reply-to', 'date');
955 foreach ($standard_headers as $hkey)
957 if (!$headers[$hkey])
960 if ($hkey=='date' && !empty($headers[$hkey]))
961 $header_value = format_date(strtotime($headers[$hkey]));
962 else if (in_array($hkey, array('from', 'to', 'cc', 'bcc', 'reply-to')))
963 $header_value = Q(rcmail_address_string($headers[$hkey], NULL, $attrib['addicon']), 'show');
965 $header_value = Q(rcube_imap::decode_mime_string($headers[$hkey], $headers['charset']));
968 $out .= '<td class="header-title">'.Q(rcube_label($hkey)).": </td>\n";
969 $out .= '<td class="'.$hkey.'" width="90%">'.$header_value."</td>\n</tr>";
973 $out .= "\n</table>\n\n";
975 return $header_count ? $out : '';
980 function rcmail_message_body($attrib)
982 global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $GET_URL, $REMOTE_OBJECTS;
984 if (!is_array($MESSAGE['parts']) && !$MESSAGE['body'])
988 $attrib['id'] = 'rcmailMsgBody';
990 $safe_mode = $MESSAGE['is_safe'] || intval($_GET['_safe']);
991 $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
992 $out = '<div '. $attrib_str . ">\n";
994 $header_attrib = array();
995 foreach ($attrib as $attr => $value)
996 if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs))
997 $header_attrib[$regs[1]] = $value;
1000 // this is an ecrypted message
1001 // -> create a plaintext body with the according message
1002 if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted')
1005 $p->type = 'content';
1006 $p->ctype_primary = 'text';
1007 $p->ctype_secondary = 'plain';
1008 $p->body = rcube_label('encryptedmessage');
1009 $MESSAGE['parts'][0] = $p;
1012 if ($MESSAGE['parts'])
1014 foreach ($MESSAGE['parts'] as $i => $part)
1016 if ($part->type=='headers')
1017 $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers);
1018 else if ($part->type=='content')
1020 if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset']))
1021 $part->ctype_parameters['charset'] = $MESSAGE['headers']->charset;
1023 // fetch part if not available
1024 if (!isset($part->body))
1025 $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part);
1027 $body = rcmail_print_body($part, $safe_mode, !$CONFIG['prefer_html']);
1028 $out .= '<div class="message-part">';
1030 if ($part->ctype_secondary != 'plain')
1031 $out .= rcmail_sanitize_html($body, $attrib['id']);
1040 $out .= $MESSAGE['body'];
1043 $ctype_primary = strtolower($MESSAGE['structure']->ctype_primary);
1044 $ctype_secondary = strtolower($MESSAGE['structure']->ctype_secondary);
1046 // list images after mail body
1047 if (get_boolean($attrib['showimages']) && $ctype_primary=='multipart' &&
1048 !empty($MESSAGE['attachments']) && !strstr($message_body, '<html') && strlen($GET_URL))
1050 foreach ($MESSAGE['attachments'] as $attach_prop)
1052 if (strpos($attach_prop->mimetype, 'image/')===0)
1053 $out .= sprintf("\n<hr />\n<p align=\"center\"><img src=\"%s&_part=%s\" alt=\"%s\" title=\"%s\" /></p>\n",
1054 htmlspecialchars($GET_URL), $attach_prop->mime_id,
1055 $attach_prop->filename,
1056 $attach_prop->filename);
1060 // tell client that there are blocked remote objects
1061 if ($REMOTE_OBJECTS && !$safe_mode)
1062 $OUTPUT->set_env('blockedobjects', true);
1070 // modify a HTML message that it can be displayed inside a HTML page
1071 function rcmail_sanitize_html($body, $container_id)
1073 // remove any null-byte characters before parsing
1074 $body = preg_replace('/\x00/', '', $body);
1077 $last_style_pos = 0;
1078 $body_lc = strtolower($body);
1080 // check for <base href>
1081 if (preg_match(($base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'), $body, $base_regs))
1082 $base_url = $base_regs[2];
1085 while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
1087 $pos = strpos($body_lc, '>', $pos)+1;
1089 // replace all css definitions with #container [def]
1090 $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id, $base_url);
1092 $body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
1093 $body_lc = strtolower($body);
1094 $last_style_pos = $pos2;
1098 // remove SCRIPT tags
1099 foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag)
1101 while (($pos = strpos($body_lc, '<'.$tag)) && (($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)) || ($pos3 = strpos($body_lc, '>', $pos))))
1103 $end = $pos2 ? $pos2 + strlen('</'.$tag.'>') : $pos3 + 1;
1104 $body = substr($body, 0, $pos) . substr($body, $end, strlen($body)-$end);
1105 $body_lc = strtolower($body);
1109 // replace event handlers on any object
1110 while ($body != $prev_body)
1113 $body = preg_replace('/(<[^!][^>]*\s)on(?:load|unload|click|dblclick|mousedown|mouseup|mouseover|mousemove|mouseout|focus|blur|keypress|keydown|keyup|submit|reset|select|change)=([^>]+>)/im', '$1__removed=$2', $body);
1114 $body = preg_replace('/(<[^!][^>]*\shref=["\']?)(javascript:)([^>]*?>)/im', '$1null:$3', $body);
1117 // resolve <base href>
1120 $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body);
1121 $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body);
1122 $body = preg_replace($base_reg, '', $body);
1125 // modify HTML links to open a new window if clicked
1126 $body = preg_replace('/<(a|link)\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1','\\2', '$container_id');", $body);
1128 // add comments arround html and other tags
1129 $out = preg_replace(array(
1131 '/(<\/?html[^>]*>)/i',
1132 '/(<\/?head[^>]*>)/i',
1133 '/(<title[^>]*>.*<\/title>)/Ui',
1134 '/(<\/?meta[^>]*>)/i'),
1138 $out = preg_replace(
1144 '<div class="rcmBody"\\1>',
1149 // quote <? of php and xml files that are specified as text/html
1150 $out = preg_replace(array('/<\?/', '/\?>/'), array('<?', '?>'), $out);
1156 // parse link attributes and set correct target
1157 function rcmail_alter_html_link($tag, $attrs, $container_id)
1159 $in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in);
1160 $attrib = parse_attrib_string($attrs);
1162 if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href']))
1163 $attrib['href'] = "./bin/modcss.php?u=" . urlencode($attrib['href']) . "&c=" . urlencode($container_id);
1165 else if (stristr((string)$attrib['href'], 'mailto:'))
1166 $attrib['onclick'] = sprintf(
1167 "return %s.command('compose','%s',this)",
1169 JQ(substr($attrib['href'], 7)));
1171 else if (!empty($attrib['href']) && $attrib['href']{0}!='#')
1172 $attrib['target'] = '_blank';
1174 return "<$tag" . create_attrib_string($attrib, array('href','name','target','onclick','id','class','style','title','rel','type','media')) . ' />';
1178 function rcmail_has_html_part($message_parts)
1180 if (!is_array($message_parts))
1183 // check all message parts
1184 foreach ($message_parts as $pid => $part)
1186 $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1187 if ($mimetype=='text/html')
1196 // return first HTML part of a message
1197 function rcmail_first_html_part($message_struct)
1201 if (!is_array($message_struct['parts']))
1206 // check all message parts
1207 foreach ($message_struct['parts'] as $pid => $part)
1209 $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1210 if ($mimetype=='text/html')
1212 $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1218 // remove special chars encoding
1219 //$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1220 //$html_part = strtr($html_part, $trans);
1229 // return first text part of a message
1230 function rcmail_first_text_part($message_struct)
1234 if (empty($message_struct['parts']))
1235 return $message_struct['UID'] ? $IMAP->get_body($message_struct['UID']) : false;
1237 // check all message parts
1238 foreach ($message_struct['parts'] as $pid => $part)
1240 $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1242 if ($mimetype=='text/plain')
1243 return $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1245 else if ($mimetype=='text/html')
1247 $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1249 // remove special chars encoding
1250 $trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1251 $html_part = strtr($html_part, $trans);
1253 // create instance of html2text class
1254 $txt = new html2text($html_part);
1255 return $txt->get_text();
1263 // decode address string and re-format it as HTML links
1264 function rcmail_address_string($input, $max=NULL, $addicon=NULL)
1266 global $IMAP, $PRINT_MODE, $CONFIG, $OUTPUT, $EMAIL_ADDRESS_PATTERN;
1268 $a_parts = $IMAP->decode_address_list($input);
1270 if (!sizeof($a_parts))
1273 $c = count($a_parts);
1277 foreach ($a_parts as $part)
1281 $out .= sprintf('%s <%s>', Q($part['name']), $part['mailto']);
1282 else if (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto']))
1284 $out .= sprintf('<a href="mailto:%s" onclick="return %s.command(\'compose\',\'%s\',this)" class="rcmContactAddress" title="%s">%s</a>',
1287 JQ($part['mailto']),
1292 $out .= sprintf(' <a href="#add" onclick="return %s.command(\'add-contact\',\'%s\',this)" title="%s"><img src="%s%s" alt="add" border="0" /></a>',
1294 urlencode($part['string']),
1295 rcube_label('addtoaddressbook'),
1296 $CONFIG['skin_path'],
1302 $out .= Q($part['name']);
1303 if ($part['mailto'])
1304 $out .= (strlen($out) ? ' ' : '') . sprintf('<%s>', Q($part['mailto']));
1308 $out .= ','.($max ? ' ' : ' ');
1310 if ($max && $j==$max && $c>$j)
1321 function rcmail_message_part_controls()
1323 global $CONFIG, $IMAP, $MESSAGE;
1325 $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC));
1326 if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$part])
1329 $part = $MESSAGE['parts'][$part];
1330 $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary'));
1331 $out = '<table '. $attrib_str . ">\n";
1333 if ($part->filename)
1335 $out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
1336 Q(rcube_label('filename')),
1338 str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
1339 Q(rcube_label('download')));
1343 $out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n",
1344 Q(rcube_label('filesize')),
1345 show_bytes($part->size));
1347 $out .= "\n</table>";
1354 function rcmail_message_part_frame($attrib)
1358 $part = $MESSAGE['parts'][asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))];
1359 $ctype_primary = strtolower($part->ctype_primary);
1361 $attrib['src'] = Q('./?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']));
1363 $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height'));
1364 $out = '<iframe '. $attrib_str . "></iframe>";
1370 // clear message composing settings
1371 function rcmail_compose_cleanup()
1373 if (!isset($_SESSION['compose']))
1376 // remove attachment files from temp dir
1377 if (is_array($_SESSION['compose']['attachments']))
1378 foreach ($_SESSION['compose']['attachments'] as $attachment)
1379 @unlink($attachment['path']);
1381 unset($_SESSION['compose']);
1386 * Send the given message compose object using the configured method
1388 function rcmail_deliver_message(&$message, $from, $mailto)
1392 $headers = $message->headers();
1393 $msg_body = $message->get();
1395 // send thru SMTP server using custom SMTP library
1396 if ($CONFIG['smtp_server'])
1398 // generate list of recipients
1399 $a_recipients = array($mailto);
1401 if (strlen($headers['Cc']))
1402 $a_recipients[] = $headers['Cc'];
1403 if (strlen($headers['Bcc']))
1404 $a_recipients[] = $headers['Bcc'];
1406 // clean Bcc from header for recipients
1407 $send_headers = $headers;
1408 unset($send_headers['Bcc']);
1411 $smtp_response = array();
1412 $sent = smtp_mail($from, $a_recipients, ($foo = $message->txtHeaders($send_headers)), $msg_body, $smtp_response);
1416 raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__,
1417 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE);
1420 // send mail using PHP's mail() function
1423 // unset some headers because they will be added by the mail() function
1424 $headers_enc = $message->headers($headers);
1425 $headers_php = $message->_headers;
1426 unset($headers_php['To'], $headers_php['Subject']);
1428 // reset stored headers and overwrite
1429 $message->_headers = array();
1430 $header_str = $message->txtHeaders($headers_php);
1432 if (ini_get('safe_mode'))
1433 $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str);
1435 $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str, "-f$from");
1438 if ($sent) // remove MDN headers after sending
1439 unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
1441 $message->_headers = array();
1442 $message->headers($headers);
1448 function rcmail_send_mdn($uid)
1450 global $CONFIG, $USER, $IMAP;
1452 $message = array('UID' => $uid);
1453 $message['headers'] = $IMAP->get_headers($message['UID']);
1454 $message['subject'] = rcube_imap::decode_mime_string($message['headers']->subject, $message['headers']->charset);
1456 if ($message['headers']->mdn_to && !$message['headers']->mdn_sent)
1458 $identity = $USER->get_identity();
1459 $sender = format_email_recipient($identity['email'], $identity['name']);
1460 $recipient = array_shift($IMAP->decode_address_list($message['headers']->mdn_to));
1461 $mailto = $recipient['mailto'];
1463 $compose = new rc_mail_mime(rcmail_header_delm());
1464 $compose->setParam(array(
1465 'text_encoding' => 'quoted-printable',
1466 'html_encoding' => 'quoted-printable',
1467 'head_encoding' => 'quoted-printable',
1468 'head_charset' => RCMAIL_CHARSET,
1469 'html_charset' => RCMAIL_CHARSET,
1470 'text_charset' => RCMAIL_CHARSET,
1473 // compose headers array
1475 'Date' => date('r'),
1477 'To' => $message['headers']->mdn_to,
1478 'Subject' => rcube_label('receiptread') . ': ' . $message['subject'],
1479 'Message-ID' => sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), rcmail_mail_domain($_SESSION['imap_host'])),
1480 'X-Sender' => $identity['email'],
1481 'Content-Type' => 'multipart/report; report-type=disposition-notification',
1484 if (!empty($CONFIG['useragent']))
1485 $headers['User-Agent'] = $CONFIG['useragent'];
1487 $body = rcube_label("yourmessage") . "\r\n\r\n" .
1488 "\t" . rcube_label("to") . ': ' . rcube_imap::decode_mime_string($message['headers']->to, $message['headers']->charset) . "\r\n" .
1489 "\t" . rcube_label("subject") . ': ' . $message['subject'] . "\r\n" .
1490 "\t" . rcube_label("sent") . ': ' . format_date(strtotime($message['headers']->date), $CONFIG['date_long']) . "\r\n" .
1491 "\r\n" . rcube_label("receiptnote") . "\r\n";
1493 $ua = !empty($CONFIG['useragent']) ? $CONFIG['useragent'] : "RoundCube Webmail (Version ".RCMAIL_VERSION.")";
1494 $report = "Reporting-UA: $ua\r\n";
1496 if ($message['headers']->to)
1497 $report .= "Original-Recipient: {$message['headers']->to}\r\n";
1499 $report .= "Final-Recipient: rfc822; {$identity['email']}\r\n" .
1500 "Original-Message-ID: {$message['headers']->messageID}\r\n" .
1501 "Disposition: manual-action/MDN-sent-manually; displayed\r\n";
1503 $compose->headers($headers, true);
1504 $compose->setTXTBody($body);
1505 $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline');
1507 $sent = rcmail_deliver_message($compose, $identity['email'], $mailto);
1511 $IMAP->set_flag($message['UID'], 'MDNSENT');
1520 // register UI objects
1521 $OUTPUT->add_handlers(array(
1522 'mailboxlist' => 'rcmail_mailbox_list',
1523 'messages' => 'rcmail_message_list',
1524 'messagecountdisplay' => 'rcmail_messagecount_display',
1525 'quotadisplay' => 'rcmail_quota_display',
1526 'messageheaders' => 'rcmail_message_headers',
1527 'messagebody' => 'rcmail_message_body',
1528 'messagecontentframe' => 'rcmail_messagecontent_frame',
1529 'messagepartframe' => 'rcmail_message_part_frame',
1530 'messagepartcontrols' => 'rcmail_message_part_controls',
1531 'searchform' => 'rcmail_search_form'