From ad18d63cc15d7b0a77a5d90dc9f8bd7476b90c8d Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Fri, 05 Feb 2010 03:25:22 -0500
Subject: [PATCH] - Fix handling of extended mailto links (with params) (#1486354)

---
 program/steps/mail/func.inc |  371 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 206 insertions(+), 165 deletions(-)

diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 213b67e..e9adc15 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -19,9 +19,7 @@
 
 */
 
-require_once('include/rcube_smtp.inc');
-
-$EMAIL_ADDRESS_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})';
+$EMAIL_ADDRESS_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9][a-z0-9\-\.]*\\.[a-z]{2,5})';
 
 // actions that do not require imap connection
 $NOIMAP_ACTIONS = array('spell', 'addcontact', 'autocomplete', 'upload', 'display-attachment', 'remove-attachment');
@@ -95,6 +93,8 @@
     $OUTPUT->set_env('read_when_deleted', true);
   if ($CONFIG['skip_deleted'])
     $OUTPUT->set_env('skip_deleted', true);
+  if ($CONFIG['display_next'])
+    $OUTPUT->set_env('display_next', true);
 	  
   if ($CONFIG['trash_mbox'])
     $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
@@ -152,10 +152,11 @@
   $a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
 
   $mbox = $IMAP->get_mailbox_name();
-  
-  // show 'to' instead of from in sent messages
-  if (($mbox==$CONFIG['sent_mbox'] || $mbox==$CONFIG['drafts_mbox']) && ($f = array_search('from', $a_show_cols))
-      && !array_search('to', $a_show_cols))
+  $delim = $IMAP->get_hierarchy_delimiter();
+
+  // show 'to' instead of 'from' in sent/draft messages
+  if ((strpos($mbox.$delim, $CONFIG['sent_mbox'].$delim)===0 || strpos($mbox.$delim, $CONFIG['drafts_mbox'].$delim)===0)
+      && ($f = array_search('from', $a_show_cols)) && !array_search('to', $a_show_cols))
     $a_show_cols[$f] = 'to';
   
   // add col definition
@@ -244,7 +245,6 @@
   if (!sizeof($a_headers))
     $OUTPUT->show_message('nomessagesfound', 'notice');
 
-
   $a_js_message_arr = array();
 
   // create row for each message
@@ -301,13 +301,12 @@
     
     $out .= sprintf("<td class=\"icon\">%s</td>\n", $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : '');
 
-
     $IMAP->set_charset(!empty($header->charset) ? $header->charset : $CONFIG['default_charset']);
   
     // format each col
     foreach ($a_show_cols as $col)
       {
-      if ($col=='from' || $col=='to')
+      if (in_array($col, array('from', 'to', 'cc', 'replyto')))
         $cont = Q(rcmail_address_string($header->$col, 3, false, $attrib['addicon']), 'show');
       else if ($col=='subject')
         {
@@ -315,7 +314,7 @@
         $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draft_uid' : '_uid';
         $cont = abbreviate_string(trim($IMAP->decode_header($header->$col)), 160);
         if (empty($cont)) $cont = rcube_label('nosubject');
-        $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), Q($cont));
+        $cont = $OUTPUT->browser->ie ? Q($cont) : sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), Q($cont));
         }
       else if ($col=='flag')
         $cont = $flagged_icon ? sprintf($image_tag, $skin_path, $flagged_icon, '') : '';
@@ -394,15 +393,23 @@
     $a_show_cols = $_SESSION['list_columns'];
 
   $mbox = $IMAP->get_mailbox_name();
