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

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

+ split rcube_contatcs.inc into another file rcube/result_set. (one class per file)
+ fixed cs on rcube_contacts and result_set
+ fixed cs and references in addcontact

  • removed some debug code from the app

# fixed encoding issue with special characters on reply/forward/compose
# fixed some issues with orphaned class/function references and use of registry
# lists in mailboxlist where nested which lead to css/js issues - removed that

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