source: subversion/branches/devel-vnext/program/steps/mail/func.inc @ 629

Last change on this file since 629 was 629, checked in by till, 6 years ago

# several smaller bugfixes (mostly introduced when i implemented the registry)
# fixed trash deletion etc.

  • removed some of the debug logging
File size: 62.9 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/steps/mail/func.inc                                           |
6 |                                                                       |
7 | This file is part of the RoundCube Webmail client                     |
8 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Provide webmail functionality and GUI objects                       |
13 |                                                                       |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16 +-----------------------------------------------------------------------+
17
18 $Id: func.inc 575 2007-05-18 12:35:28Z thomasb $
19
20*/
21
22require_once 'lib/html2text.inc';
23require_once 'lib/enriched.inc';
24
25
26$EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i';
27$registry = rc_registry::getInstance();
28$registry->set('EMAIL_ADDRESS_PATTERN', $EMAIL_ADDRESS_PATTERN, 'core');
29$CONFIG = $registry->get('CONFIG', 'core');
30$IMAP   = $registry->get('IMAP', 'core');
31$OUTPUT = $registry->get('OUTPUT', 'core');
32
33if (empty($_SESSION['mbox'])) {
34    $_SESSION['mbox'] = $IMAP->get_mailbox_name();
35}
36// set imap properties and session vars
37if ($mbox = rc_main::get_input_value('_mbox', RCUBE_INPUT_GPC)) {
38    $IMAP->set_mailbox($mbox);
39    $_SESSION['mbox'] = $mbox;
40}
41
42if (!empty($_GET['_page'])) {
43    $IMAP->set_page((int)$_GET['_page']);
44    $_SESSION['page'] = (int)$_GET['_page'];
45}
46
47// set mailbox to INBOX if not set
48if (empty($_SESSION['mbox'])) {
49    $_SESSION['mbox'] = $IMAP->get_mailbox_name();
50}
51// set default sort col/order to session
52if (!isset($_SESSION['sort_col'])) {
53    $_SESSION['sort_col'] = $CONFIG['message_sort_col'];
54}
55if (!isset($_SESSION['sort_order'])) {
56    $_SESSION['sort_order'] = $CONFIG['message_sort_order'];
57}
58// set message set for search result
59if (
60    !empty($_REQUEST['_search'])
61    && isset($_SESSION['search'][$_REQUEST['_search']])
62) {
63    $IMAP->set_search_set($_SESSION['search'][$_REQUEST['_search']]);
64}
65
66// define url for getting message parts
67if (strlen($_GET['_uid'])) {
68    $GET_URL = rc_main::rcmail_url(
69                'get',
70                array(
71                    '_mbox' => $IMAP->get_mailbox_name(),
72                    '_uid'  => rc_main::get_input_value('_uid', RCUBE_INPUT_GET)
73                )
74    );
75    $registry->set('GET_URL', $GET_URL, 'core');
76}
77
78// set current mailbox in client environment
79$OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name());
80$OUTPUT->set_env('quota', $IMAP->get_capability('quota'));
81
82if ($CONFIG['trash_mbox']) {
83    $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
84}
85if ($CONFIG['drafts_mbox']) {
86    $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
87}
88if ($CONFIG['junk_mbox']) {
89    $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']);
90}
91if (!$OUTPUT->ajax_call) {
92    rc_main::rcube_add_label('checkingmail');
93}
94
95// return the mailboxlist in HTML
96function rcmail_mailbox_list($attrib)
97{
98    $registry  = rc_registry::getInstance();
99    $IMAP      = $registry->get('IMAP', 'core');
100    $CONFIG    = $registry->get('CONFIG', 'core');
101    $OUTPUT    = $registry->get('OUTPUT', 'core');
102    $COMM_PATH = $registry->get('COMM_PATH', 'core');
103
104    $s_added_script = $registry->get('s_added_script', 'core');
105    if (is_null($s_added_script)) {
106        $s_added_script = FALSE;
107        $registry->get('s_added_script', $s_added_script);
108    }
109    $a_mailboxes = $registry->get('a_mailboxes', 'core');
110
111    // add some labels to client
112    rc_main::rcube_add_label('purgefolderconfirm');
113    rc_main::rcube_add_label('deletemessagesconfirm');
114
115    // $mboxlist_start = rcube_timer();
116
117    $type = $attrib['type'] ? $attrib['type'] : 'ul';
118    $add_attrib = $type=='select' ? array('style', 'class', 'id', 'name', 'onchange') :
119                                  array('style', 'class', 'id');
120
121    if ($type=='ul' && !$attrib['id']) {
122        $attrib['id'] = 'rcmboxlist';
123    }
124    // allow the following attributes to be added to the <ul> tag
125    $attrib_str = rc_main::create_attrib_string($attrib, $add_attrib);
126
127    $out = '<' . $type . $attrib_str . ">\n";
128
129    // add no-selection option
130    if ($type=='select' && $attrib['noselection']) {
131        $out .= sprintf(
132                    '<option value="0">%s</option>'."\n",
133                    rcube_label($attrib['noselection'])
134        );
135    }
136    // get mailbox list
137    $mbox_name = $IMAP->get_mailbox_name();
138
139    // for these mailboxes we have localized labels
140    $special_mailboxes = array('inbox', 'sent', 'drafts', 'trash', 'junk');
141
142
143    // build the folders tree
144    if (empty($a_mailboxes)) {
145        // get mailbox list
146        $a_folders = $IMAP->list_mailboxes();
147        $delimiter = $IMAP->get_hierarchy_delimiter();
148        $a_mailboxes = array();
149
150        // rcube_print_time($mboxlist_start, 'list_mailboxes()');
151
152        foreach ($a_folders as $folder) {
153            rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
154        }
155    }
156
157    //var_dump($a_mailboxes);
158
159    if ($type=='select') {
160        $out .= rcmail_render_folder_tree_select(
161                    $a_mailboxes,
162                    $special_mailboxes,
163                    $mbox_name,
164                    $attrib['maxlength']
165        );
166    }
167    else {
168        $out .= rcmail_render_folder_tree_html(
169                    $a_mailboxes,
170                    $special_mailboxes,
171                    $mbox_name,
172                    $attrib['maxlength']
173        );
174    }
175    $registry->set('a_mailboxes', $a_mailboxes);
176    // rcube_print_time($mboxlist_start, 'render_folder_tree()');
177
178
179    if ($type=='ul') {
180        $OUTPUT->add_gui_object('mailboxlist', $attrib['id']);
181    }
182    return $out . "</$type>";
183}
184
185
186
187
188// create a hierarchical array of the mailbox list
189function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
190{
191    $pos = strpos($folder, $delm);
192    if ($pos !== false) {
193        $subFolders = substr($folder, $pos+1);
194        $currentFolder = substr($folder, 0, $pos);
195    }
196    else {
197        $subFolders = false;
198        $currentFolder = $folder;
199    }
200
201    $path .= $currentFolder;
202
203    if (!isset($arrFolders[$currentFolder])) {
204        $arrFolders[$currentFolder] = array(
205                                        'id'      => $path,
206                                        'name'    => rc_main::rcube_charset_convert($currentFolder, 'UTF-7'),
207                                        'folders' => array()
208        );
209    }
210
211    if (!empty($subFolders)) {
212        rcmail_build_folder_tree(
213                $arrFolders[$currentFolder]['folders'],
214                $subFolders,
215                $delm,
216                $path.$delm
217        );
218    }
219}
220
221
222// return html for a structured list <ul> for the mailbox tree
223function rcmail_render_folder_tree_html(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
224{
225    $registry  = rc_registry::getInstance();
226    $IMAP      = $registry->get('IMAP', 'core');
227    $CONFIG    = $registry->get('CONFIG', 'core');
228    $OUTPUT    = $registry->get('OUTPUT', 'core');
229    $COMM_PATH = $registry->get('COMM_PATH', 'core');
230
231    $idx = 0;
232    $out = '';
233    foreach ($arrFolders as $key => $folder)
234    {
235        $zebra_class = ($nestLevel*$idx)%2 ? 'even' : 'odd';
236        $title = '';
237
238        $folder_lc = strtolower($folder['id']);
239        if (in_array($folder_lc, $special))
240            $foldername = rcube_label($folder_lc);
241        else {
242            $foldername = $folder['name'];
243
244            // shorten the folder name to a given length
245            if ($maxlength && $maxlength>1) {
246                $fname = abbrevate_string($foldername, $maxlength);
247                if ($fname != $foldername)
248                    $title = ' title="'.rc_main::Q($foldername).'"';
249                $foldername = $fname;
250            }
251        }
252
253        // add unread message count display
254        if ($unread_count = $IMAP->messagecount($folder['id'], 'RECENT', ($folder['id']==$mbox_name)))
255            $foldername .= sprintf(' (%d)', $unread_count);
256
257        // make folder name safe for ids and class names
258        $folder_id  = preg_replace('/[^A-Za-z0-9\-_]/', '', $folder['id']);
259        $class_name = preg_replace('/[^a-z0-9\-_]/', '', $folder_lc);
260
261        // set special class for Sent, Drafts, Trash and Junk
262        if ($folder['id']==$CONFIG['sent_mbox'])
263            $class_name = 'sent';
264        else if ($folder['id']==$CONFIG['drafts_mbox'])
265            $class_name = 'drafts';
266        else if ($folder['id']==$CONFIG['trash_mbox'])
267            $class_name = 'trash';
268        else if ($folder['id']==$CONFIG['junk_mbox'])
269            $class_name = 'junk';
270
271        $js_name = htmlspecialchars(rc_main::JQ($folder['id']));
272
273        $_string_out = '<li id="rcmli%s" class="mailbox %s %s%s%s"><a href="%s"';
274        $_string_out.= ' onclick="return %s.command(\'list\',\'%s\',this)"';
275        $_string_out.= ' onmouseover="return %s.focus_folder(\'%s\')"';
276        $_string_out.= ' onmouseout="return %s.unfocus_folder(\'%s\')"';
277        $_string_out.= ' onmouseup="return %s.folder_mouse_up(\'%s\')"%s>%s</a>';
278
279        $out .= sprintf(
280                    $_string_out,
281                    $folder_id,
282                    $class_name,
283                    $zebra_class,
284                    $unread_count ? ' unread' : '',
285                    $folder['id']==$mbox_name ? ' selected' : '',
286                    rc_main::Q(rc_main::rcmail_url('', array('_mbox' => $folder['id']))),
287                    JS_OBJECT_NAME,
288                    $js_name,
289                    JS_OBJECT_NAME,
290                    $js_name,
291                    JS_OBJECT_NAME,
292                    $js_name,
293                    JS_OBJECT_NAME,
294                    $js_name,
295                    $title,
296                    rc_main::Q($foldername)
297        );
298        /**
299         * Close <li> Element.
300         */
301        $out .= "</li>\n";
302
303        /**
304         * Append a new list if it has subfolders.
305         */
306        if (!empty($folder['folders'])) {
307            $out .= "\n<ul>\n";
308            $out .= rcmail_render_folder_tree_html($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1) . "</ul>\n";
309        }
310
311        $idx++;
312    }
313
314    return $out;
315}
316
317
318// return html for a flat list <select> for the mailbox tree
319function rcmail_render_folder_tree_select(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0)
320{
321    $registry  = rc_registry::getInstance();
322    $IMAP      = $registry->get('IMAP', 'core');
323    $OUTPUT    = $registry->get('OUTPUT', 'core');
324
325    $idx = 0;
326    $out = '';
327    foreach ($arrFolders as $key=>$folder) {
328        $folder_lc = strtolower($folder['id']);
329        if (in_array($folder_lc, $special))
330            $foldername = rcube_label($folder_lc);
331        else {
332            $foldername = $folder['name'];
333
334            // shorten the folder name to a given length
335            if ($maxlength && $maxlength>1)
336                $foldername = abbrevate_string($foldername, $maxlength);
337        }
338
339        $out .= sprintf(
340                    '<option value="%s">%s%s</option>'."\n",
341                    htmlspecialchars($folder['id']),
342                    str_repeat('&nbsp;', $nestLevel*4),
343                    rc_main::Q($foldername));
344
345    if (!empty($folder['folders']))
346      $out .= rcmail_render_folder_tree_select($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1);
347
348    $idx++;
349    }
350
351  return $out;
352  }
353
354
355/**
356 * rcmail_message_list
357 *
358 * return the message list as HTML table
359 *
360 * @todo   Changed icon > icon1/icon2
361 * @access public
362 * @param  array $attrib
363 * @return string
364 */
365function rcmail_message_list($attrib)
366{
367    $registry  = rc_registry::getInstance();
368    $IMAP      = $registry->get('IMAP', 'core');
369    $CONFIG    = $registry->get('CONFIG', 'core');
370    $COMM_PATH = $registry->get('COMM_PATH', 'core');
371    $OUTPUT    = $registry->get('OUTPUT', 'core');
372
373    $skin_path = $CONFIG['skin_path'];
374    $image_tag = '<img src="%s%s" alt="%s" border="0" />';
375
376    // check to see if we have some settings for sorting
377    $sort_col   = $_SESSION['sort_col'];
378    $sort_order = $_SESSION['sort_order'];
379
380    // add some labels to client
381    rc_main::rcube_add_label('from', 'to');
382
383    // get message headers
384    $a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order);
385
386    // add id to message list table if not specified
387    if (isset($attrib['id']) === false || empty($attrib['id']) === true) {
388        $attrib['id'] = 'rcubemessagelist';
389    }
390
391    // allow the following attributes to be added to the <table> tag
392    $attrib_str = rc_main::create_attrib_string(
393                        $attrib,
394                        array(
395                            'style', 'class', 'id',
396                            'cellpadding', 'cellspacing',
397                            'border', 'summary'
398                        )
399    );
400
401    $out = '<table' . $attrib_str . ">\n";
402
403
404    // define list of cols to be displayed
405    $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
406    $a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
407
408    $mbox = $IMAP->get_mailbox_name();
409
410    // show 'to' instead of from in sent messages
411    if (
412        ($mbox==$CONFIG['sent_mbox'] || $mbox==$CONFIG['drafts_mbox'])
413        && ($f = array_search('from', $a_show_cols))
414        && !array_search('to', $a_show_cols)
415    ) {
416        $a_show_cols[$f] = 'to';
417    }
418
419    // add col definition
420    $out .= '<colgroup>';
421    $out .= '<col class="icon" />';
422
423    foreach ($a_show_cols as $col) {
424        $out .= sprintf('<col class="%s" />', $col);
425    }
426
427    $out .= '<col class="icon" />';
428    $out .= "</colgroup>\n";
429
430    // add table title
431    $out .= '<thead><tr>' . "\n";
432    $out .= '<td class="icon1">&nbsp;</td>' . "\n";
433
434    $javascript = '';
435    foreach ($a_show_cols as $col) {
436        // get column name
437        $col_name = rc_main::Q(rcube_label($col));
438
439        // make sort links
440        $sort = '';
441        if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols)) {
442            // have buttons configured
443            if (
444                !empty($attrib['sortdescbutton'])
445                || !empty($attrib['sortascbutton'])
446            ) {
447                $sort = '&nbsp;&nbsp;';
448
449                // asc link
450                if (!empty($attrib['sortascbutton'])) {
451                    $sort .= $OUTPUT->button(
452                                array(
453                                    'command' => 'sort',
454                                    'prop' => $col.'_ASC',
455                                    'image' => $attrib['sortascbutton'],
456                                    'align' => 'absmiddle',
457                                    'title' => 'sortasc'
458                                )
459                    );
460                }
461
462                // desc link
463                if (!empty($attrib['sortdescbutton'])) {
464                    $sort .= $OUTPUT->button(array(
465                            'command' => 'sort',
466                            'prop' => $col.'_DESC',
467                            'image' => $attrib['sortdescbutton'],
468                            'align' => 'absmiddle',
469                            'title' => 'sortdesc'));
470                }
471            }
472            // just add a link tag to the header
473            else {
474                $col_name = sprintf(
475                            '<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
476                            JS_OBJECT_NAME,
477                            $col,
478                            rcube_label('sortby'),
479                            $col_name
480                );
481            }
482        }
483
484        $sort_class = $col==$sort_col ? " sorted$sort_order" : '';
485
486        // put it all together
487        $out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n";
488    }
489
490    $out.= '<td class="icon2">';
491    $out.= ($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '');
492    $out.= "</td>\n";
493    $out.= "</tr></thead>\n<tbody>\n";
494
495    // no messages in this mailbox
496    if (!sizeof($a_headers)) {
497        $out .= sprintf(
498                    '<tr><td colspan="%d">%s</td></tr>',
499                    sizeof($a_show_cols)+2,
500                    rc_main::Q(rcube_label('nomessagesfound')));
501    }
502
503
504    $a_js_message_arr = array();
505
506    // create row for each message
507    foreach ($a_headers as $i => $header) {
508
509
510
511        $message_icon = $attach_icon = '';
512        $js_row_arr = array();
513
514        /**
515         * @todo make those configurable.
516         * @ignore
517         */
518        $zebra_class = $i%2 ? '' : 'alt';
519
520        // set messag attributes to javascript array
521        if ($header->deleted) {
522            $js_row_arr['deleted'] = true;
523        }
524        if (!$header->seen) {
525            $js_row_arr['unread'] = true;
526        }
527        if ($header->answered) {
528            $js_row_arr['replied'] = true;
529        }
530
531        // set message icon
532        if ($attrib['deletedicon'] && $header->deleted) {
533            $message_icon = $attrib['deletedicon'];
534        }
535        elseif ($attrib['unreadicon'] && !$header->seen) {
536            $message_icon = $attrib['unreadicon'];
537        }
538        elseif ($attrib['repliedicon'] && $header->answered) {
539            $message_icon = $attrib['repliedicon'];
540        }
541        elseif ($attrib['messageicon']) {
542            $message_icon = $attrib['messageicon'];
543        }
544        // set attachment icon
545        if ($attrib['attachmenticon'] && preg_match("/multipart\/[mr]/i", $header->ctype)) {
546            $attach_icon = $attrib['attachmenticon'];
547        }
548        $out .= sprintf(
549                    '<tr id="rcmrow%d" class="message%s%s %s">'."\n",
550                    $header->uid,
551                    $header->seen ? '' : ' unread',
552                    $header->deleted ? ' deleted' : '',
553                    $zebra_class
554        );
555        /**
556         * @todo icon > icon1
557         */
558        $out .= sprintf(
559                    '<td rev="%s" class="icon1">%s</td>' . "\n",
560                    $header->seen,
561                    $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : ''
562        );
563
564        // format each col
565        foreach ($a_show_cols as $col) {
566
567
568            $cont_normalized = '';
569            $cont            = '';
570
571            if ($col=='from' || $col=='to') {
572                $cont_normalized.= $header->$col;
573                $cont           .= rc_main::Q(
574                                    rcmail_address_string(
575                                        $header->$col,
576                                        3,
577                                        $attrib['addicon']
578                                    ),
579                                    'show'
580                );
581            }
582            elseif ($col=='subject') {
583                $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
584                $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
585                $cont = rc_main::Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
586                if (empty($cont)) {
587                    $cont_normalized.= '';
588                    $cont           .= rc_main::Q(rcube_label('nosubject'));
589                }
590                else {
591                    $cont_normalized.= $cont;
592                }
593                $cont = sprintf(
594                            '<a href="%s" onclick="return false">%s</a>',
595                            rc_main::Q(
596                                rc_main::rcmail_url(
597                                    $action,
598                                    array($uid_param=>$header->uid, '_mbox'=>$mbox)
599                                )
600                            ),
601                            $cont
602                );
603            }
604            else if ($col=='size') {
605                $cont_normalized.= $header->$col;
606                $cont            = show_bytes($header->$col);
607            }
608            else if ($col=='date') {
609                $cont_normalized.= @strtotime($header->date);
610                $cont            = rc_main::format_date($header->date);
611            }
612            else {
613                $cont_normalized.= $header->$col;
614                $cont            = rc_main::Q($header->$col);
615            }
616            /**
617             * Macbay Skin specific, maybe we can keep it.
618             */
619            if (in_array($col, array('from','subject'))) {
620                $cont = '<span>' . $cont . '</span>';
621            }
622            $out .= '<td rev="' . rcmail_normalize_content($cont_normalized) . '"';
623            $out .= ' class="' . $col . '">' . $cont . "</td>\n";
624        }
625
626        /**
627         * @todo icon > icon2
628         */
629        $out .= sprintf(
630                    '<td rev="%s" class="icon2">%s</td>' . "\n",
631                    $attach_icon ? '1' : '',
632                    $attach_icon ? sprintf($image_tag, $skin_path, $attach_icon, '') : ''
633        );
634        $out .= "</tr>\n";
635
636        if (sizeof($js_row_arr)) {
637            $a_js_message_arr[$header->uid] = $js_row_arr;
638        }
639    }
640
641    // complete message table
642    $out .= "</tbody></table>\n";
643
644
645    $message_count = $IMAP->messagecount();
646
647    // set client env
648    $OUTPUT->add_gui_object('mailcontframe', 'mailcontframe');
649    $OUTPUT->add_gui_object('messagelist', $attrib['id']);
650    $OUTPUT->set_env('messagecount', $message_count);
651    $OUTPUT->set_env('current_page', $IMAP->list_page);
652    $OUTPUT->set_env('pagecount', ceil($message_count/$IMAP->page_size));
653    $OUTPUT->set_env('sort_col', $sort_col);
654    $OUTPUT->set_env('sort_order', $sort_order);
655
656    if ($attrib['messageicon']) {
657        $OUTPUT->set_env('messageicon', $skin_path . $attrib['messageicon']);
658    }
659    if ($attrib['deletedicon']) {
660        $OUTPUT->set_env('deletedicon', $skin_path . $attrib['deletedicon']);
661    }
662    if ($attrib['unreadicon']) {
663        $OUTPUT->set_env('unreadicon', $skin_path . $attrib['unreadicon']);
664    }
665    if ($attrib['repliedicon']) {
666        $OUTPUT->set_env('repliedicon', $skin_path . $attrib['repliedicon']);
667    }
668    if ($attrib['attachmenticon']) {
669        $OUTPUT->set_env('attachmenticon', $skin_path . $attrib['attachmenticon']);
670    }
671    $OUTPUT->set_env('messages', $a_js_message_arr);
672
673    $OUTPUT->include_script('list.js');
674
675    return $out;
676}
677
678/**
679 * rcmail_normalize_content
680 *
681 * Function creates attribute "rev" for JS-based sorting in message
682 * list table and attempts to normalize the supplied content by
683 * converting it to lowercase, stripping html and so on.
684 *
685 * @access public
686 * @param  string $string_content
687 * @return string
688 * @see    rcmail_message_list
689 * @see    rcmail_js_message_list
690 */
691function rcmail_normalize_content($string_content)
692{
693    return trim(
694            strip_tags(
695                htmlentities(
696                    strip_tags(
697                        strtolower($string_content)
698                    )
699                )
700            )
701    );
702}
703
704// return javascript commands to add rows to the message list
705function rcmail_js_message_list($a_headers, $insert_top=FALSE)
706{
707    $registry = rc_registry::getInstance();
708    $CONFIG   = $registry->get('CONFIG', 'core');
709    $IMAP     = $registry->get('IMAP', 'core');
710    $OUTPUT   = $registry->get('OUTPUT', 'core');
711
712    $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
713    $mbox        = $IMAP->get_mailbox_name();
714
715    // show 'to' instead of from in sent messages
716    if (
717        ($mbox == $CONFIG['sent_mbox'] || $mbox == $CONFIG['drafts_mbox'])
718        && (($f = array_search('from', $a_show_cols)) !== false)
719        && array_search('to', $a_show_cols) === false
720    ) {
721        $a_show_cols[$f] = 'to';
722    }
723    $OUTPUT->command('set_message_coltypes', $a_show_cols);
724
725    // loop through message headers
726    for ($n=0; $a_headers[$n]; $n++) {
727        $header = $a_headers[$n];
728        $a_msg_cols = array();
729        $a_msg_flags = array();
730
731        // format each col; similar as in rcmail_message_list()
732        foreach ($a_show_cols as $col) {
733            if ($col=='from' || $col=='to') {
734                $cont = rc_main::Q(rcmail_address_string($header->$col, 3), 'show');
735            }
736            elseif ($col=='subject') {
737                $action    = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
738                $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
739                $cont      = rc_main::Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
740                if (!$cont) {
741                    $cont = rc_main::Q(rcube_label('nosubject'));
742                }
743                $cont = sprintf(
744                            '<a href="%s" onclick="return false">%s</a>',
745                            rc_main::Q(
746                                rc_main::rcmail_url(
747                                    $action,
748                                    array($uid_param=>$header->uid, '_mbox'=>$mbox)
749                                )
750                            ),
751                            $cont
752                );
753            }
754            elseif ($col=='size') {
755                $cont = show_bytes($header->$col);
756            }
757            elseif ($col=='date') {
758                $cont = rc_main::format_date($header->date);
759            }
760            else {
761                $cont = rc_main::Q($header->$col);
762            }
763            $a_msg_cols[$col] = $cont;
764        }
765
766        $a_msg_flags['deleted'] = $header->deleted ? 1 : 0;
767        $a_msg_flags['unread']  = $header->seen ? 0 : 1;
768        $a_msg_flags['replied'] = $header->answered ? 1 : 0;
769        $OUTPUT->command(
770                    'add_message_row',
771                    $header->uid,
772                    $a_msg_cols,
773                    $a_msg_flags,
774                    preg_match("/multipart\/m/i", $header->ctype),
775                    $insert_top
776        );
777    }
778}
779
780
781// return an HTML iframe for loading mail content
782function rcmail_messagecontent_frame($attrib)
783{
784    $registry = rc_registry::getInstance();
785    $OUTPUT   = $registry->get('OUTPUT', 'core');
786
787    if (empty($attrib['id']))
788        $attrib['id'] = 'rcmailcontentwindow';
789
790    // allow the following attributes to be added to the <iframe> tag
791    $attrib_str = rc_main::create_attrib_string(
792                    $attrib,
793                    array('id', 'class', 'style', 'src', 'width', 'height', 'frameborder')
794    );
795    $framename = $attrib['id'];
796
797    $out = sprintf(
798                '<iframe name="%s"%s></iframe>'."\n",
799                $framename,
800                $attrib_str
801    );
802
803    $OUTPUT->set_env('contentframe', $framename);
804    $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/blank.gif');
805
806    return $out;
807}
808
809
810function rcmail_messagecount_display($attrib)
811{
812    $registry = rc_registry::getInstance();
813    $IMAP     = $registry->get('IMAP', 'core');
814    $OUTPUT   = $registry->get('OUTPUT', 'core');
815
816    if (!$attrib['id'])
817        $attrib['id'] = 'rcmcountdisplay';
818
819    $OUTPUT->add_gui_object('countdisplay', $attrib['id']);
820
821    // allow the following attributes to be added to the <span> tag
822    $attrib_str = rc_main::create_attrib_string($attrib, array('style', 'class', 'id'));
823
824
825    $out = '<span' . $attrib_str . '>';
826    $out .= rcmail_get_messagecount_text();
827    $out .= '</span>';
828    return $out;
829}
830
831
832function rcmail_quota_display($attrib)
833{
834    $registry  = rc_registry::getInstance();
835    $COMM_PATH = $registry->get('COMM_PATH', 'core');
836    $OUTPUT    = $registry->get('OUTPUT', 'core');
837
838    if (!$attrib['id'])
839        $attrib['id'] = 'rcmquotadisplay';
840
841    $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
842
843    // allow the following attributes to be added to the <span> tag
844    $attrib_str = rc_main::create_attrib_string($attrib, array('style', 'class', 'id'));
845
846    $out = '<span' . $attrib_str . '>';
847    $out .= rcmail_quota_content($attrib['display']);
848    $out .= '</span>';
849    return $out;
850}
851
852
853function rcmail_quota_content($display)
854{
855    $registry  = rc_registry::getInstance();
856    $COMM_PATH = $registry->get('COMM_PATH', 'core');
857    $IMAP      = $registry->get('IMAP', 'core');
858
859    if (!$IMAP->get_capability('QUOTA')) {
860        $quota_text = rcube_label('unknown');
861    }
862    elseif ($quota = $IMAP->get_quota()) {
863        $quota_text = sprintf(
864                            "%s / %s (%.0f%%)",
865                            show_bytes($quota["used"] * 1024),
866                            show_bytes($quota["total"] * 1024),
867                            $quota["percent"]
868        );
869
870        // show quota as image (by Brett Patterson)
871        if ($display == 'image' && function_exists('imagegif')) {
872            $attrib = array('width' => 100, 'height' => 14);
873            $quota_text = sprintf(
874                            '<img src="./bin/quotaimg.php?u=%s&amp;q=%d&amp;w=%d&amp;h=%d" width="%d" height="%d" alt="%s" title="%s / %s" />',
875                            $quota['used'], $quota['total'],
876                            $attrib['width'], $attrib['height'],
877                            $attrib['width'], $attrib['height'],
878                            $quota_text,
879                            show_bytes($quota["used"] * 1024),
880                            show_bytes($quota["total"] * 1024));
881        }
882    }
883    else {
884        $quota_text = rcube_label('unlimited');
885    }
886    return $quota_text;
887}
888
889
890function rcmail_get_messagecount_text($count=NULL, $page=NULL)
891{
892    $registry = rc_registry::getInstance();
893    $MESSAGE  = $registry->get('MESSAGE', 'core');
894    $IMAP     = $registry->get('IMAP', 'core');
895
896    if (isset($MESSAGE['index'])) {
897        return rcube_label(
898                    array(
899                        'name' => 'messagenrof',
900                        'vars' => array(
901                                    'nr'  => $MESSAGE['index']+1,
902                                    'count' => $count!==NULL ? $count : $IMAP->messagecount()
903                        )
904                    )
905        );
906    }
907
908    if ($page===NULL) {
909        $page = $IMAP->list_page;
910    }
911    $start_msg = ($page-1) * $IMAP->page_size + 1;
912    $max = $count!==NULL ? $count : $IMAP->messagecount();
913
914    if ($max==0) {
915        $out = rcube_label('mailboxempty');
916    }
917    else {
918        $out = rcube_label(array('name' => 'messagesfromto',
919                              'vars' => array('from'  => $start_msg,
920                                              'to'    => min($max, $start_msg + $IMAP->page_size - 1),
921                                              'count' => $max)));
922    }
923    return rc_main::Q($out);
924}
925
926
927function rcmail_print_body($part, $safe=FALSE, $plain=FALSE)
928{
929    $registry       = rc_registry::getInstance();
930    $REMOTE_OBJECTS = $registry->get('REMOTE_OBJECTS', 'core');
931    $IMAP           = $registry->get('IMAP', 'core');
932
933    $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body;
934
935    // convert html to text/plain
936    if ($part->ctype_secondary=='html' && $plain) {
937        $txt  = new html2text($body, false, true);
938        $body = $txt->get_text();
939        $part->ctype_secondary = 'plain';
940    }
941
942    // text/html
943    if ($part->ctype_secondary == 'html') {
944        // remove charset specification in HTML message
945        $body = preg_replace('/charset=[a-z0-9\-]+/i', '', $body);
946
947        if ($safe !== FALSE) {
948            return rc_main::Q($body, 'show', FALSE);
949        }
950        // remove remote images and scripts
951
952        $remote_patterns = array(
953                            '/<img\s+(.*)src=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
954                            '/(src|background)=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
955                            '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
956                            '/(<link.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
957                            '/url\s*\(["\']?([hftps]{3,5}:\/{2}[^"\'\s]+)["\']?\)/i',
958                            '/url\s*\(["\']?([\.\/]+[^"\'\s]+)["\']?\)/i',
959                            '/<script.+<\/script>/Umis'
960        );
961
962        $remote_replaces = array(
963                            '<img \\1src=\\2./program/blocked.gif\\4',
964                            '',
965                            '',
966                            '',
967                            'none',
968                            'none',
969                            '');
970
971        // set flag if message containes remote obejcts that where blocked
972        foreach ($remote_patterns as $pattern) {
973            if (preg_match($pattern, $body)) {
974                $REMOTE_OBJECTS = TRUE;
975                $registry->set('REMOTE_OBJECTS', true, 'core');
976                break;
977            }
978        }
979
980        $body = preg_replace($remote_patterns, $remote_replaces, $body);
981        return rc_main::Q($body, 'show', FALSE);
982
983    }
984
985    // text/enriched
986    if ($part->ctype_secondary=='enriched') {
987        return rc_main::Q(enriched_to_html($body), 'show');
988    }
989    // make links and email-addresses clickable
990    $convert_patterns = $convert_replaces = $replace_strings = array();
991
992    $url_chars = 'a-z0-9_\-\+\*\$\/&%=@#:;';
993    $url_chars_within = '\?\.~,!';
994
995    $convert_patterns[] = "/([\w]+):\/\/([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
996    $convert_replaces[] = "rcmail_str_replacement('<a href=\"\\1://\\2\" target=\"_blank\">\\1://\\2</a>', \$replace_strings)";
997
998    $convert_patterns[] = "/([^\/:]|\s)(www\.)([a-z0-9\-]{2,}[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
999    $convert_replaces[] = "rcmail_str_replacement('\\1<a href=\"http://\\2\\3\" target=\"_blank\">\\2\\3</a>', \$replace_strings)";
1000
1001    $convert_patterns[] = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/ie';
1002    $convert_replaces[] = "rcmail_str_replacement('<a href=\"mailto:\\1\" onclick=\"return ".JS_OBJECT_NAME.".command(\'compose\',\'\\1\',this)\">\\1</a>', \$replace_strings)";
1003
1004    if ($part->ctype_parameters['format'] != 'flowed') {
1005        $body = wordwrap(trim($body), 80);
1006    }
1007    $body = preg_replace($convert_patterns, $convert_replaces, $body);
1008
1009    // split body into single lines
1010    $a_lines = preg_split('/\r?\n/', $body);
1011    $quote_level = 0;
1012
1013    // colorize quoted parts
1014    for ($n=0; $n<sizeof($a_lines); $n++) {
1015        $line = $a_lines[$n];
1016        $quotation = '';
1017        $q = 0;
1018
1019        if (preg_match('/^(>+\s*)/', $line, $regs)) {
1020            $q = strlen(preg_replace('/\s/', '', $regs[1]));
1021            $line = substr($line, strlen($regs[1]));
1022
1023            if ($q > $quote_level) {
1024                $quotation = str_repeat('<blockquote>', $q - $quote_level);
1025            }
1026            elseif ($q < $quote_level) {
1027                $quotation = str_repeat("</blockquote>", $quote_level - $q);
1028            }
1029        }
1030        elseif ($quote_level > 0) {
1031            $quotation = str_repeat("</blockquote>", $quote_level);
1032        }
1033        $quote_level = $q;
1034        $a_lines[$n] = $quotation . rc_main::Q($line, 'replace', FALSE);
1035    }
1036
1037    // insert the links for urls and mailtos
1038    $body = preg_replace(
1039                "/##string_replacement\{([0-9]+)\}##/e",
1040                "\$replace_strings[\\1]",
1041                join("\n", $a_lines)
1042    );
1043    return '<div class="pre">' . $body . "\n</div>";
1044}
1045
1046
1047
1048// add a string to the replacement array and return a replacement string
1049function rcmail_str_replacement($str, &$rep)
1050{
1051    $registry  = rc_registry::getInstance();
1052    $rpl_count = $registry->get('rpl_count', 'core');
1053
1054    if (empty($rpl_count)) {
1055        $rpl_count = (int) 0;
1056    }
1057    $rep[$rpl_count] = stripslashes($str);
1058    $resp = "##string_replacement{" . $rpl_count . "}##";
1059    //rc_main::tfk_debug("replace: $resp");
1060    //rc_main::tfk_debug("/ str: $str, count: $rpl_count, total: " . var_export($rep, true));
1061
1062    $rpl_count++;
1063    $registry->set('rpl_count', $rpl_count, 'core');
1064
1065    return $resp;
1066}
1067
1068
1069function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE)
1070{
1071    $registry          = rc_registry::getInstance();
1072    $IMAP              = $registry->get('IMAP', 'core');
1073    $sa_inline_objects = $registry->get('sa_inline_objects', 'core');
1074
1075    if (is_null($sa_inline_objects)) {
1076        $sa_inline_objects = array();
1077    }
1078
1079    // arguments are: (bool)$prefer_html, (string)$get_url
1080    extract($arg);
1081
1082    $a_attachments = array();
1083    $a_return_parts = array();
1084    $out = '';
1085
1086    $message_ctype_primary = strtolower($structure->ctype_primary);
1087    $message_ctype_secondary = strtolower($structure->ctype_secondary);
1088
1089    // show message headers
1090    if (
1091        $recursive
1092        && is_array($structure->headers)
1093        && isset($structure->headers['subject'])
1094    ) {
1095        $c = new stdClass;
1096        $c->type = 'headers';
1097        $c->headers = &$structure->headers;
1098        $a_return_parts[] = $c;
1099    }
1100
1101    // print body if message doesn't have multiple parts
1102    if ($message_ctype_primary == 'text') {
1103        $structure->type = 'content';
1104        $a_return_parts[] = &$structure;
1105    }
1106
1107    // message contains alternative parts
1108    else if (
1109        $message_ctype_primary=='multipart'
1110        && $message_ctype_secondary=='alternative'
1111        && is_array($structure->parts)
1112    ) {
1113        // get html/plaintext parts
1114        $plain_part = $html_part = $print_part = $related_part = NULL;
1115
1116        foreach ($structure->parts as $p => $sub_part) {
1117            $sub_ctype_primary = strtolower($sub_part->ctype_primary);
1118            $sub_ctype_secondary = strtolower($sub_part->ctype_secondary);
1119
1120            // check if sub part is
1121            if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='plain')
1122                $plain_part = $p;
1123            else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='html')
1124                $html_part = $p;
1125            else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='enriched')
1126                $enriched_part = $p;
1127            else if ($sub_ctype_primary=='multipart' && $sub_ctype_secondary=='related')
1128                $related_part = $p;
1129        }
1130
1131        // parse related part (alternative part could be in here)
1132        if (is_null($related_part) === FALSE && $prefer_html) {
1133            list($parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE);
1134            $a_return_parts = array_merge($a_return_parts, $parts);
1135            $a_attachments = array_merge($a_attachments, $attachmnts);
1136        }
1137        // print html/plain part
1138        else if (is_null($html_part) !== TRUE && $prefer_html) {
1139            $print_part = &$structure->parts[$html_part];
1140        }
1141        else if (is_null($enriched_part) !== TRUE) {
1142            $print_part = &$structure->parts[$enriched_part];
1143        }
1144        else if (is_null($plain_part) !== TRUE) {
1145            $print_part = &$structure->parts[$plain_part];
1146        }
1147        // show message body
1148        if (is_object($print_part)) {
1149            $print_part->type = 'content';
1150            $a_return_parts[] = $print_part;
1151        }
1152        // show plaintext warning
1153        else if ($html_part!==NULL) {
1154            $c = new stdClass;
1155            $c->type = 'content';
1156            $c->body = rcube_label('htmlmessage');
1157            $c->ctype_primary = 'text';
1158            $c->ctype_secondary = 'plain';
1159
1160            $a_return_parts[] = $c;
1161        }
1162
1163        // add html part as attachment
1164        if ($html_part!==NULL && $structure->parts[$html_part]!==$print_part) {
1165            $html_part = &$structure->parts[$html_part];
1166            $html_part->filename = rcube_label('htmlmessage');
1167            $html_part->mimetype = 'text/html';
1168
1169            $a_attachments[] = $html_part;
1170        }
1171    }
1172    // message contains multiple parts
1173    else if (is_array($structure->parts) && !empty($structure->parts)) {
1174        for ($i=0; $i<count($structure->parts); $i++) {
1175            $mail_part      = &$structure->parts[$i];
1176            $primary_type   = strtolower($mail_part->ctype_primary);
1177            $secondary_type = strtolower($mail_part->ctype_secondary);
1178
1179            // multipart/alternative
1180            if ($primary_type=='multipart') {
1181                list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
1182
1183                $a_return_parts = array_merge($a_return_parts, $parts);
1184                $a_attachments  = array_merge($a_attachments, $attachmnts);
1185            }
1186            // part text/[plain|html] OR message/delivery-status
1187            else if (
1188                (
1189                    $primary_type=='text'
1190                    && ($secondary_type=='plain' || $secondary_type=='html')
1191                    && $mail_part->disposition!='attachment'
1192                )
1193                ||
1194                ($primary_type=='message' && $secondary_type=='delivery-status')
1195            ) {
1196                $mail_part->type  = 'content';
1197                $a_return_parts[] = $mail_part;
1198            }
1199
1200            // part message/*
1201            else if ($primary_type=='message') {
1202                list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
1203
1204                $a_return_parts = array_merge($a_return_parts, $parts);
1205                $a_attachments  = array_merge($a_attachments, $attachmnts);
1206            }
1207            // part is file/attachment
1208            else if (
1209                $mail_part->disposition=='attachment'
1210                || $mail_part->disposition=='inline'
1211                || $mail_part->headers['content-id']
1212                || (
1213                    empty($mail_part->disposition)
1214                    && $mail_part->filename
1215                )
1216            ) {
1217                // skip apple resource forks
1218                if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile')
1219                    continue;
1220
1221                // part belongs to a related message
1222                if ($message_ctype_secondary=='related' && $mail_part->headers['content-id'])
1223                {
1224                    $mail_part->content_id = preg_replace(
1225                                                array('/^</', '/>$/'),
1226                                                '',
1227                                                $mail_part->headers['content-id']
1228                    );
1229                    $sa_inline_objects[] = $mail_part;
1230                }
1231                // is regular attachment
1232                else {
1233                    if (!$mail_part->filename) {
1234                        $mail_part->filename = 'file_' . $mail_part->mime_id;
1235                    }
1236                    $a_attachments[] = $mail_part;
1237                }
1238            }
1239        }
1240
1241        // if this was a related part try to resolve references
1242        if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects)) {
1243            $a_replaces = array();
1244
1245            foreach ($sa_inline_objects as $inline_object) {
1246                $a_replaces['cid:'.$inline_object->content_id] = htmlspecialchars(
1247                                                                    sprintf(
1248                                                                        $get_url,
1249                                                                        $inline_object->mime_id
1250                                                                    )
1251                );
1252            }
1253            // add replace array to each content part
1254            // (will be applied later when part body is available)
1255            for ($i=0; $i<count($a_return_parts); $i++) {
1256                if ($a_return_parts[$i]->type == 'content') {
1257                    $a_return_parts[$i]->replaces = $a_replaces;
1258                }
1259            }
1260        }
1261    }
1262    // message is single part non-text
1263    else if ($structure->filename) {
1264        $a_attachments[] = $structure;
1265    }
1266    $registry->set('sa_inline_objects', $sa_inline_objects, 'core');
1267
1268    return array($a_return_parts, $a_attachments);
1269}
1270
1271
1272
1273
1274// return table with message headers
1275function rcmail_message_headers($attrib, $headers=NULL)
1276{
1277    $registry  = rc_registry::getInstance();
1278    $IMAP      = $registry->get('IMAP', 'core');
1279    $OUTPUT    = $registry->get('OUTPUT', 'core');
1280    $MESSAGE   = $registry->get('MESSAGE', 'core');
1281    $sa_attrib = $registry->get('sa_attrib', 'core');
1282
1283    rc_main::tfk_debug('rcmail_message_headers: hello? hello!');
1284
1285    // keep header table attrib
1286    if (is_array($attrib) && !$sa_attrib) {
1287        $sa_attrib = $attrib;
1288    }
1289    elseif (!is_array($attrib) && is_array($sa_attrib)) {
1290        $attrib = $sa_attrib;
1291    }
1292    $registry->set('sa_attrib', $sa_attrib, 'core');
1293
1294    if (isset($MESSAGE) === false) {
1295        rc_main::tfk_debug('rcmail_message_headers: no $MESSAGE :(');
1296        return FALSE;
1297    }
1298
1299    rc_main::tfk_debug('MESSAGE: ' . var_export($MESSAGE, true));
1300
1301    // get associative array of headers object
1302    if (is_null($headers) === true) {
1303        $headers = is_object($MESSAGE['structure']->headers) ? get_object_vars($MESSAGE['structure']->headers) : $MESSAGE['structure']->headers;
1304    }
1305    $header_count = 0;
1306
1307    // allow the following attributes to be added to the <table> tag
1308    $attrib_str = rc_main::create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
1309    $out = '<table' . $attrib_str . ">\n";
1310
1311    // show these headers
1312    $standard_headers = array('subject', 'from', 'organization', 'to', 'cc', 'bcc', 'reply-to', 'date');
1313
1314    rc_main::tfk_debug('rcmail_message_headers: ' . var_export($headers, true));
1315
1316    foreach ($standard_headers as $hkey) {
1317        if (isset($headers[$hkey]) === false) {
1318            continue;
1319        }
1320        if ($hkey=='date' && empty($headers[$hkey]) === false) {
1321            $header_value = rc_main::format_date(strtotime($headers[$hkey]));
1322        }
1323        elseif(in_array($hkey, array('from', 'to', 'cc', 'bcc', 'reply-to'))) {
1324            $header_value = rc_main::Q(
1325                                rcmail_address_string(
1326                                    $headers[$hkey],
1327                                    NULL,
1328                                    $attrib['addicon']
1329                                ),
1330                                'show'
1331            );
1332        }
1333        else {
1334            $header_value = rc_main::Q(
1335                                rcube_imap::decode_mime_string(
1336                                    $headers[$hkey],
1337                                    $headers['charset']
1338                                )
1339            );
1340        }
1341        $out .= "\n<tr>\n";
1342        $out .= '<td class="header-title">' . rc_main::Q(rcube_label($hkey));
1343        $out .= ":&nbsp;</td>\n";
1344        $out .= '<td class="' . $hkey . '" width="90%">' . $header_value;
1345        $out .= "</td>\n</tr>";
1346        $header_count++;
1347    }
1348
1349    $out .= "\n</table>\n\n";
1350
1351    //rc_main::tfk_debug('rcmail_message_headers, count: ' . $header_count);
1352
1353    return $header_count ? $out : '';
1354}
1355
1356
1357
1358function rcmail_message_body($attrib)
1359{
1360    $registry       = rc_registry::getInstance();
1361    $CONFIG         = $registry->get('CONFIG', 'core');
1362    $OUTPUT         = $registry->get('OUTPUT', 'core');
1363    $MESSAGE        = $registry->get('MESSAGE', 'core');
1364    $IMAP           = $registry->get('IMAP', 'core');
1365    $GET_URL        = $registry->get('GET_URL', 'core');
1366    $REMOTE_OBJECTS = $registry->get('REMOTE_OBJECTS', 'core');
1367
1368    if (!is_array($MESSAGE['parts']) && !$MESSAGE['body']) {
1369        return '';
1370    }
1371    if (!$attrib['id']) {
1372        $attrib['id'] = 'rcmailMsgBody';
1373    }
1374    $safe_mode = (bool)$_GET['_safe'];
1375    $attrib_str = rc_main::create_attrib_string($attrib, array('style', 'class', 'id'));
1376    $out = '<div '. $attrib_str . ">\n";
1377
1378    $header_attrib = array();
1379    foreach ($attrib as $attr => $value) {
1380        if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) {
1381            $header_attrib[$regs[1]] = $value;
1382        }
1383    }
1384
1385    // this is an ecrypted message
1386    // -> create a plaintext body with the according message
1387    if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted') {
1388        $p = new stdClass;
1389        $p->type = 'content';
1390        $p->ctype_primary = 'text';
1391        $p->ctype_secondary = 'plain';
1392        $p->body = rcube_label('encryptedmessage');
1393        $MESSAGE['parts'][0] = $p;
1394    }
1395
1396    if ($MESSAGE['parts']) {
1397        foreach ($MESSAGE['parts'] as $i => $part) {
1398            if ($part->type=='headers') {
1399                $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers);
1400            }
1401            elseif ($part->type=='content') {
1402                if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) {
1403                    $part->ctype_parameters['charset'] = $MESSAGE['headers']->charset;
1404                }
1405                // fetch part if not available
1406                if (!isset($part->body))
1407                    $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part);
1408
1409                $body = rcmail_print_body($part, $safe_mode, !$CONFIG['prefer_html']);
1410                //$out .= '<div class="message-part">';
1411
1412                if ($part->ctype_secondary != 'plain')
1413                    $out .= rcmail_sanitize_html($body, $attrib['id']);
1414                else
1415                    $out .= $body;
1416
1417                //$out .= "</div>\n";
1418            }
1419        }
1420    }
1421    else {
1422        $out .= $MESSAGE['body'];
1423    }
1424
1425    $ctype_primary = strtolower($MESSAGE['structure']->ctype_primary);
1426    $ctype_secondary = strtolower($MESSAGE['structure']->ctype_secondary);
1427
1428    // list images after mail body
1429    if (
1430        get_boolean($attrib['showimages'])
1431        && $ctype_primary=='multipart'
1432        && $ctype_secondary=='mixed'
1433        && sizeof($MESSAGE['attachments'])
1434        && !strstr($message_body, '<html')
1435        && strlen($GET_URL)
1436    ) {
1437        foreach ($MESSAGE['attachments'] as $attach_prop) {
1438            if (strpos($attach_prop->mimetype, 'image/')===0) {
1439                $out .= sprintf(
1440                            "\n<hr />\n<p align=\"center\"><img src=\"%s&amp;_part=%s\" alt=\"%s\" title=\"%s\" /></p>\n",
1441                            htmlspecialchars($GET_URL), $attach_prop->mime_id,
1442                            $attach_prop->filename,
1443                            $attach_prop->filename
1444                );
1445            }
1446        }
1447    }
1448
1449    // tell client that there are blocked remote objects
1450    if ($REMOTE_OBJECTS && !$safe_mode) {
1451        $OUTPUT->set_env('blockedobjects', true);
1452    }
1453    $out .= "\n</div>";
1454    return $out;
1455}
1456
1457
1458
1459// modify a HTML message that it can be displayed inside a HTML page
1460function rcmail_sanitize_html($body, $container_id)
1461{
1462    // remove any null-byte characters before parsing
1463    $body = preg_replace('/\x00/', '', $body);
1464
1465    $last_style_pos = 0;
1466    $body_lc = strtolower($body);
1467
1468    // find STYLE tags
1469    while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
1470    {
1471        $pos = strpos($body_lc, '>', $pos)+1;
1472
1473        // replace all css definitions with #container [def]
1474        $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id);
1475
1476        $body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
1477        $body_lc = strtolower($body);
1478        $last_style_pos = $pos2;
1479    }
1480
1481
1482    // remove SCRIPT tags
1483    foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag) {
1484        while (($pos = strpos($body_lc, '<'.$tag)) && ($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)))
1485        {
1486            $pos2 += strlen('</'.$tag.'>');
1487            $body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2);
1488            $body_lc = strtolower($body);
1489        }
1490    }
1491
1492    // replace event handlers on any object
1493    while ($body != $prev_body) {
1494        $prev_body = $body;
1495        $body = preg_replace('/(<[^!][^>]*\s)(on[^=>]+)=([^>]+>)/im', '$1__removed=$3', $body);
1496        $body = preg_replace('/(<[^!][^>]*\shref=["\']?)(javascript:)([^>]*?>)/im', '$1null:$3', $body);
1497    }
1498
1499    // resolve <base href>
1500    $base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i';
1501    if (preg_match($base_reg, $body, $regs)) {
1502        $base_url = $regs[2];
1503        $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body);
1504        $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body);
1505        $body = preg_replace($base_reg, '', $body);
1506    }
1507
1508    // modify HTML links to open a new window if clicked
1509    $body = preg_replace('/<a\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1');", $body);
1510
1511    // add comments arround html and other tags
1512    $out = preg_replace(array(
1513            '/(<!DOCTYPE.+)/i',
1514            '/(<\/?html[^>]*>)/i',
1515            '/(<\/?head[^>]*>)/i',
1516            '/(<title[^>]*>.*<\/title>)/Ui',
1517            '/(<\/?meta[^>]*>)/i'),
1518            '<!--\\1-->',
1519            $body
1520    );
1521
1522    $out = preg_replace(
1523            array(
1524                '/<body([^>]*)>/i',
1525                '/<\/body>/i'
1526            ),
1527            array(
1528                '<div class="rcmBody"\\1>',
1529                '</div>'
1530            ),
1531            $out
1532    );
1533
1534    // quote <? of php and xml files that are specified as text/html
1535    $out = preg_replace(array('/<\?/', '/\?>/'), array('&lt;?', '?&gt;'), $out);
1536
1537    return $out;
1538}
1539
1540
1541// parse link attributes and set correct target
1542function rcmail_alter_html_link($in)
1543{
1544    $in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in);
1545    $attrib = rc_main::parse_attrib_string($in);
1546
1547    if (stristr((string)$attrib['href'], 'mailto:')) {
1548        $attrib['onclick'] = sprintf(
1549                                    "return %s.command('compose','%s',this)",
1550                                    JS_OBJECT_NAME,
1551                                    rc_main::JQ(substr($attrib['href'], 7))
1552        );
1553    }
1554    else if (!empty($attrib['href']) && $attrib['href']{0}!='#') {
1555        $attrib['target'] = '_blank';
1556    }
1557    $resp = '<a';
1558    $resp.= rc_main::create_attrib_string(
1559                    $attrib,
1560                    array(
1561                        'href', 'name', 'target', 'onclick', 'id', 'class', 'style', 'title'
1562                    )
1563    );
1564    $resp .= '>';
1565    return $resp;
1566}
1567
1568
1569// replace all css definitions with #container [def]
1570function rcmail_mod_css_styles($source, $container_id)
1571{
1572    $a_css_values = array();
1573    $last_pos = 0;
1574
1575    // cut out all contents between { and }
1576    while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
1577    {
1578        $key = sizeof($a_css_values);
1579        $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
1580        $source = substr($source, 0, $pos+1);
1581        $source.= "<<str_replacement[$key]>>";
1582        $source.= substr($source, $pos2, strlen($source)-$pos2);
1583        $last_pos = $pos+2;
1584    }
1585
1586    // remove html commends and add #container to each tag selector.
1587    // also replace body definition because we also stripped off the <body> tag
1588    $styles = preg_replace(
1589                array(
1590                    '/(^\s*<!--)|(-->\s*$)/',
1591                    '/(^\s*|,\s*|\}\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im',
1592                    '/<<str_replacement\[([0-9]+)\]>>/e',
1593                    "/$container_id\s+body/i"
1594                ),
1595                array(
1596                    '',
1597                    "\\1#$container_id \\2",
1598                    "\$a_css_values[\\1]",
1599                    "$container_id div.rcmBody"
1600                ),
1601                $source
1602    );
1603    return $styles;
1604}
1605
1606
1607function rcmail_has_html_part($message_parts)
1608{
1609   if (!is_array($message_parts)) {
1610      return FALSE;
1611   }
1612   // check all message parts
1613   foreach ($message_parts as $pid => $part)
1614   {
1615      $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1616      if ($mimetype=='text/html')
1617      {
1618         return TRUE;
1619      }
1620   }
1621
1622   return FALSE;
1623}
1624
1625// return first HTML part of a message
1626function rcmail_first_html_part($message_struct)
1627{
1628    $registry = rc_registry::getInstance();
1629    $IMAP     = $registry->get('IMAP', 'core');
1630
1631    if (!is_array($message_struct['parts'])) {
1632        return FALSE;
1633    }
1634    $html_part = NULL;
1635
1636    // check all message parts
1637    foreach ($message_struct['parts'] as $pid => $part) {
1638        $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1639        if ($mimetype=='text/html') {
1640            $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1641        }
1642    }
1643
1644    if ($html_part) {
1645        // remove special chars encoding
1646        //$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1647        //$html_part = strtr($html_part, $trans);
1648
1649        return $html_part;
1650    }
1651    return FALSE;
1652}
1653
1654
1655// return first text part of a message
1656function rcmail_first_text_part($message_struct)
1657{
1658    $registry = rc_registry::getInstance();
1659    $IMAP     = $registry->get('IMAP', 'core');
1660
1661    if (empty($message_struct['parts'])) {
1662        return $message_struct['UID'] ? $IMAP->get_body($message_struct['UID']) : false;
1663    }
1664    // check all message parts
1665    foreach ($message_struct['parts'] as $pid => $part) {
1666        $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1667
1668        if ($mimetype=='text/plain') {
1669            return $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1670        }
1671        else if ($mimetype=='text/html') {
1672            $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1673
1674            // remove special chars encoding
1675            $trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1676            $html_part = strtr($html_part, $trans);
1677
1678            // create instance of html2text class
1679            $txt = new html2text($html_part);
1680            return $txt->get_text();
1681        }
1682    }
1683    return FALSE;
1684}
1685
1686
1687// decode address string and re-format it as HTML links
1688function rcmail_address_string($input, $max=NULL, $addicon=NULL)
1689{
1690    $registry              = rc_registry::getInstance();
1691    $CONFIG                = $registry->get('CONFIG', 'core');
1692    $IMAP                  = $registry->get('IMAP', 'core');
1693    $PRINT_MODE            = $registry->get('PRINT_MODE', 'core');
1694    $OUTPUT                = $registry->get('OUTPUT', 'core');
1695    $EMAIL_ADDRESS_PATTERN = $registry->get('EMAIL_ADDRESS_PATTERN', 'core');
1696
1697    $a_parts = $IMAP->decode_address_list($input);
1698
1699    if (!sizeof($a_parts)) {
1700        return $input;
1701    }
1702    $c = count($a_parts);
1703    $j = 0;
1704    $out = '';
1705
1706    foreach ($a_parts as $part) {
1707
1708        $j++;
1709        if ($PRINT_MODE) {
1710            $out .= sprintf('%s &lt;%s&gt;', rc_main::Q($part['name']), $part['mailto']);
1711        }
1712        elseif (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto'])) {
1713            $out .= sprintf(
1714                        '<a href="mailto:%s" onclick="return %s.command(\'compose\',\'%s\',this)" class="rcmContactAddress" title="%s">%s</a>',
1715                        rc_main::Q($part['mailto']),
1716                        JS_OBJECT_NAME,
1717                        rc_main::JQ($part['mailto']),
1718                        rc_main::Q($part['mailto']),
1719                        rc_main::Q($part['name']));
1720            /**
1721             * Build icon to allow adding to addressbook.
1722             * @ignore
1723             */
1724            /*
1725            if ($addicon) {
1726                $out .= sprintf(
1727                            '&nbsp;<a href="#add" onclick="return %s.command(\'add-contact\',\'%s\',this)" title="%s"><img src="%s%s" alt="add" border="0" /></a>',
1728                            JS_OBJECT_NAME,
1729                            urlencode($part['string']),
1730                            rcube_label('addtoaddressbook'),
1731                            $CONFIG['skin_path'],
1732                            $addicon
1733                );
1734            }*/
1735        }
1736        else {
1737            if ($part['name']) {
1738                $out .= rc_main::Q($part['name']);
1739            }
1740            if ($part['mailto']) {
1741                $out .= (strlen($out) ? ' ' : '');
1742                $out .= sprintf('&lt;%s&gt;', rc_main::Q($part['mailto']));
1743            }
1744        }
1745
1746        if ($c>$j) {
1747            $out .= ','.($max ? '&nbsp;' : ' ');
1748        }
1749        if ($max && $j==$max && $c>$j) {
1750            $out .= '...';
1751            break;
1752        }
1753    }
1754    return $out;
1755}
1756
1757
1758function rcmail_message_part_controls()
1759{
1760    $registry = rc_registry::getInstance();
1761    $CONFIG   = $registry->get('CONFIG', 'core');
1762    $IMAP     = $registry->get('IMAP', 'core');
1763    $MESSAGE  = $registry->get('MESSAGE', 'core');
1764
1765    if (
1766        !is_array($MESSAGE)
1767        || !is_array($MESSAGE['parts'])
1768        || !($_GET['_uid'] && $_GET['_part'])
1769        || !$MESSAGE['parts'][$_GET['_part']]
1770    ) {
1771        return '';
1772    }
1773    $part = &$MESSAGE['parts'][$_GET['_part']];
1774
1775    $attrib_str = rc_main::create_attrib_string(
1776                        $attrib,
1777                        array(
1778                            'id',
1779                            'class',
1780                            'style',
1781                            'cellspacing',
1782                            'cellpadding',
1783                            'border',
1784                            'summary'
1785                        )
1786    );
1787    $out = '<table '. $attrib_str . ">\n";
1788
1789    if ($filename) {
1790        $out .= sprintf(
1791                    '<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
1792                    rc_main::Q(rcube_label('filename')),
1793                    rc_main::Q($part->filename),
1794                    str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
1795                    rc_main::Q(rcube_label('download')));
1796    }
1797
1798    if ($part->size) {
1799        $out .= sprintf(
1800                    '<tr><td class="title">%s</td><td>%s</td></tr>' . "\n",
1801                    rc_main::Q(rcube_label('filesize')),
1802                    show_bytes($part->size)
1803        );
1804    }
1805    $out .= "\n</table>";
1806
1807    return $out;
1808  }
1809
1810
1811
1812function rcmail_message_part_frame($attrib)
1813{
1814    $registry = rc_registry::getInstance();
1815    $MESSGAGE = $registry->get('MESSAGE', 'core');
1816
1817    $part = $MESSAGE['parts'][$_GET['_part']];
1818    $ctype_primary = strtolower($part->ctype_primary);
1819
1820    $attrib['src'] = './?';
1821    $attrib['src'].= str_replace(
1822                        '_frame=',
1823                        ($ctype_primary=='text' ? '_show=' : '_preload='),
1824                        $_SERVER['QUERY_STRING']
1825    );
1826    $attrib_str = rc_main::create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height'));
1827    $out = '<iframe '. $attrib_str . "></iframe>";
1828
1829  return $out;
1830  }
1831
1832
1833// clear message composing settings
1834function rcmail_compose_cleanup()
1835{
1836    if (!isset($_SESSION['compose']))
1837        return;
1838
1839    // remove attachment files from temp dir
1840    if (is_array($_SESSION['compose']['attachments'])) {
1841        foreach ($_SESSION['compose']['attachments'] as $attachment) {
1842            @unlink($attachment['path']);
1843        }
1844    }
1845    unset($_SESSION['compose']);
1846}
1847
1848
1849// register UI objects
1850$OUTPUT->add_handlers(array(
1851  'mailboxlist' => 'rcmail_mailbox_list',
1852  'messages' => 'rcmail_message_list',
1853  'messagecountdisplay' => 'rcmail_messagecount_display',
1854  'quotadisplay' => 'rcmail_quota_display',
1855  'messageheaders' => 'rcmail_message_headers',
1856  'messagebody' => 'rcmail_message_body',
1857  'messagecontentframe' => 'rcmail_messagecontent_frame',
1858  'messagepartframe' => 'rcmail_message_part_frame',
1859  'messagepartcontrols' => 'rcmail_message_part_controls',
1860  'searchform' => 'rcmail_search_form'
1861));
1862
1863?>
Note: See TracBrowser for help on using the repository browser.