-
-  // show 'to' instead of from in sent messages
-  if (($mbox == $CONFIG['sent_mbox'] || $mbox == $CONFIG['drafts_mbox'])
+  $delim = $IMAP->get_hierarchy_delimiter();
+  
+  // show 'to' instead of 'from' in sent/draft messages
+  if ((strpos($mbox.$delim, $CONFIG['sent_mbox'].$delim)===0 || strpos($mbox.$delim, $CONFIG['drafts_mbox'].$delim)===0)
       && (($f = array_search('from', $a_show_cols)) !== false) && array_search('to', $a_show_cols) === false)
     $a_show_cols[$f] = 'to';
 
   $browser = new rcube_browser;
 
   $OUTPUT->command('set_message_coltypes', $a_show_cols);
+
+  // remove 'attachment' and 'flag' columns, we don't need them here
+  if(($key = array_search('attachment', $a_show_cols)) !== FALSE)
+    unset($a_show_cols[$key]);
+  if(($key = array_search('flag', $a_show_cols)) !== FALSE)
+    unset($a_show_cols[$key]);
+
   if ($browser->ie && $replace)
     $OUTPUT->command('offline_message_list', true);
 
@@ -417,24 +424,18 @@
 
     $IMAP->set_charset(!empty($header->charset) ? $header->charset : $CONFIG['default_charset']);
 
-    // remove 'attachment' and 'flag' columns, we don't need them here
-    if(($key = array_search('attachment', $a_show_cols)) !== FALSE)
-      unset($a_show_cols[$key]);
-    if(($key = array_search('flag', $a_show_cols)) !== FALSE)
-      unset($a_show_cols[$key]);
-
     // format each col; similar as in rcmail_message_list()
     foreach ($a_show_cols as $col)
       {
-      if ($col=='from' || $col=='to')
+      if (in_array($col, array('from', 'to', 'cc', 'replyto')))
         $cont = Q(rcmail_address_string($header->$col, 3), 'show');
       else if ($col=='subject')
         {
         $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
         $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draft_uid' : '_uid';
-        $cont = abbreviate_string(trim($IMAP->decode_header($header->$col)), 160);
+	$cont = abbreviate_string(trim($IMAP->decode_header($header->$col)), 160);
         if (!$cont) $cont = rcube_label('nosubject');
-        $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), Q($cont));
+        $cont = $browser->ie ? Q($cont) : sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), Q($cont));
         }
       else if ($col=='size')
         $cont = show_bytes($header->$col);
@@ -456,7 +457,7 @@
       $a_msg_flags['forwarded'] = 1;
     if ($header->flagged)
       $a_msg_flags['flagged'] = 1;
-    
+      
     $OUTPUT->command('add_message_row',
       $header->uid,
       $a_msg_cols,
@@ -465,8 +466,8 @@
       $insert_top);
     }
 
-    if ($browser->ie && $replace)
-      $OUTPUT->command('offline_message_list', false);
+  if ($browser->ie && $replace)
+    $OUTPUT->command('offline_message_list', false);
   }
 
 
@@ -489,9 +490,6 @@
   }
 
 
-/**
- *
- */
 function rcmail_messagecount_display($attrib)
   {
   global $IMAP, $OUTPUT;
@@ -505,9 +503,6 @@
   }
 
 
-/**
- *
- */
 function rcmail_quota_display($attrib)
   {
   global $OUTPUT, $COMM_PATH;
@@ -519,69 +514,59 @@
     $_SESSION['quota_display'] = $attrib['display'];
 
   $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
-
-  return html::span($attrib, rcmail_quota_content(NULL, $attrib));
+  
+  $quota = rcmail_quota_content($attrib);
+  
+  if (is_array($quota)) {
+    $OUTPUT->add_script('$(document).ready(function(){
+	rcmail.set_quota('.json_serialize($quota).')});', 'foot');
+    $quota = '';
+    }
+  
+  return html::span($attrib, $quota);
   }
 
 
