source: subversion/trunk/roundcubemail/program/steps/mail/func.inc @ 938

Last change on this file since 938 was 938, checked in by thomasb, 5 years ago

New class rcube_user + send message disposition notification

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