source: github/program/steps/mail/func.inc @ 5eee009

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since 5eee009 was 5eee009, checked in by thomascube <thomas@…>, 6 years ago

Allow vars and PHP code in templates; improved page title; fixed #1484395

  • Property mode set to 100644
File size: 41.5 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$
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
28if (empty($_SESSION['mbox']))
29  $_SESSION['mbox'] = $IMAP->get_mailbox_name();
30
31// set imap properties and session vars
32if ($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC))
33  {
34  $IMAP->set_mailbox($mbox);
35  $_SESSION['mbox'] = $mbox;
36  }
37
38if (!empty($_GET['_page']))
39  {
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'];
51if (!isset($_SESSION['sort_order']))
52  $_SESSION['sort_order'] = $CONFIG['message_sort_order'];
53
54// set message set for search result
55if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']]))
56  $IMAP->set_search_set($_SESSION['search'][$_REQUEST['_search']]);
57
58
59// define url for getting message parts
60if (strlen($_GET['_uid']))
61  $GET_URL = rcmail_url('get', array('_mbox'=>$IMAP->get_mailbox_name(), '_uid'=>get_input_value('_uid', RCUBE_INPUT_GET)));
62
63
64// set current mailbox in client environment
65$OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name());
66$OUTPUT->set_env('quota', $IMAP->get_capability('quota'));
67
68if ($CONFIG['trash_mbox'])
69  $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
70if ($CONFIG['drafts_mbox'])
71  $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
72if ($CONFIG['junk_mbox'])
73  $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']);
74
75if (!$OUTPUT->ajax_call)
76  rcube_add_label('checkingmail', 'deletemessage', 'movemessagetotrash');
77
78// set page title
79if (empty($_action) || $_action == 'list')
80  $OUTPUT->set_pagetitle(rcube_charset_convert($IMAP->get_mailbox_name(), 'UTF-7'));
81
82
83
84// return the message list as HTML table
85function rcmail_message_list($attrib)
86  {
87  global $IMAP, $CONFIG, $COMM_PATH, $OUTPUT;
88
89  $skin_path = $CONFIG['skin_path'];
90  $image_tag = '<img src="%s%s" alt="%s" border="0" />';
91
92  // check to see if we have some settings for sorting
93  $sort_col   = $_SESSION['sort_col'];
94  $sort_order = $_SESSION['sort_order'];
95 
96  // add some labels to client
97  rcube_add_label('from', 'to');
98
99  // get message headers
100  $a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order);
101
102  // add id to message list table if not specified
103  if (!strlen($attrib['id']))
104    $attrib['id'] = 'rcubemessagelist';
105
106  // allow the following attributes to be added to the <table> tag
107  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
108
109  $out = '<table' . $attrib_str . ">\n";
110
111
112  // define list of cols to be displayed
113  $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
114  $a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
115
116  $mbox = $IMAP->get_mailbox_name();
117 
118  // show 'to' instead of from in sent messages
119  if (($mbox==$CONFIG['sent_mbox'] || $mbox==$CONFIG['drafts_mbox']) && ($f = array_search('from', $a_show_cols))
120      && !array_search('to', $a_show_cols))
121    $a_show_cols[$f] = 'to';
122 
123  // add col definition
124  $out .= '<colgroup>';
125  $out .= '<col class="icon" />';
126
127  foreach ($a_show_cols as $col)
128    $out .= sprintf('<col class="%s" />', $col);
129
130  $out .= '<col class="icon" />';
131  $out .= "</colgroup>\n";
132
133  // add table title
134  $out .= "<thead><tr>\n<td class=\"icon\">&nbsp;</td>\n";
135
136  $javascript = '';
137  foreach ($a_show_cols as $col)
138    {
139    // get column name
140    $col_name = Q(rcube_label($col));
141
142    // make sort links
143    $sort = '';
144    if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols))
145      {
146      // have buttons configured
147      if (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))
148        {
149        $sort = '&nbsp;&nbsp;';
150
151        // asc link
152        if (!empty($attrib['sortascbutton']))
153          {
154          $sort .= $OUTPUT->button(array(
155            'command' => 'sort',
156            'prop' => $col.'_ASC',
157            'image' => $attrib['sortascbutton'],
158            'align' => 'absmiddle',
159            'title' => 'sortasc'));
160          }       
161       
162        // desc link
163        if (!empty($attrib['sortdescbutton']))
164          {
165          $sort .= $OUTPUT->button(array(
166            'command' => 'sort',
167            'prop' => $col.'_DESC',
168            'image' => $attrib['sortdescbutton'],
169            'align' => 'absmiddle',
170            'title' => 'sortdesc'));
171          }
172        }
173      // just add a link tag to the header
174      else
175        {
176        $col_name = sprintf(
177          '<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
178          JS_OBJECT_NAME,
179          $col,
180          rcube_label('sortby'),
181          $col_name);
182        }
183      }
184     
185    $sort_class = $col==$sort_col ? " sorted$sort_order" : '';
186
187    // put it all together
188    $out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n";   
189    }
190
191  $out .= '<td class="icon">'.($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '')."</td>\n";
192  $out .= "</tr></thead>\n<tbody>\n";
193
194  // no messages in this mailbox
195  if (!sizeof($a_headers))
196    $OUTPUT->show_message('nomessagesfound', 'notice');
197
198
199  $a_js_message_arr = array();
200
201  // create row for each message
202  foreach ($a_headers as $i => $header)  //while (list($i, $header) = each($a_headers))
203    {
204    $message_icon = $attach_icon = '';
205    $js_row_arr = array();
206    $zebra_class = $i%2 ? 'even' : 'odd';
207
208    // set messag attributes to javascript array
209    if ($header->deleted)
210      $js_row_arr['deleted'] = true;
211    if (!$header->seen)
212      $js_row_arr['unread'] = true;
213    if ($header->answered)
214      $js_row_arr['replied'] = true;
215    // set message icon 
216    if ($attrib['deletedicon'] && $header->deleted)
217      $message_icon = $attrib['deletedicon'];
218    else if ($attrib['unreadicon'] && !$header->seen)
219      $message_icon = $attrib['unreadicon'];
220    else if ($attrib['repliedicon'] && $header->answered)
221      $message_icon = $attrib['repliedicon'];
222    else if ($attrib['messageicon'])
223      $message_icon = $attrib['messageicon'];
224   
225    // set attachment icon
226    if ($attrib['attachmenticon'] && preg_match("/multipart\/[mr]/i", $header->ctype))
227      $attach_icon = $attrib['attachmenticon'];
228       
229    $out .= sprintf('<tr id="rcmrow%d" class="message%s%s %s">'."\n",
230                    $header->uid,
231                    $header->seen ? '' : ' unread',
232                    $header->deleted ? ' deleted' : '',
233                    $zebra_class);   
234   
235    $out .= sprintf("<td class=\"icon\">%s</td>\n", $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : '');
236   
237    // format each col
238    foreach ($a_show_cols as $col)
239      {
240      if ($col=='from' || $col=='to')
241        $cont = Q(rcmail_address_string($header->$col, 3, $attrib['addicon']), 'show');
242      else if ($col=='subject')
243        {
244        $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
245        $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
246        $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
247        if (empty($cont)) $cont = Q(rcube_label('nosubject'));
248        $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont);
249        }
250      else if ($col=='size')
251        $cont = show_bytes($header->$col);
252      else if ($col=='date')
253        $cont = format_date($header->date);
254      else
255        $cont = Q($header->$col);
256       
257      $out .= '<td class="'.$col.'">' . $cont . "</td>\n";
258      }
259
260    $out .= sprintf("<td class=\"icon\">%s</td>\n", $attach_icon ? sprintf($image_tag, $skin_path, $attach_icon, '') : '');
261    $out .= "</tr>\n";
262   
263    if (sizeof($js_row_arr))
264      $a_js_message_arr[$header->uid] = $js_row_arr;
265    }
266 
267  // complete message table
268  $out .= "</tbody></table>\n";
269 
270 
271  $message_count = $IMAP->messagecount();
272 
273  // set client env
274  $OUTPUT->add_gui_object('mailcontframe', 'mailcontframe');
275  $OUTPUT->add_gui_object('messagelist', $attrib['id']);
276  $OUTPUT->set_env('messagecount', $message_count);
277  $OUTPUT->set_env('current_page', $IMAP->list_page);
278  $OUTPUT->set_env('pagecount', ceil($message_count/$IMAP->page_size));
279  $OUTPUT->set_env('sort_col', $sort_col);
280  $OUTPUT->set_env('sort_order', $sort_order);
281 
282  if ($attrib['messageicon'])
283    $OUTPUT->set_env('messageicon', $skin_path . $attrib['messageicon']);
284  if ($attrib['deletedicon'])
285    $OUTPUT->set_env('deletedicon', $skin_path . $attrib['deletedicon']);
286  if ($attrib['unreadicon'])
287    $OUTPUT->set_env('unreadicon', $skin_path . $attrib['unreadicon']);
288  if ($attrib['repliedicon'])
289    $OUTPUT->set_env('repliedicon', $skin_path . $attrib['repliedicon']);
290  if ($attrib['attachmenticon'])
291    $OUTPUT->set_env('attachmenticon', $skin_path . $attrib['attachmenticon']);
292 
293  $OUTPUT->set_env('messages', $a_js_message_arr);
294 
295  $OUTPUT->include_script('list.js');
296 
297  return $out;
298  }
299
300
301// return javascript commands to add rows to the message list
302function rcmail_js_message_list($a_headers, $insert_top=FALSE)
303  {
304  global $CONFIG, $IMAP, $OUTPUT;
305
306  $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
307  $mbox = $IMAP->get_mailbox_name();
308
309  // show 'to' instead of from in sent messages
310  if (($mbox == $CONFIG['sent_mbox'] || $mbox == $CONFIG['drafts_mbox'])
311      && (($f = array_search('from', $a_show_cols)) !== false) && array_search('to', $a_show_cols) === false)
312    $a_show_cols[$f] = 'to';
313
314  $OUTPUT->command('set_message_coltypes', $a_show_cols);
315
316  // loop through message headers
317  for ($n=0; $a_headers[$n]; $n++)
318    {
319    $header = $a_headers[$n];
320    $a_msg_cols = array();
321    $a_msg_flags = array();
322
323    // format each col; similar as in rcmail_message_list()
324    foreach ($a_show_cols as $col)
325      {
326      if ($col=='from' || $col=='to')
327        $cont = Q(rcmail_address_string($header->$col, 3), 'show');
328      else if ($col=='subject')
329        {
330        $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
331        $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid';
332        $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
333        if (!$cont) $cont = Q(rcube_label('nosubject'));
334        $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont);
335        }
336      else if ($col=='size')
337        $cont = show_bytes($header->$col);
338      else if ($col=='date')
339        $cont = format_date($header->date);
340      else
341        $cont = Q($header->$col);
342         
343      $a_msg_cols[$col] = $cont;
344      }
345
346    $a_msg_flags['deleted'] = $header->deleted ? 1 : 0;
347    $a_msg_flags['unread'] = $header->seen ? 0 : 1;
348    $a_msg_flags['replied'] = $header->answered ? 1 : 0;
349    $OUTPUT->command('add_message_row',
350      $header->uid,
351      $a_msg_cols,
352      $a_msg_flags,
353      preg_match("/multipart\/m/i", $header->ctype),
354      $insert_top);
355    }
356  }
357
358
359// return an HTML iframe for loading mail content
360function rcmail_messagecontent_frame($attrib)
361  {
362  global $OUTPUT;
363 
364  if (empty($attrib['id']))
365    $attrib['id'] = 'rcmailcontentwindow';
366
367  // allow the following attributes to be added to the <iframe> tag
368  $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height', 'frameborder'));
369  $framename = $attrib['id'];
370
371  $out = sprintf('<iframe name="%s"%s></iframe>'."\n",
372         $framename,
373         $attrib_str);
374
375  $OUTPUT->set_env('contentframe', $framename);
376  $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/blank.gif');
377
378  return $out;
379  }
380
381
382function rcmail_messagecount_display($attrib)
383  {
384  global $IMAP, $OUTPUT;
385 
386  if (!$attrib['id'])
387    $attrib['id'] = 'rcmcountdisplay';
388
389  $OUTPUT->add_gui_object('countdisplay', $attrib['id']);
390
391  // allow the following attributes to be added to the <span> tag
392  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
393
394 
395  $out = '<span' . $attrib_str . '>';
396  $out .= rcmail_get_messagecount_text();
397  $out .= '</span>';
398  return $out;
399  }
400
401
402function rcmail_quota_display($attrib)
403  {
404  global $OUTPUT, $COMM_PATH;
405
406  if (!$attrib['id'])
407    $attrib['id'] = 'rcmquotadisplay';
408
409  $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
410
411  // allow the following attributes to be added to the <span> tag
412  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
413
414  $out = '<span' . $attrib_str . '>';
415  $out .= rcmail_quota_content($attrib['display']);
416  $out .= '</span>';
417  return $out;
418  }
419
420
421function rcmail_quota_content($display)
422  {
423  global $IMAP, $COMM_PATH;
424
425  if (!$IMAP->get_capability('QUOTA'))
426    $quota_text = rcube_label('unknown');
427  else if ($quota = $IMAP->get_quota())
428    {
429    $quota_text = sprintf("%s / %s (%.0f%%)",
430                          show_bytes($quota["used"] * 1024),
431                          show_bytes($quota["total"] * 1024),
432                          $quota["percent"]);
433
434    // show quota as image (by Brett Patterson)
435    if ($display == 'image' && function_exists('imagegif'))
436      {
437      $attrib = array('width' => 100, 'height' => 14);
438      $quota_text = sprintf('<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" />',
439                            $quota['used'], $quota['total'],
440                            $attrib['width'], $attrib['height'],
441                            $attrib['width'], $attrib['height'],
442                            $quota_text,
443                            show_bytes($quota["used"] * 1024),
444                            show_bytes($quota["total"] * 1024));
445      }
446    }
447  else
448    $quota_text = rcube_label('unlimited');
449
450  return $quota_text;
451  }
452
453
454function rcmail_get_messagecount_text($count=NULL, $page=NULL)
455  {
456  global $IMAP, $MESSAGE;
457 
458  if (isset($MESSAGE['index']))
459    {
460    return rcube_label(array('name' => 'messagenrof',
461                             'vars' => array('nr'  => $MESSAGE['index']+1,
462                                             'count' => $count!==NULL ? $count : $IMAP->messagecount())));
463    }
464
465  if ($page===NULL)
466    $page = $IMAP->list_page;
467   
468  $start_msg = ($page-1) * $IMAP->page_size + 1;
469  $max = $count!==NULL ? $count : $IMAP->messagecount();
470
471  if ($max==0)
472    $out = rcube_label('mailboxempty');
473  else
474    $out = rcube_label(array('name' => 'messagesfromto',
475                              'vars' => array('from'  => $start_msg,
476                                              'to'    => min($max, $start_msg + $IMAP->page_size - 1),
477                                              'count' => $max)));
478
479  return Q($out);
480  }
481
482
483function rcmail_print_body($part, $safe=FALSE, $plain=FALSE)
484  {
485  global $IMAP, $REMOTE_OBJECTS;
486 
487  $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body;
488
489  // convert html to text/plain
490  if ($part->ctype_secondary=='html' && $plain)
491    {
492    $txt = new html2text($body, false, true);
493    $body = $txt->get_text();
494    $part->ctype_secondary = 'plain';
495    }
496   
497  // text/html
498  if ($part->ctype_secondary=='html')
499    {
500    // remove charset specification in HTML message
501    $body = preg_replace('/charset=[a-z0-9\-]+/i', '', $body);
502
503    if (!$safe)  // remove remote images and scripts
504      {
505      $remote_patterns = array('/<img\s+(.*)src=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
506                               '/(src|background)=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
507                               '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
508                               '/(<link.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
509                               '/url\s*\(["\']?([hftps]{3,5}:\/{2}[^"\'\s]+)["\']?\)/i',
510                               '/url\s*\(["\']?([\.\/]+[^"\'\s]+)["\']?\)/i',
511                               '/<script.+<\/script>/Umis');
512
513      $remote_replaces = array('<img \\1src=\\2./program/blocked.gif\\4',
514                               '',
515                               '',
516                               '',
517                               'none',
518                               'none',
519                               '');
520     
521      // set flag if message containes remote obejcts that where blocked
522      foreach ($remote_patterns as $pattern)
523        {
524        if (preg_match($pattern, $body))
525          {
526          $REMOTE_OBJECTS = TRUE;
527          break;
528          }
529        }
530
531      $body = preg_replace($remote_patterns, $remote_replaces, $body);
532      }
533
534    return Q($body, 'show', FALSE);
535    }
536
537  // text/enriched
538  if ($part->ctype_secondary=='enriched')
539    {
540    return Q(enriched_to_html($body), 'show');
541    }
542  else
543    {
544    // make links and email-addresses clickable
545    $convert_patterns = $convert_replaces = $replace_strings = array();
546   
547    $url_chars = 'a-z0-9_\-\+\*\$\/&%=@#:;';
548    $url_chars_within = '\?\.~,!';
549
550    $convert_patterns[] = "/([\w]+):\/\/([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
551    $convert_replaces[] = "rcmail_str_replacement('<a href=\"\\1://\\2\" target=\"_blank\">\\1://\\2</a>', \$replace_strings)";
552
553    $convert_patterns[] = "/([^\/:]|\s)(www\.)([a-z0-9\-]{2,}[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
554    $convert_replaces[] = "rcmail_str_replacement('\\1<a href=\"http://\\2\\3\" target=\"_blank\">\\2\\3</a>', \$replace_strings)";
555   
556    $convert_patterns[] = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/ie';
557    $convert_replaces[] = "rcmail_str_replacement('<a href=\"mailto:\\1\" onclick=\"return ".JS_OBJECT_NAME.".command(\'compose\',\'\\1\',this)\">\\1</a>', \$replace_strings)";
558   
559    if ($part->ctype_parameters['format'] != 'flowed')
560      $body = wordwrap(trim($body), 80);
561
562    $body = preg_replace($convert_patterns, $convert_replaces, $body);
563
564    // split body into single lines
565    $a_lines = preg_split('/\r?\n/', $body);
566    $quote_level = 0;
567
568    // colorize quoted parts
569    for($n=0; $n<sizeof($a_lines); $n++)
570      {
571      $line = $a_lines[$n];
572      $quotation = '';
573      $q = 0;
574     
575      if (preg_match('/^(>+\s*)/', $line, $regs))
576        {
577        $q = strlen(preg_replace('/\s/', '', $regs[1]));
578        $line = substr($line, strlen($regs[1]));
579
580        if ($q > $quote_level)
581          $quotation = str_repeat('<blockquote>', $q - $quote_level);
582        else if ($q < $quote_level)
583          $quotation = str_repeat("</blockquote>", $quote_level - $q);
584        }
585      else if ($quote_level > 0)
586        $quotation = str_repeat("</blockquote>", $quote_level);
587
588      $quote_level = $q;
589      $a_lines[$n] = $quotation . Q($line, 'replace', FALSE);
590      }
591
592    // insert the links for urls and mailtos
593    $body = preg_replace("/##string_replacement\{([0-9]+)\}##/e", "\$replace_strings[\\1]", join("\n", $a_lines));
594   
595    return "<div class=\"pre\">".$body."\n</div>";
596    }
597  }
598
599
600
601// add a string to the replacement array and return a replacement string
602function rcmail_str_replacement($str, &$rep)
603  {
604  static $count = 0;
605  $rep[$count] = stripslashes($str);
606  return "##string_replacement{".($count++)."}##";
607  }
608
609
610function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE)
611  {
612  global $IMAP;
613  static $sa_inline_objects = array();
614
615  // arguments are: (bool)$prefer_html, (string)$get_url
616  extract($arg);
617
618  $a_attachments = array();
619  $a_return_parts = array();
620  $out = '';
621
622  $message_ctype_primary = strtolower($structure->ctype_primary);
623  $message_ctype_secondary = strtolower($structure->ctype_secondary);
624
625  // show message headers
626  if ($recursive && is_array($structure->headers) && isset($structure->headers['subject']))
627    {
628    $c = new stdClass;
629    $c->type = 'headers';
630    $c->headers = &$structure->headers;
631    $a_return_parts[] = $c;
632    }
633
634  // print body if message doesn't have multiple parts
635  if ($message_ctype_primary=='text')
636    {
637    $structure->type = 'content';
638    $a_return_parts[] = &$structure;
639    }
640
641  // message contains alternative parts
642  else if ($message_ctype_primary=='multipart' && $message_ctype_secondary=='alternative' && is_array($structure->parts))
643    {
644    // get html/plaintext parts
645    $plain_part = $html_part = $print_part = $related_part = NULL;
646   
647    foreach ($structure->parts as $p => $sub_part)
648      {
649      $rel_parts = $attachmnts = null;
650      $sub_ctype_primary = strtolower($sub_part->ctype_primary);
651      $sub_ctype_secondary = strtolower($sub_part->ctype_secondary);
652
653      // check if sub part is
654      if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='plain')
655        $plain_part = $p;
656      else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='html')
657        $html_part = $p;
658      else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='enriched')
659        $enriched_part = $p;
660      else if ($sub_ctype_primary=='multipart' && ($sub_ctype_secondary=='related' || $sub_ctype_secondary=='mixed'))
661        $related_part = $p;
662      }
663     
664    // parse related part (alternative part could be in here)
665    if ($related_part!==NULL)
666    {
667      list($rel_parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE);
668      $a_attachments = array_merge($a_attachments, $attachmnts);
669    }
670   
671    // merge related parts if any
672    if ($rel_parts && $prefer_html && !$html_part)
673      $a_return_parts = array_merge($a_return_parts, $rel_parts);
674
675    // choose html/plain part to print
676    else if ($html_part!==NULL && $prefer_html)
677      $print_part = &$structure->parts[$html_part];
678    else if ($enriched_part!==NULL)
679      $print_part = &$structure->parts[$enriched_part];
680    else if ($plain_part!==NULL)
681      $print_part = &$structure->parts[$plain_part];
682
683    // show message body
684    if (is_object($print_part))
685      {
686      $print_part->type = 'content';
687      $a_return_parts[] = $print_part;
688      }
689    // show plaintext warning
690    else if ($html_part!==NULL && empty($a_return_parts))
691      {
692      $c = new stdClass;
693      $c->type = 'content';
694      $c->body = rcube_label('htmlmessage');
695      $c->ctype_primary = 'text';
696      $c->ctype_secondary = 'plain';
697     
698      $a_return_parts[] = $c;
699      }
700                               
701    // add html part as attachment
702    if ($html_part!==NULL && $structure->parts[$html_part]!==$print_part)
703      {
704      $html_part = &$structure->parts[$html_part];
705      $html_part->filename = rcube_label('htmlmessage');
706      $html_part->mimetype = 'text/html';
707     
708      $a_attachments[] = $html_part;
709      }
710    }
711
712  // message contains multiple parts
713  else if (is_array($structure->parts) && !empty($structure->parts))
714    {
715    for ($i=0; $i<count($structure->parts); $i++)
716      {
717      $mail_part = &$structure->parts[$i];
718      $primary_type = strtolower($mail_part->ctype_primary);
719      $secondary_type = strtolower($mail_part->ctype_secondary);
720
721      // multipart/alternative
722      if ($primary_type=='multipart')
723        {
724        list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
725
726        $a_return_parts = array_merge($a_return_parts, $parts);
727        $a_attachments = array_merge($a_attachments, $attachmnts);
728        }
729
730      // part text/[plain|html] OR message/delivery-status
731      else if (($primary_type=='text' && ($secondary_type=='plain' || $secondary_type=='html') && $mail_part->disposition!='attachment') ||
732               ($primary_type=='message' && $secondary_type=='delivery-status'))
733        {
734        $mail_part->type = 'content';
735        $a_return_parts[] = $mail_part;
736        }
737
738      // part message/*
739      else if ($primary_type=='message')
740        {
741        list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE);
742         
743        $a_return_parts = array_merge($a_return_parts, $parts);
744        $a_attachments = array_merge($a_attachments, $attachmnts);
745        }
746
747      // part is file/attachment
748      else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] ||
749               (empty($mail_part->disposition) && $mail_part->filename))
750        {
751        // skip apple resource forks
752        if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile')
753          continue;
754
755        // part belongs to a related message
756        if ($message_ctype_secondary=='related' && $mail_part->headers['content-id'])
757          {
758          $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
759          $sa_inline_objects[] = $mail_part;
760          }
761        // is regular attachment
762        else
763          {
764          if (!$mail_part->filename)
765            $mail_part->filename = 'file_'.$mail_part->mime_id;
766          $a_attachments[] = $mail_part;
767          }
768        }
769      }
770
771    // if this was a related part try to resolve references
772    if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects))
773      {
774      $a_replaces = array();
775       
776      foreach ($sa_inline_objects as $inline_object)
777        $a_replaces['cid:'.$inline_object->content_id] = htmlspecialchars(sprintf($get_url, $inline_object->mime_id));
778     
779      // add replace array to each content part
780      // (will be applied later when part body is available)
781      for ($i=0; $i<count($a_return_parts); $i++)
782        {
783        if ($a_return_parts[$i]->type=='content')
784          $a_return_parts[$i]->replaces = $a_replaces;
785        }
786      }
787    }
788
789  // message is single part non-text
790  else if ($structure->filename)
791    $a_attachments[] = $structure;
792
793  return array($a_return_parts, $a_attachments);
794  }
795
796
797
798
799// return table with message headers
800function rcmail_message_headers($attrib, $headers=NULL)
801  {
802  global $IMAP, $OUTPUT, $MESSAGE;
803  static $sa_attrib;
804 
805  // keep header table attrib
806  if (is_array($attrib) && !$sa_attrib)
807    $sa_attrib = $attrib;
808  else if (!is_array($attrib) && is_array($sa_attrib))
809    $attrib = $sa_attrib;
810 
811 
812  if (!isset($MESSAGE))
813    return FALSE;
814
815  // get associative array of headers object
816  if (!$headers)
817    $headers = is_object($MESSAGE['headers']) ? get_object_vars($MESSAGE['headers']) : $MESSAGE['headers'];
818 
819  $header_count = 0;
820 
821  // allow the following attributes to be added to the <table> tag
822  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
823  $out = '<table' . $attrib_str . ">\n";
824
825  // show these headers
826  $standard_headers = array('subject', 'from', 'organization', 'to', 'cc', 'bcc', 'reply-to', 'date');
827 
828  foreach ($standard_headers as $hkey)
829    {
830    if (!$headers[$hkey])
831      continue;
832
833    if ($hkey=='date' && !empty($headers[$hkey]))
834      $header_value = format_date(strtotime($headers[$hkey]));
835    else if (in_array($hkey, array('from', 'to', 'cc', 'bcc', 'reply-to')))
836      $header_value = Q(rcmail_address_string($headers[$hkey], NULL, $attrib['addicon']), 'show');
837    else
838      $header_value = Q(rcube_imap::decode_mime_string($headers[$hkey], $headers['charset']));
839
840    $out .= "\n<tr>\n";
841    $out .= '<td class="header-title">'.Q(rcube_label($hkey)).":&nbsp;</td>\n";
842    $out .= '<td class="'.$hkey.'" width="90%">'.$header_value."</td>\n</tr>";
843    $header_count++;
844    }
845
846  $out .= "\n</table>\n\n";
847
848  return $header_count ? $out : ''; 
849  }
850
851
852
853function rcmail_message_body($attrib)
854  {
855  global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $GET_URL, $REMOTE_OBJECTS;
856 
857  if (!is_array($MESSAGE['parts']) && !$MESSAGE['body'])
858    return '';
859   
860  if (!$attrib['id'])
861    $attrib['id'] = 'rcmailMsgBody';
862
863  $safe_mode = (bool)$_GET['_safe'];
864  $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
865  $out = '<div '. $attrib_str . ">\n";
866 
867  $header_attrib = array();
868  foreach ($attrib as $attr => $value)
869    if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs))
870      $header_attrib[$regs[1]] = $value;
871
872
873  // this is an ecrypted message
874  // -> create a plaintext body with the according message
875  if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted')
876    {
877    $p = new stdClass;
878    $p->type = 'content';
879    $p->ctype_primary = 'text';
880    $p->ctype_secondary = 'plain';
881    $p->body = rcube_label('encryptedmessage');
882    $MESSAGE['parts'][0] = $p;
883    }
884 
885  if ($MESSAGE['parts'])
886    {
887    foreach ($MESSAGE['parts'] as $i => $part)
888      {
889      if ($part->type=='headers')
890        $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers);
891      else if ($part->type=='content')
892        {
893        if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset']))
894          $part->ctype_parameters['charset'] = $MESSAGE['headers']->charset;
895
896        // fetch part if not available
897        if (!isset($part->body))
898          $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part);
899
900        $body = rcmail_print_body($part, $safe_mode, !$CONFIG['prefer_html']);
901        $out .= '<div class="message-part">';
902       
903        if ($part->ctype_secondary != 'plain')
904          $out .= rcmail_sanitize_html($body, $attrib['id']);
905        else
906          $out .= $body;
907
908        $out .= "</div>\n";
909        }
910      }
911    }
912  else
913    $out .= $MESSAGE['body'];
914
915
916  $ctype_primary = strtolower($MESSAGE['structure']->ctype_primary);
917  $ctype_secondary = strtolower($MESSAGE['structure']->ctype_secondary);
918 
919  // list images after mail body
920  if (get_boolean($attrib['showimages']) && $ctype_primary=='multipart' &&
921      !empty($MESSAGE['attachments']) && !strstr($message_body, '<html') && strlen($GET_URL))
922    {
923    foreach ($MESSAGE['attachments'] as $attach_prop)
924      {
925      if (strpos($attach_prop->mimetype, 'image/')===0)
926        $out .= sprintf("\n<hr />\n<p align=\"center\"><img src=\"%s&amp;_part=%s\" alt=\"%s\" title=\"%s\" /></p>\n",
927                        htmlspecialchars($GET_URL), $attach_prop->mime_id,
928                        $attach_prop->filename,
929                        $attach_prop->filename);
930      }
931    }
932 
933  // tell client that there are blocked remote objects
934  if ($REMOTE_OBJECTS && !$safe_mode)
935    $OUTPUT->set_env('blockedobjects', true);
936
937  $out .= "\n</div>";
938  return $out;
939  }
940
941
942
943// modify a HTML message that it can be displayed inside a HTML page
944function rcmail_sanitize_html($body, $container_id)
945  {
946  // remove any null-byte characters before parsing
947  $body = preg_replace('/\x00/', '', $body);
948 
949  $last_style_pos = 0;
950  $body_lc = strtolower($body);
951 
952  // find STYLE tags
953  while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
954    {
955    $pos = strpos($body_lc, '>', $pos)+1;
956
957    // replace all css definitions with #container [def]
958    $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id);
959
960    $body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
961    $body_lc = strtolower($body);
962    $last_style_pos = $pos2;
963    }
964
965
966  // remove SCRIPT tags
967  foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag)
968    {
969    while (($pos = strpos($body_lc, '<'.$tag)) && ($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)))
970      {
971      $pos2 += strlen('</'.$tag.'>');
972      $body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2);
973      $body_lc = strtolower($body);
974      }
975    }
976
977  // replace event handlers on any object
978  while ($body != $prev_body)
979    {
980    $prev_body = $body;
981    $body = preg_replace('/(<[^!][^>]*\s)(on[^=>]+)=([^>]+>)/im', '$1__removed=$3', $body);
982    $body = preg_replace('/(<[^!][^>]*\shref=["\']?)(javascript:)([^>]*?>)/im', '$1null:$3', $body);
983    }
984
985  // resolve <base href>
986  $base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i';
987  if (preg_match($base_reg, $body, $regs))
988    {
989    $base_url = $regs[2];
990    $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body);
991    $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body);
992    $body = preg_replace($base_reg, '', $body);
993    }
994   
995  // modify HTML links to open a new window if clicked
996  $body = preg_replace('/<a\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1');", $body);
997
998  // add comments arround html and other tags
999  $out = preg_replace(array(
1000      '/(<!DOCTYPE.+)/i',
1001      '/(<\/?html[^>]*>)/i',
1002      '/(<\/?head[^>]*>)/i',
1003      '/(<title[^>]*>.*<\/title>)/Ui',
1004      '/(<\/?meta[^>]*>)/i'),
1005    '<!--\\1-->',
1006    $body);
1007
1008  $out = preg_replace(array('/<body([^>]*)>/i',
1009                            '/<\/body>/i'),
1010                      array('<div class="rcmBody"\\1>',
1011                            '</div>'),
1012                      $out);
1013
1014  // quote <? of php and xml files that are specified as text/html
1015  $out = preg_replace(array('/<\?/', '/\?>/'), array('&lt;?', '?&gt;'), $out);
1016
1017  return $out;
1018  }
1019
1020
1021// parse link attributes and set correct target
1022function rcmail_alter_html_link($in)
1023  {
1024  $in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in);
1025  $attrib = parse_attrib_string($in);
1026
1027  if (stristr((string)$attrib['href'], 'mailto:'))
1028    $attrib['onclick'] = sprintf("return %s.command('compose','%s',this)",
1029                                 JS_OBJECT_NAME,
1030                                 JQ(substr($attrib['href'], 7)));
1031  else if (!empty($attrib['href']) && $attrib['href']{0}!='#')
1032    $attrib['target'] = '_blank';
1033 
1034  return '<a' . create_attrib_string($attrib, array('href', 'name', 'target', 'onclick', 'id', 'class', 'style', 'title')) . '>';
1035  }
1036
1037
1038// replace all css definitions with #container [def]
1039function rcmail_mod_css_styles($source, $container_id)
1040  {
1041  $a_css_values = array();
1042  $last_pos = 0;
1043 
1044  // cut out all contents between { and }
1045  while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos)))
1046    {
1047    $key = sizeof($a_css_values);
1048    $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1));
1049    $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2);
1050    $last_pos = $pos+2;
1051    }
1052
1053  // remove html commends and add #container to each tag selector.
1054  // also replace body definition because we also stripped off the <body> tag
1055  $styles = preg_replace(array('/(^\s*<!--)|(-->\s*$)/', '/(^\s*|,\s*|\}\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im', '/<<str_replacement\[([0-9]+)\]>>/e', "/$container_id\s+body/i"),
1056                         array('', "\\1#$container_id \\2", "\$a_css_values[\\1]", "$container_id div.rcmBody"),
1057                         $source);
1058
1059  return $styles;
1060  }
1061
1062
1063function rcmail_has_html_part($message_parts)
1064{
1065   if (!is_array($message_parts))
1066      return FALSE;
1067
1068   // check all message parts
1069   foreach ($message_parts as $pid => $part)
1070   {
1071      $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1072      if ($mimetype=='text/html')
1073      {
1074         return TRUE;
1075      }
1076   }
1077   
1078   return FALSE;
1079}
1080
1081// return first HTML part of a message
1082function rcmail_first_html_part($message_struct)
1083  {
1084  global $IMAP;
1085
1086  if (!is_array($message_struct['parts']))
1087    return FALSE;
1088   
1089  $html_part = NULL;
1090
1091  // check all message parts
1092  foreach ($message_struct['parts'] as $pid => $part)
1093    {
1094    $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1095    if ($mimetype=='text/html')
1096      {
1097      $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1098      }
1099    }
1100
1101  if ($html_part)
1102    {
1103    // remove special chars encoding
1104    //$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1105    //$html_part = strtr($html_part, $trans);
1106
1107    return $html_part;
1108    }
1109
1110  return FALSE;
1111}
1112
1113
1114// return first text part of a message
1115function rcmail_first_text_part($message_struct)
1116  {
1117  global $IMAP;
1118
1119  if (empty($message_struct['parts']))
1120    return $message_struct['UID'] ? $IMAP->get_body($message_struct['UID']) : false;
1121
1122  // check all message parts
1123  foreach ($message_struct['parts'] as $pid => $part)
1124    {
1125    $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
1126
1127    if ($mimetype=='text/plain')
1128      return $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1129
1130    else if ($mimetype=='text/html')
1131      {
1132      $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
1133     
1134      // remove special chars encoding
1135      $trans = array_flip(get_html_translation_table(HTML_ENTITIES));
1136      $html_part = strtr($html_part, $trans);
1137
1138      // create instance of html2text class
1139      $txt = new html2text($html_part);
1140      return $txt->get_text();
1141      }
1142    }
1143
1144  return FALSE;
1145  }
1146
1147
1148// decode address string and re-format it as HTML links
1149function rcmail_address_string($input, $max=NULL, $addicon=NULL)
1150  {
1151  global $IMAP, $PRINT_MODE, $CONFIG, $OUTPUT, $EMAIL_ADDRESS_PATTERN;
1152 
1153  $a_parts = $IMAP->decode_address_list($input);
1154
1155  if (!sizeof($a_parts))
1156    return $input;
1157
1158  $c = count($a_parts);
1159  $j = 0;
1160  $out = '';
1161
1162  foreach ($a_parts as $part)
1163    {
1164    $j++;
1165    if ($PRINT_MODE)
1166      $out .= sprintf('%s &lt;%s&gt;', Q($part['name']), $part['mailto']);
1167    else if (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto']))
1168      {
1169      $out .= sprintf('<a href="mailto:%s" onclick="return %s.command(\'compose\',\'%s\',this)" class="rcmContactAddress" title="%s">%s</a>',
1170                      Q($part['mailto']),
1171                      JS_OBJECT_NAME,
1172                      JQ($part['mailto']),
1173                      Q($part['mailto']),
1174                      Q($part['name']));
1175                     
1176      if ($addicon)
1177        $out .= sprintf('&nbsp;<a href="#add" onclick="return %s.command(\'add-contact\',\'%s\',this)" title="%s"><img src="%s%s" alt="add" border="0" /></a>',
1178                        JS_OBJECT_NAME,
1179                        urlencode($part['string']),
1180                        rcube_label('addtoaddressbook'),
1181                        $CONFIG['skin_path'],
1182                        $addicon);
1183      }
1184    else
1185      {
1186      if ($part['name'])
1187        $out .= Q($part['name']);
1188      if ($part['mailto'])
1189        $out .= (strlen($out) ? ' ' : '') . sprintf('&lt;%s&gt;', Q($part['mailto']));
1190      }
1191     
1192    if ($c>$j)
1193      $out .= ','.($max ? '&nbsp;' : ' ');
1194       
1195    if ($max && $j==$max && $c>$j)
1196      {
1197      $out .= '...';
1198      break;
1199      }       
1200    }
1201   
1202  return $out;
1203  }
1204
1205
1206function rcmail_message_part_controls()
1207  {
1208  global $CONFIG, $IMAP, $MESSAGE;
1209 
1210  if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']])
1211    return '';
1212   
1213  $part = &$MESSAGE['parts'][$_GET['_part']];
1214 
1215  $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary'));
1216  $out = '<table '. $attrib_str . ">\n";
1217 
1218  if ($filename)
1219    {
1220    $out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
1221                    Q(rcube_label('filename')),
1222                    Q($part->filename),
1223                    str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
1224                    Q(rcube_label('download')));
1225    }
1226   
1227  if ($part->size)
1228    $out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n",
1229                    Q(rcube_label('filesize')),
1230                    show_bytes($part->size));
1231 
1232  $out .= "\n</table>";
1233 
1234  return $out;
1235  }
1236
1237
1238
1239function rcmail_message_part_frame($attrib)
1240  {
1241  global $MESSAGE;
1242 
1243  $part = $MESSAGE['parts'][$_GET['_part']];
1244  $ctype_primary = strtolower($part->ctype_primary);
1245
1246  $attrib['src'] = Q('./?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']));
1247
1248  $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height'));
1249  $out = '<iframe '. $attrib_str . "></iframe>";
1250   
1251  return $out;
1252  }
1253
1254
1255// clear message composing settings
1256function rcmail_compose_cleanup()
1257  {
1258  if (!isset($_SESSION['compose']))
1259    return;
1260
1261  // remove attachment files from temp dir
1262  if (is_array($_SESSION['compose']['attachments']))
1263    foreach ($_SESSION['compose']['attachments'] as $attachment)
1264      @unlink($attachment['path']);
1265 
1266  unset($_SESSION['compose']);
1267  }
1268
1269
1270// register UI objects
1271$OUTPUT->add_handlers(array(
1272  'mailboxlist' => 'rcmail_mailbox_list',
1273  'messages' => 'rcmail_message_list',
1274  'messagecountdisplay' => 'rcmail_messagecount_display',
1275  'quotadisplay' => 'rcmail_quota_display',
1276  'messageheaders' => 'rcmail_message_headers',
1277  'messagebody' => 'rcmail_message_body',
1278  'messagecontentframe' => 'rcmail_messagecontent_frame',
1279  'messagepartframe' => 'rcmail_message_part_frame',
1280  'messagepartcontrols' => 'rcmail_message_part_controls',
1281  'searchform' => 'rcmail_search_form'
1282));
1283
1284?>
Note: See TracBrowser for help on using the repository browser.