- Support UTF-7 encoding in messages (#1485832)

release-0.6
alecpl 15 years ago
parent 2de7d74c2b
commit a5897a3e38

@ -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

@ -205,7 +205,6 @@ function rcube_charset_convert($str, $from, $to=NULL)
// 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 @@ function rcube_charset_convert($str, $from, $to=NULL)
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,35 +227,49 @@ function rcube_charset_convert($str, $from, $to=NULL)
$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);
}
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;
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;
}
}
// report error
@ -304,6 +314,7 @@ function rcube_parse_charset($charset)
'ISO88598I' => 'ISO-8859-8',
'KSC56011987' => 'EUC-KR',
'UNICODE' => 'UTF-8',
'UTF7IMAP' => 'UTF7-IMAP'
);
$str = preg_replace('/[^a-z0-9]/i', '', $charset);
@ -321,6 +332,93 @@ function rcube_parse_charset($charset)
}
/**
* 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
*
@ -408,7 +506,7 @@ function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
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 @@ function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
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 @@ function rcmail_localize_foldername($name)
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');
}

@ -78,11 +78,11 @@ class rcube_config
// 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) {

@ -2762,7 +2762,7 @@ class rcube_imap
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

@ -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 @@ $RCMAIL->imap_init(true);
// 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 @@ else if ($RCMAIL->action=='create-folder')
{
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 @@ else if ($RCMAIL->action=='create-folder')
$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('&nbsp;&nbsp;&nbsp;&nbsp;', substr_count($create, $delimiter)) . $foldersplit[count($foldersplit)-1];
@ -73,8 +73,8 @@ else if ($RCMAIL->action=='rename-folder')
{
$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 @@ else if ($RCMAIL->action=='rename-folder')
$foldersplit = explode($delimiter, $folderlist[$x]);
$level = count($foldersplit) - 1;
$display_rename = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $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('&nbsp;&nbsp;&nbsp;&nbsp;', $level) . rcube_charset_convert($foldersplit[$level], 'UTF-7');
$display_rename = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $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;
$OUTPUT->command('replace_folder_row', $oldname_utf8, rcube_charset_convert($rename, 'UTF-7'), $display_rename, $before);
$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, 'UTF7-IMAP'), $display_rename, $before);
$OUTPUT->command('reset_folder_rename');
}
else if (!$rename && $OUTPUT->ajax_call)
@ -130,7 +129,7 @@ else if ($RCMAIL->action=='delete-folder')
$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 @@ else if ($RCMAIL->action=='delete-folder')
{
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 @@ function rcube_subscription_form($attrib)
// 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 @@ function rcube_subscription_form($attrib)
for ($i=1; $i<=$level; $i++) {
$ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i));
if ($ancestor_folder && !$seen[$ancestor_folder]++) {
$ancestor_name = rcube_charset_convert($foldersplit[$i-1], 'UTF-7');
$ancestor_name = rcube_charset_convert($foldersplit[$i-1], 'UTF7-IMAP');
$list_folders[] = array('id' => $ancestor_folder, 'name' => $ancestor_name, 'level' => $i-1, 'virtual' => true);
}
}
@ -231,7 +230,7 @@ function rcube_subscription_form($attrib)
$classes = array($i%2 ? 'even' : 'odd');
$folder_js = JQ($folder['id']);
$display_folder = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $folder['level']) . ($protected ? rcmail_localize_foldername($folder['id']) : $folder['name']);
$folder_utf8 = rcube_charset_convert($folder['id'], 'UTF-7');
$folder_utf8 = rcube_charset_convert($folder['id'], 'UTF7-IMAP');
if ($folder['virtual'])
$classes[] = 'virtual';

Loading…
Cancel
Save