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 |  301 ++++++++++++++++++++++++++-----------------------
 1 files changed, 160 insertions(+), 141 deletions(-)

diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index f6e4a9d..e9adc15 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -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
@@ -305,7 +306,7 @@
     // 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')
         {
@@ -392,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);
 
@@ -415,16 +424,10 @@
 
     $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')
         {
@@ -454,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,
@@ -463,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);
   }
 
 
@@ -487,9 +490,6 @@
   }
 
 
-/**
- *
- */
 function rcmail_messagecount_display($attrib)
   {
   global $IMAP, $OUTPUT;
@@ -503,9 +503,6 @@
   }
 
 
-/**
- *
- */
 function rcmail_quota_display($attrib)
   {
   global $OUTPUT, $COMM_PATH;
@@ -517,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;
@@ -608,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
@@ -657,6 +661,7 @@
   }
 }
 
+
 /**
  * Cleans up the given message HTML Body (for displaying)
  *
@@ -674,7 +679,7 @@
   // special replacements (not properly handled by washtml class)
   $html_search = array(
     '/(<\/nobr>)(\s+)(<nobr>)/i',	// space(s) between <NOBR>
-    '/<title>.*<\/title>/i',		// PHP bug #32547 workaround: remove title tag
+    '/<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
   );
@@ -687,7 +692,7 @@
   $html = preg_replace($html_search, $html_replace, $html);
 
   // fix (unknown/malformed) HTML tags before "wash"
-  $html = preg_replace_callback('/(<[\/!]*)([^ >]+)/', 'rcmail_html_tag_callback', $html);
+  $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
@@ -728,10 +733,10 @@
 
   // 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;
 }
 
@@ -779,64 +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 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));
-  }
+  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;
 }
 
 
@@ -887,8 +905,8 @@
   $tagname = $matches[2];
 
   $tagname = preg_replace(array(
-    '/:.*$/',		// Microsoft's Smart Tags <st1:xxxx>
-    '/[^a-z0-9_-]/i',	// forbidden characters
+    '/:.*$/',			// Microsoft's Smart Tags <st1:xxxx>
+    '/[^a-z0-9_\[\]\!-]/i',	// forbidden characters
     ), '', $tagname);
 
   return $matches[1].$tagname;
@@ -1017,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);
@@ -1129,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';
@@ -1425,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',
     );

--
Gitblit v1.9.1