-/**
- *
- */
-function rcmail_quota_content($quota=NULL, $attrib=NULL)
+function rcmail_quota_content($attrib=NULL)
   {
-  global $IMAP, $COMM_PATH, $RCMAIL;
+  global $COMM_PATH, $RCMAIL;
 
   $display = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : '';
 
-  if (is_array($quota) && !empty($quota['used']) && !empty($quota['total']))
-    {
-      if (!isset($quota['percent']))
-        $quota['percent'] = $quota['used'] / $quota['total'];
-    }
-  elseif (!$IMAP->get_capability('QUOTA'))
+  $quota = $RCMAIL->imap->get_quota();
+  $quota = $RCMAIL->plugins->exec_hook('quota', $quota);
+
+  if (!isset($quota['used']) || !isset($quota['total']))
     return rcube_label('unknown');
-  else
-    $quota = $IMAP->get_quota();
 
-  if ($quota && !($quota['total']==0 && $RCMAIL->config->get('quota_zero_as_unlimited')))
+  if (!($quota['total']==0 && $RCMAIL->config->get('quota_zero_as_unlimited')))
     {
-    $quota_text = sprintf('%s / %s (%.0f%%)',
-                          show_bytes($quota['used'] * 1024),
-                          show_bytes($quota['total'] * 1024),
-                          $quota['percent']);
+    if (!isset($quota['percent']))
+      $quota['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100));
+    
+    $quota_result = sprintf('%s / %s (%.0f%%)',
+        show_bytes($quota['used'] * 1024), show_bytes($quota['total'] * 1024),
+        $quota['percent']);
 
-    // show quota as image (by Brett Patterson)
-    if ($display == 'image' && function_exists('imagegif'))
-      {
-      if (!$attrib['width'])
-        $attrib['width'] = isset($_SESSION['quota_width']) ? $_SESSION['quota_width'] : 100;
-      else
-	$_SESSION['quota_width'] = $attrib['width'];
+    if ($display == 'image') {
+      $quota_result = array(
+    	'percent' 	=> $quota['percent'],
+        'title'		=> $quota_result,
+	);
 
-      if (!$attrib['height'])
-        $attrib['height'] = isset($_SESSION['quota_height']) ? $_SESSION['quota_height'] : 14;
-      else
-	$_SESSION['quota_height'] = $attrib['height'];
-	    
-      $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" />',
-                            $quota['used'], $quota['total'],
-                            $attrib['width'], $attrib['height'],
-                            $attrib['width'], $attrib['height'],
-                            $quota_text,
-                            show_bytes($quota['used'] * 1024),
-                            show_bytes($quota['total'] * 1024));
+      if ($attrib['width'])
+        $quota_result['width'] = $attrib['width'];
+      if ($attrib['height'])
+        $quota_result['height']	= $attrib['height'];
       }
     }
   else
-    $quota_text = rcube_label('unlimited');
+    return rcube_label('unlimited');
 
-  return $quota_text;
+  return $quota_result;
   }
 
 
-/**
- *
- */
 function rcmail_get_messagecount_text($count=NULL, $page=NULL)
   {
   global $IMAP, $MESSAGE;
@@ -610,26 +595,43 @@
   return Q($out);
   }
 
-/**
- *
- */
+
 function rcmail_mailbox_name_display($attrib)
 {
-    global $RCMAIL;
+  global $RCMAIL;
 
-    if (!$attrib['id'])
-        $attrib['id'] = 'rcmmailboxname';
+  if (!$attrib['id'])
+    $attrib['id'] = 'rcmmailboxname';
 
-    $RCMAIL->output->add_gui_object('mailboxname', $attrib['id']);
+  $RCMAIL->output->add_gui_object('mailboxname', $attrib['id']);
 
-    return html::span($attrib, rcmail_get_mailbox_name_text());
+  return html::span($attrib, rcmail_get_mailbox_name_text());
 }
+
 
 function rcmail_get_mailbox_name_text()
 {
-    global $RCMAIL;
-    return rcmail_localize_foldername($RCMAIL->imap->get_mailbox_name());
+  global $RCMAIL;
+  return rcmail_localize_foldername($RCMAIL->imap->get_mailbox_name());
 }
+
+
+function rcmail_send_unread_count($mbox_name, $force=false)
+{
+  global $RCMAIL;
+    
+  $old_unseen = $_SESSION['unseen_count'][$mbox_name];
+  $unseen = $RCMAIL->imap->messagecount($mbox_name, 'UNSEEN', $force);
+
+  if ($unseen != $old_unseen || ($mbox_name == 'INBOX'))
+    $RCMAIL->output->command('set_unread_count', $mbox_name, $unseen, ($mbox_name == 'INBOX'));
+
+  // @TODO: this data is doubled (session and cache tables) if caching is enabled
+  $_SESSION['unseen_count'][$mbox_name] = $unseen;
+    
+  return $unseen;
+}
+
 
 /**
  * Sets message is_safe flag according to 'show_images' option value
@@ -659,6 +661,7 @@
   }
 }
 
+
 /**
  * Cleans up the given message HTML Body (for displaying)
  *
@@ -672,40 +675,38 @@
   global $REMOTE_OBJECTS;
   
   $p += array('safe' => false, 'inline_html' => true);
-  
+
   // special replacements (not properly handled by washtml class)
   $html_search = array(
     '/(<\/nobr>)(\s+)(<nobr>)/i',	// space(s) between <NOBR>
-    '/(<[\/]*st1:[^>]+>)/i',		// Microsoft's Smart Tags <ST1>
-    '/<\/?rte_text>/i',			// Rich Text Editor tags (#1485647)
-    '/<title>.*<\/title>/i',		// PHP bug #32547 workaround: remove title tag
-    '/<html[^>]*>/im',			// malformed html: remove html tags (#1485139)
-    '/<\/html>/i',			// malformed html: remove html tags (#1485139)
+    '/<title[^>]*>.*<\/title>/i',		// PHP bug #32547 workaround: remove title tag
     '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/',	// byte-order mark (only outlook?)
+    '/<html\s[^>]+>/i',			// washtml/DOMDocument cannot handle xml namespaces
   );
   $html_replace = array(
     '\\1'.' &nbsp; '.'\\3',
     '',
     '',
-    '',
-    '',
-    '',
-    '',
+    '<html>',
   );
   $html = preg_replace($html_search, $html_replace, $html);
 
-  // charset was converted to UTF-8 in rcube_imap::get_message_part() -> change charset specification in HTML accordingly
-  $charset_pattern = '/(\s+content=[\'"]?\w+\/\w+;\s*charset)=([a-z0-9-_]+)/i';
-  if (preg_match($charset_pattern, $html)) {
-    $html = preg_replace($charset_pattern, '\\1='.RCMAIL_CHARSET, $html);
+  // fix (unknown/malformed) HTML tags before "wash"
+  $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', 'rcmail_html_tag_callback', $html);
+
+  // charset was converted to UTF-8 in rcube_imap::get_message_part(),
+  // -> change charset specification in HTML accordingly
+  $charset_pattern = '(<meta\s+[^>]*)(content=[\'"]?\w+\/\w+;\s*charset)=([a-z0-9-_]+)';
+  if (preg_match("/$charset_pattern/Ui", $html)) {
+    $html = preg_replace("/$charset_pattern/i", '\\1\\2='.RCMAIL_CHARSET, $html);
   }
   else {
-    // add head for malformed messages, washtml cannot work without that
+    // add meta content-type to malformed messages, washtml cannot work without that
     if (!preg_match('/<head[^>]*>(.*)<\/head>/Uims', $html))
       $html = '<head></head>'. $html;
-    $html = substr_replace($html, '<meta http-equiv="content-type" content="text/html; charset='.RCMAIL_CHARSET.'" />', intval(stripos($html, '<head>')+6), 0);
+    $html = substr_replace($html, '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />', intval(stripos($html, '<head>')+6), 0);
   }
-    
+
   // turn relative into absolute urls
   $html = rcmail_resolve_base($html);
 
@@ -730,13 +731,12 @@
   $washer = new washtml($wash_opts);
   $washer->add_callback('form', 'rcmail_washtml_callback');
 
-  if ($p['safe']) {  // allow CSS styles, will be sanitized by rcmail_washtml_callback()
-    $washer->add_callback('style', 'rcmail_washtml_callback');
-  }
-    
+  // allow CSS styles, will be sanitized by rcmail_washtml_callback()
+  $washer->add_callback('style', 'rcmail_washtml_callback');
+
   $html = $washer->wash($html);
   $REMOTE_OBJECTS = $washer->extlinks;
-  
+
   return $html;
 }
 
@@ -784,57 +784,77 @@
   unset($data['body']);
 
   // plaintext postprocessing
-  if ($part->ctype_secondary == 'plain') {
-    // make links and email-addresses clickable
-    $replacements = new rcube_string_replacer;
-    
-    // search for patterns like links and e-mail addresses
-    $body = preg_replace_callback($replacements->link_pattern, array($replacements, 'link_callback'), $body);
-    $body = preg_replace_callback($replacements->mailto_pattern, array($replacements, 'mailto_callback'), $body);
-
-    // split body into single lines
-    $a_lines = preg_split('/\r?\n/', $body);
-    $q_lines = array();
-    $quote_level = 0;
-
-    // find/mark quoted lines...
-    for ($n=0, $cnt=count($a_lines); $n < $cnt; $n++) {
-      $q = 0;
-    
-      if ($a_lines[$n][0] == '>' && preg_match('/^(>+\s*)+/', $a_lines[$n], $regs)) {
-        $q = strlen(preg_replace('/\s/', '', $regs[0]));
-	$a_lines[$n] = substr($a_lines[$n], strlen($regs[0]));
-
-        if ($q > $quote_level)
-          $q_lines[$n]['quote'] = $q - $quote_level;
-        else if ($q < $quote_level)
-          $q_lines[$n]['endquote'] = $quote_level - $q;
-      }
-      else if ($quote_level > 0)
-        $q_lines[$n]['endquote'] = $quote_level;
-
-      $quote_level = $q;
-    }
-
-    // quote plain text
-    $body = Q(join("\n", $a_lines), 'replace', false);
-
-    // ... colorize quoted lines
-    $a_lines = preg_split('/\n/', $body);
-    foreach ($q_lines as $i => $q)
-      if ($q['quote'])
-        $a_lines[$i] = str_repeat('<blockquote>', $q['quote']) . $a_lines[$i];
-      else if ($q['endquote'])
-        $a_lines[$i] = str_repeat('</blockquote>', $q['endquote']) . $a_lines[$i];
-
-    // insert the links for urls and mailtos
-    $body = $replacements->resolve(join("\n", $a_lines));
-  }
+  if ($part->ctype_secondary == 'plain')
+    $body = rcmail_plain_body($body);
 
   // allow post-processing of the message body
   $data = $RCMAIL->plugins->exec_hook('message_part_after', array('type' => $part->ctype_secondary, 'body' => $body) + $data);
 
   return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']);
+}
+
+
+/**
+ * Handle links and citation marks in plain text message
+ *
+ * @param string  Plain text string 
+ * @return string Formatted HTML string
+ */
+function rcmail_plain_body($body)
+{
+  // make links and email-addresses clickable
+  $replacements = new rcube_string_replacer;
+    
+  // search for patterns like links and e-mail addresses
+  $body = preg_replace_callback($replacements->link_pattern, array($replacements, 'link_callback'), $body);
+  $body = preg_replace_callback($replacements->mailto_pattern, array($replacements, 'mailto_callback'), $body);
+
+  // split body into single lines
+  $a_lines = preg_split('/\r?\n/', $body);
+  $q_lines = array();
+  $quote_level = 0;
+
+  // find/mark quoted lines...
+  for ($n=0, $cnt=count($a_lines); $n < $cnt; $n++) {
+    $q = 0;
+
+    if ($a_lines[$n][0] == '>' && preg_match('/^(>+\s*)+/', $a_lines[$n], $regs)) {
+      $q = strlen(preg_replace('/\s/', '', $regs[0]));
+        $a_lines[$n] = substr($a_lines[$n], strlen($regs[0]));
+
+      if ($q > $quote_level)
+        $q_lines[$n]['quote'] = $q - $quote_level;
+      else if ($q < $quote_level)
+        $q_lines[$n]['endquote'] = $quote_level - $q;
+    }
+    else if ($quote_level > 0)
+      $q_lines[$n]['endquote'] = $quote_level;
+
+    $quote_level = $q;
+  }
+
+  // quote plain text
+  $body = Q(join("\n", $a_lines), 'replace', false);
+
+  // colorize signature
+  if (($sp = strrpos($body, '-- ')) !== false)
+    if (($sp == 0 || $body[$sp-1] == "\n") && $body[$sp+3] == "\n") {
+      $body = substr($body, 0, max(0, $sp))
+	.'<span class="sig">'.substr($body, $sp).'</span>';
+    }
+
+  // colorize quoted lines
+  $a_lines = preg_split('/\n/', $body);
+  foreach ($q_lines as $i => $q)
+    if ($q['quote'])
+      $a_lines[$i] = str_repeat('<blockquote>', $q['quote']) . $a_lines[$i];
+    else if ($q['endquote'])
+      $a_lines[$i] = str_repeat('</blockquote>', $q['endquote']) . $a_lines[$i];
+
+  // insert the links for urls and mailtos
+  $body = $replacements->resolve(join("\n", $a_lines));
+    
+  return $body;
 }
 
 
@@ -878,6 +898,22 @@
 
 
 /**
+ * Callback function for HTML tags fixing
+ */
+function rcmail_html_tag_callback($matches)
+{
+  $tagname = $matches[2];
+
+  $tagname = preg_replace(array(
+    '/:.*$/',			// Microsoft's Smart Tags <st1:xxxx>
+    '/[^a-z0-9_\[\]\!-]/i',	// forbidden characters
+    ), '', $tagname);
+
+  return $matches[1].$tagname;
+}
+
+
+/**
  * return table with message headers
  */
 function rcmail_message_headers($attrib, $headers=NULL)
@@ -897,7 +933,7 @@
   // get associative array of headers object
   if (!$headers)
     $headers = is_object($MESSAGE->headers) ? get_object_vars($MESSAGE->headers) : $MESSAGE->headers;
-    
+
   // show these headers
   $standard_headers = array('subject', 'from', 'to', 'cc', 'bcc', 'replyto', 'date');
   $output_headers = array();
@@ -980,7 +1016,7 @@
       {
       if ($part->type == 'headers')
         $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers);
-      else if ($part->type == 'content')
+      else if ($part->type == 'content' && $part->size)
         {
         if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset']))
           $part->ctype_parameters['charset'] = $MESSAGE->headers->charset;
@@ -999,7 +1035,8 @@
       }
     }
   else
