[Svn] r2505 - in trunk/roundcubemail: . program/include program/steps/settings

trac at roundcube.net trac at roundcube.net
Wed May 20 11:55:15 CEST 2009


Author: alec
Date: 2009-05-20 04:55:15 -0500 (Wed, 20 May 2009)
New Revision: 2505

Modified:
   trunk/roundcubemail/CHANGELOG
   trunk/roundcubemail/program/include/main.inc
   trunk/roundcubemail/program/include/rcube_config.php
   trunk/roundcubemail/program/include/rcube_imap.php
   trunk/roundcubemail/program/steps/settings/manage_folders.inc
Log:
- Support UTF-7 encoding in messages (#1485832)


Modified: trunk/roundcubemail/CHANGELOG
===================================================================
--- trunk/roundcubemail/CHANGELOG	2009-05-20 09:03:14 UTC (rev 2504)
+++ trunk/roundcubemail/CHANGELOG	2009-05-20 09:55:15 UTC (rev 2505)
@@ -1,6 +1,7 @@
 CHANGELOG RoundCube Webmail
 ===========================
 
+- Support UTF-7 encoding in messages (#1485832)
 - Better support for malformed character names (#1485758)
 - Added possibility to encrypt received header, option 'http_received_header_encrypt',
   added some more logic in encrypt/decrypt functions for security

Modified: trunk/roundcubemail/program/include/main.inc
===================================================================
--- trunk/roundcubemail/program/include/main.inc	2009-05-20 09:03:14 UTC (rev 2504)
+++ trunk/roundcubemail/program/include/main.inc	2009-05-20 09:55:15 UTC (rev 2505)
@@ -205,7 +205,6 @@
     
   // convert charset using mbstring module
   if ($mbstring_loaded) {
-    $aliases['UTF-7'] = 'UTF7-IMAP';
     $aliases['WINDOWS-1257'] = 'ISO-8859-13';
     
     if (is_null($mbstring_list)) {
@@ -220,9 +219,6 @@
     if (in_array($mb_from, $mbstring_list) && in_array($mb_to, $mbstring_list)) {
       if (mb_check_encoding($str, $mb_from) && ($out = mb_convert_encoding($str, $mb_to, $mb_from)))
         return $out;
-      else
-        // return here, encoding supported, but string is invalid
-        return $str;
     }
   }
 
@@ -231,36 +227,50 @@
     $conv = new utf8();
 
   // convert string to UTF-8
-  if ($from == 'UTF-7') {
-    if ($_str = utf7_to_utf8($str))
-      $str = $_str;
-    else
+  if ($to == 'UTF-8') {
+    if ($from == 'UTF7-IMAP') {
+      if ($_str = utf7_to_utf8($str))
+        $str = $_str;
+      else
+        $error = true;
+    }
+    else if ($from == 'UTF-7') {
+      if ($_str = rcube_utf7_to_utf8($str))
+        $str = $_str;
+      else
+        $error = true;
+    }
+    else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) {
+      $str = utf8_encode($str);
+    }
+    else if ($from != 'UTF-8' && $conv) {
+      $conv->loadCharset($from);
+      $str = $conv->strToUtf8($str);
+    }
+    else if ($from != 'UTF-8')
       $error = true;
   }
-  else if (($from == 'ISO-8859-1') && function_exists('utf8_encode')) {
-    $str = utf8_encode($str);
-  }
-  else if ($from != 'UTF-8' && $conv) {
-    $conv->loadCharset($from);
-    $str = $conv->strToUtf8($str);
-  }
-  else if ($from != 'UTF-8')
-    $error = true;
-
+  
   // encode string for output
-  if ($to == 'UTF-7') {
-    return utf8_to_utf7($str);
+  if ($from == 'UTF-8') {
+    // @TODO: we need a function for UTF-7 (RFC2152) conversion
+    if ($to == 'UTF7-IMAP' || $to == 'UTF-7') {
+      if ($_str = utf8_to_utf7($str))
+        $str = $_str;
+      else
+        $error = true;
+    }
+    else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) {
+      return utf8_decode($str);
+    }
+    else if ($to != 'UTF-8' && $conv) {
+      $conv->loadCharset($to);
+      return $conv->utf8ToStr($str);
+    }
+    else if ($to != 'UTF-8') {
+      $error = true;
+    }
   }
-  else if ($to == 'ISO-8859-1' && function_exists('utf8_decode')) {
-    return utf8_decode($str);
-  }
-  else if ($to != 'UTF-8' && $conv) {
-    $conv->loadCharset($to);
-    return $conv->utf8ToStr($str);
-  }
-  else if ($to != 'UTF-8') {
-    $error = true;
-  }
   
   // report error
   if ($error && !$convert_warning){
@@ -304,6 +314,7 @@
     'ISO88598I'     => 'ISO-8859-8',
     'KSC56011987'   => 'EUC-KR',
     'UNICODE'	    => 'UTF-8',
+    'UTF7IMAP'	    => 'UTF7-IMAP'
   );
 
   $str = preg_replace('/[^a-z0-9]/i', '', $charset);
@@ -322,6 +333,93 @@
 
 
 /**
+ * Converts string from standard UTF-7 (RFC 2152) to UTF-8.
+ *
+ * @param  string  Input string
+ * @return The converted string
+ */
+function rcube_utf7_to_utf8($str)
+{
+  $Index_64 = array(
+    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
+    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
+    0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,
+    1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
+    0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
+    1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
+    0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
+    1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
+  );
+
+  $u7len = strlen($str);
+  $str = strval($str);
+  $res = '';
+
+  for ($i=0; $u7len > 0; $i++, $u7len--)
+  {
+    $u7 = $str[$i];
+    if ($u7 == '+')
+    {
+      $i++;
+      $u7len--;
+      $ch = '';
+
+      for (; $u7len > 0; $i++, $u7len--)
+      {
+        $u7 = $str[$i];
+
+        if (!$Index_64[ord($u7)])
+          break;
+
+	$ch .= $u7;
+      }
+
+      if ($ch == '') {
+        if ($u7 == '-')
+          $res .= '+';
+        continue;
+      }
+
+      $res .= rcube_utf16_to_utf8(base64_decode($ch));
+    }
+    else
+    {
+      $res .= $u7;
+    }
+  }
+
+  return $res;
+}
+
+/**
+ * Converts string from UTF-16 to UTF-8 (helper for utf-7 to utf-8 conversion)
+ *
+ * @param  string  Input string
+ * @return The converted string
+ */
+function rcube_utf16_to_utf8($str)
+{
+  $len = strlen($str);
+  $dec = '';
+
+  for ($i = 0; $i < $len; $i += 2) {
+    $c = ord($str[$i]) << 8 | ord($str[$i + 1]);
+    if ($c >= 0x0001 && $c <= 0x007F) {
+      $dec .= chr($c);
+    } else if ($c > 0x07FF) {
+      $dec .= chr(0xE0 | (($c >> 12) & 0x0F));
+      $dec .= chr(0x80 | (($c >>  6) & 0x3F));
+      $dec .= chr(0x80 | (($c >>  0) & 0x3F));
+    } else {
+      $dec .= chr(0xC0 | (($c >>  6) & 0x1F));
+      $dec .= chr(0x80 | (($c >>  0) & 0x3F));
+    }
+  }
+  return $dec;
+}
+
+
+/**
  * Replacing specials characters to a specific encoding type
  *
  * @param  string  Input string
@@ -408,7 +506,7 @@
   if ($enctype=='js')
     {
     if ($charset!='UTF-8')
-      $str = rcube_charset_convert($str, RCMAIL_CHARSET,$charset);
+      $str = rcube_charset_convert($str, RCMAIL_CHARSET, $charset);
       
     return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
     }
@@ -1057,7 +1155,7 @@
   if (!isset($arrFolders[$currentFolder])) {
     $arrFolders[$currentFolder] = array(
       'id' => $path,
-      'name' => rcube_charset_convert($currentFolder, 'UTF-7'),
+      'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
       'virtual' => $virtual,
       'folders' => array());
   }
@@ -1232,7 +1330,7 @@
   if ($folder_class = rcmail_folder_classname($name))
     return rcube_label($folder_class);
   else
-    return rcube_charset_convert($name, 'UTF-7');
+    return rcube_charset_convert($name, 'UTF7-IMAP');
 }
 
 

Modified: trunk/roundcubemail/program/include/rcube_config.php
===================================================================
--- trunk/roundcubemail/program/include/rcube_config.php	2009-05-20 09:03:14 UTC (rev 2504)
+++ trunk/roundcubemail/program/include/rcube_config.php	2009-05-20 09:55:15 UTC (rev 2505)
@@ -78,11 +78,11 @@
 
     // fix default imap folders encoding
     foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
-      $this->prop[$folder] = rcube_charset_convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF-7');
+      $this->prop[$folder] = rcube_charset_convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');
 
     if (!empty($this->prop['default_imap_folders']))
       foreach ($this->prop['default_imap_folders'] as $n => $folder)
-        $this->prop['default_imap_folders'][$n] = rcube_charset_convert($folder, RCMAIL_CHARSET, 'UTF-7');
+        $this->prop['default_imap_folders'][$n] = rcube_charset_convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
 
     // set PHP error logging according to config
     if ($this->prop['debug_level'] & 1) {

Modified: trunk/roundcubemail/program/include/rcube_imap.php
===================================================================
--- trunk/roundcubemail/program/include/rcube_imap.php	2009-05-20 09:03:14 UTC (rev 2504)
+++ trunk/roundcubemail/program/include/rcube_imap.php	2009-05-20 09:55:15 UTC (rev 2505)
@@ -2762,7 +2762,7 @@
       if (($p = array_search(strtolower($folder), $this->default_folders_lc)) !== false && !$a_defaults[$p])
         $a_defaults[$p] = $folder;
       else
-        $folders[$folder] = rc_strtolower(rcube_charset_convert($folder, 'UTF-7'));
+        $folders[$folder] = rc_strtolower(rcube_charset_convert($folder, 'UTF7-IMAP'));
       }
 
     // sort folders and place defaults on the top

Modified: trunk/roundcubemail/program/steps/settings/manage_folders.inc
===================================================================
--- trunk/roundcubemail/program/steps/settings/manage_folders.inc	2009-05-20 09:03:14 UTC (rev 2504)
+++ trunk/roundcubemail/program/steps/settings/manage_folders.inc	2009-05-20 09:55:15 UTC (rev 2505)
@@ -19,7 +19,7 @@
 
 */
 
-// WARNING: folder names in UI are encoded with UTF-8
+// WARNING: folder names in UI are encoded with RCMAIL_CHARSET
 
 // init IMAP connection
 $RCMAIL->imap_init(true);
@@ -27,14 +27,14 @@
 // subscribe to one or more mailboxes
 if ($RCMAIL->action=='subscribe')
   {
-  if ($mbox = get_input_value('_mbox', RCUBE_INPUT_POST, false, 'UTF-7'))
+  if ($mbox = get_input_value('_mbox', RCUBE_INPUT_POST, false, 'UTF7-IMAP'))
     $IMAP->subscribe(array($mbox));
   }
 
 // unsubscribe one or more mailboxes
 else if ($RCMAIL->action=='unsubscribe')
   {
-  if ($mbox = get_input_value('_mbox', RCUBE_INPUT_POST, false, 'UTF-7'))
+  if ($mbox = get_input_value('_mbox', RCUBE_INPUT_POST, false, 'UTF7-IMAP'))
     $IMAP->unsubscribe(array($mbox));
   }
 
@@ -43,7 +43,7 @@
   {
   if (!empty($_POST['_name']))
     {
-    $name = trim(get_input_value('_name', RCUBE_INPUT_POST, FALSE, 'UTF-7'));
+    $name = trim(get_input_value('_name', RCUBE_INPUT_POST, FALSE, 'UTF7-IMAP'));
     $create = $IMAP->create_mailbox($name, TRUE);
     }
   
@@ -52,9 +52,9 @@
     $delimiter = $IMAP->get_hierarchy_delimiter();
     $folderlist = $IMAP->list_unsubscribed();
     $index = array_search($create, $folderlist);
-    $before = $index !== false && isset($folderlist[$index+1]) ? rcube_charset_convert($folderlist[$index+1], 'UTF-7') : false;
+    $before = $index !== false && isset($folderlist[$index+1]) ? rcube_charset_convert($folderlist[$index+1], 'UTF7-IMAP') : false;
     
-    $create = rcube_charset_convert($create, 'UTF-7');
+    $create = rcube_charset_convert($create, 'UTF7-IMAP');
     $foldersplit = explode($delimiter, $create);
     $display_create = str_repeat('    ', substr_count($create, $delimiter)) . $foldersplit[count($foldersplit)-1];
 
@@ -73,8 +73,8 @@
     {
     $name_utf8 = trim(get_input_value('_folder_newname', RCUBE_INPUT_POST));
     $oldname_utf8 = get_input_value('_folder_oldname', RCUBE_INPUT_POST);
-    $name = rcube_charset_convert($name_utf8, 'UTF-8', 'UTF-7');
-    $oldname = rcube_charset_convert($oldname_utf8, 'UTF-8', 'UTF-7');
+    $name = rcube_charset_convert($name_utf8, RCMAIL_CHARSET, 'UTF7-IMAP');
+    $oldname = rcube_charset_convert($oldname_utf8, RCMAIL_CHARSET, 'UTF7-IMAP');
 
     $rename = $IMAP->rename_mailbox($oldname, $name);
     }
@@ -95,23 +95,22 @@
         $foldersplit = explode($delimiter, $folderlist[$x]);
         $level = count($foldersplit) - 1;
         $display_rename = str_repeat('    ', $level) 
-          . rcube_charset_convert($foldersplit[$level], 'UTF-7');
+          . rcube_charset_convert($foldersplit[$level], 'UTF7-IMAP');
 
-        $before = isset($folderlist[$x+1]) ? rcube_charset_convert($folderlist[$x+1], 'UTF-7') : false;
+        $before = isset($folderlist[$x+1]) ? rcube_charset_convert($folderlist[$x+1], 'UTF7-IMAP') : false;
         
-        $OUTPUT->command('replace_folder_row', rcube_charset_convert($oldfolder, 'UTF-7'),
-          rcube_charset_convert($folderlist[$x], 'UTF-7'), $display_rename, $before);
+        $OUTPUT->command('replace_folder_row', rcube_charset_convert($oldfolder, 'UTF7-IMAP'),
+          rcube_charset_convert($folderlist[$x], 'UTF7-IMAP'), $display_rename, $before);
         }
       }
 
     $foldersplit = explode($delimiter, $rename);
     $level = count($foldersplit) - 1;
-    $display_rename = str_repeat('    ', $level) . rcube_charset_convert($foldersplit[$level], 'UTF-7');
+    $display_rename = str_repeat('    ', $level) . rcube_charset_convert($foldersplit[$level], 'UTF7-IMAP');
     $index = array_search($rename, $folderlist);
-    $before = $index !== false && isset($folderlist[$index+1]) ? rcube_charset_convert($folderlist[$index+1], 'UTF-7') : false;
+    $before = $index !== false && isset($folderlist[$index+1]) ? rcube_charset_convert($folderlist[$index+1], 'UTF7-IMAP') : false;
 
-    $OUTPUT->command('replace_folder_row', $oldname_utf8, rcube_charset_convert($rename, 'UTF-7'), $display_rename, $before);
-
+    $OUTPUT->command('replace_folder_row', $oldname_utf8, rcube_charset_convert($rename, 'UTF7-IMAP'), $display_rename, $before);
     $OUTPUT->command('reset_folder_rename');
     }
   else if (!$rename && $OUTPUT->ajax_call)
@@ -130,7 +129,7 @@
   $delimiter = $IMAP->get_hierarchy_delimiter();
   
   $mboxes_utf8 = get_input_value('_mboxes', RCUBE_INPUT_POST);
-  $mboxes = rcube_charset_convert($mboxes_utf8, 'UTF-8', 'UTF-7');
+  $mboxes = rcube_charset_convert($mboxes_utf8, RCMAIL_CHARSET, 'UTF7-IMAP');
 
   if ($mboxes)
     $deleted = $IMAP->delete_mailbox(array($mboxes));
@@ -142,7 +141,7 @@
       {
       if (preg_match('/^'. preg_quote($mboxes.$delimiter, '/') .'/', $mbox))
         {
-        $OUTPUT->command('remove_folder_row', rcube_charset_convert($mbox, 'UTF-7'));
+        $OUTPUT->command('remove_folder_row', rcube_charset_convert($mbox, 'UTF7-IMAP'));
         }
       }
     $OUTPUT->show_message('folderdeleted', 'confirmation');
@@ -189,7 +188,7 @@
   // pre-process folders list
   foreach ($a_unsubscribed as $i => $folder) {
     $foldersplit = explode($delimiter, $folder);
-    $name = rcube_charset_convert(array_pop($foldersplit), 'UTF-7');
+    $name = rcube_charset_convert(array_pop($foldersplit), 'UTF7-IMAP');
     $parent_folder = join($delimiter, $foldersplit);
     $level = count($foldersplit);
 
@@ -198,7 +197,7 @@
       for ($i=1; $i<=$level; $i++) {
 	$ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i));