-    $out .= html::div('message-part', html::tag('pre', array(), Q($MESSAGE->body)));
+    $out .= html::div('message-part', html::tag('pre', array(),
+      rcmail_plain_body(Q($MESSAGE->body, 'strict', false))));
 
   $ctype_primary = strtolower($MESSAGE->structure->ctype_primary);
   $ctype_secondary = strtolower($MESSAGE->structure->ctype_secondary);
@@ -1111,12 +1148,12 @@
     $attrib['href'] = "./bin/modcss.php?u=" . urlencode($attrib['href']) . "&amp;c=" . urlencode($GLOBALS['rcmail_html_container_id']);
     $end = ' />';
   }
-  else if (preg_match("/^mailto:$EMAIL_ADDRESS_PATTERN/i", $attrib['href'], $mailto)) {
+  else if (preg_match('/^mailto:'.$EMAIL_ADDRESS_PATTERN.'(\?[^"\'>]+)?/i', $attrib['href'], $mailto)) {
     $attrib['href'] = $mailto[0];
     $attrib['onclick'] = sprintf(
       "return %s.command('compose','%s',this)",
       JS_OBJECT_NAME,
-      JQ($mailto[1]));
+      JQ($mailto[1].$mailto[2]));
   }
   else if (!empty($attrib['href']) && $attrib['href'][0] != '#') {
     $attrib['target'] = '_blank';
@@ -1295,7 +1332,7 @@
 /**
  * Send the given message compose object using the configured method
  */
-function rcmail_deliver_message(&$message, $from, $mailto)
+function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error)
 {
   global $CONFIG, $RCMAIL;
 
@@ -1319,8 +1356,12 @@
     unset($message->_headers['Bcc']);
 
     // send message
-    $smtp_response = array();
-    $sent = smtp_mail($from, $a_recipients, ($foo = $message->txtHeaders($send_headers, true)), $msg_body, $smtp_response);
+    if (!is_object($RCMAIL->smtp))
+      $RCMAIL->smtp_init(true);
+     
+    $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, ($foo = $message->txtHeaders($send_headers, true)), $msg_body);
+    $smtp_response = $RCMAIL->smtp->get_response();
+    $smtp_error = $RCMAIL->smtp->get_error();
 
     // log error
     if (!$sent)
@@ -1373,7 +1414,7 @@
 }
 
 
-function rcmail_send_mdn($uid)
+function rcmail_send_mdn($uid, &$smtp_error)
 {
   global $RCMAIL, $IMAP;
 
@@ -1403,7 +1444,7 @@
       'From' => $sender,
       'To'   => $message->headers->mdn_to,
       'Subject' => rcube_label('receiptread') . ': ' . $message->subject,
-      'Message-ID' => sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), $RCMAIL->config->mail_domain($_SESSION['imap_host'])),
+      'Message-ID' => sprintf('<%s@%s>', md5(uniqid('rcmail'.mt_rand(),true)), $RCMAIL->config->mail_domain($_SESSION['imap_host'])),
       'X-Sender' => $identity['email'],
       'Content-Type' => 'multipart/report; report-type=disposition-notification',
     );
@@ -1431,7 +1472,7 @@
     $compose->setTXTBody(rc_wordwrap($body, 75, "\r\n"));
     $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline');
 
-    $sent = rcmail_deliver_message($compose, $identity['email'], $mailto);
+    $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error);
 
     if ($sent)
     {

--
Gitblit v1.9.1