Merge branch 'master' of https://github.com/roundcube/roundcubemail
3 files added
38 files modified
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Fix invalid error message on deleting mail from read only folder (#1488694) |
| | | - Fix error where session wasn't updated after folder rename/delete (#1488692) |
| | | - Replace data URIs of images (pasted in HTML editor) with inline attachments (#1488502) |
| | | - Fix PLAIN authentication for some IMAP servers (#1488674) |
| | | - Fix encoding vCard file when contains PHOTO;ENCODING=b (#1488683) |
| | | - Fix focus issue in IE when selecting message row (#1488620) |
| | | - Remove (too big) min-width on mail screen |
| | | - Add full headers view in message preview window (#1488538) |
| | | - Fix message display page issues - unified with message preview (#1488590, #1488642) |
| | | - Fix displaying all headers when they contain malformed characters (#1488666) |
| | | - Fix decoding of HTML messages with UTF-16 charset specified (#1488654) |
| | | - Fix quota capability detection so it can be overwritten by a plugin (#1488655) |
| | | - Added template object 'frame' |
| | |
| | | // TCP port used for IMAP connections |
| | | $rcmail_config['default_port'] = 143; |
| | | |
| | | // IMAP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or empty to use |
| | | // IMAP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null to use |
| | | // best server supported one) |
| | | $rcmail_config['imap_auth_type'] = null; |
| | | |
| | |
| | | $result = array(); |
| | | |
| | | while ($file = readdir($dir)) { |
| | | if (preg_match('/^[a-z_]+$/', $file)) { |
| | | if (preg_match('/^[a-z0-9_]+$/', $file)) { |
| | | $input = file_get_contents($dir_path . '/' . $file); |
| | | |
| | | if (file_exists($dir_path . '/' . $file . '.out')) { |
New file |
| | |
| | | require ["variables"]; |
| | | set "EDITOR" "Roundcube"; |
| | | set "EDITOR_VERSION" "123"; |
| | |
| | | // The query can contain the following macros that will be expanded as follows: |
| | | // %p is replaced with the plaintext new password |
| | | // %c is replaced with the crypt version of the new password, MD5 if available |
| | | // otherwise DES. |
| | | // otherwise DES. More hash function can be enabled using the password_crypt_hash |
| | | // configuration parameter. |
| | | // %D is replaced with the dovecotpw-crypted version of the new password |
| | | // %o is replaced with the password before the change |
| | | // %n is replaced with the hashed version of the new password |
| | |
| | | // Default: "SELECT update_passwd(%c, %u)" |
| | | $rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)'; |
| | | |
| | | // By default the crypt() function which is used to create the '%c' |
| | | // parameter uses the md5 algorithm. To use different algorithms |
| | | // you can choose between: des, md5, blowfish, sha256, sha512. |
| | | // Before using other hash functions than des or md5 please make sure |
| | | // your operating system supports the other hash functions. |
| | | $rcmail_config['password_crypt_hash'] = 'md5'; |
| | | |
| | | // By default domains in variables are using unicode. |
| | | // Enable this option to use punycoded names |
| | | $rcmail_config['password_idn_ascii'] = false; |
| | |
| | | // crypted password |
| | | if (strpos($sql, '%c') !== FALSE) { |
| | | $salt = ''; |
| | | if (CRYPT_MD5) { |
| | | // Always use eight salt characters for MD5 (#1488136) |
| | | $len = 8; |
| | | } else if (CRYPT_STD_DES) { |
| | | $len = 2; |
| | | } else { |
| | | return PASSWORD_CRYPT_ERROR; |
| | | |
| | | if (!($crypt_hash = $rcmail->config->get('password_crypt_hash'))) |
| | | { |
| | | if (CRYPT_MD5) |
| | | $crypt_hash = 'md5'; |
| | | else if (CRYPT_STD_DES) |
| | | $crypt_hash = 'des'; |
| | | } |
| | | |
| | | switch ($crypt_hash) |
| | | { |
| | | case 'md5': |
| | | $len = 8; |
| | | $salt_hashindicator = '$1$'; |
| | | break; |
| | | case 'des': |
| | | $len = 2; |
| | | break; |
| | | case 'blowfish': |
| | | $len = 22; |
| | | $salt_hashindicator = '$2a$'; |
| | | break; |
| | | case 'sha256': |
| | | $len = 16; |
| | | $salt_hashindicator = '$5$'; |
| | | break; |
| | | case 'sha512': |
| | | $len = 16; |
| | | $salt_hashindicator = '$6$'; |
| | | break; |
| | | default: |
| | | return PASSWORD_CRYPT_ERROR; |
| | | } |
| | | |
| | | //Restrict the character set used as salt (#1488136) |
| | |
| | | $salt .= $seedchars[rand(0, 63)]; |
| | | } |
| | | |
| | | $sql = str_replace('%c', $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $sql); |
| | | $sql = str_replace('%c', $db->quote(crypt($passwd, $salt_hashindicator ? $salt_hashindicator .$salt.'$' : $salt)), $sql); |
| | | } |
| | | |
| | | // dovecotpw |
| | |
| | | $pieces = explode("_", $username); |
| | | $domain = $pieces[0]; |
| | | break; |
| | | case 8: // domain taken from alias, username left as it was |
| | | $email = $rcmail->user->data['alias']; |
| | | $domain = substr(strrchr($email, "@"), 1); |
| | | break; |
| | | default: // username@domain |
| | | $domain = substr(strrchr($username, "@"), 1); |
| | | } |
| | |
| | | $err_code = $this->storage->get_error_code(); |
| | | $res_code = $this->storage->get_response_code(); |
| | | |
| | | if ($err_code < 0) { |
| | | $this->output->show_message('storageerror', 'error'); |
| | | } |
| | | else if ($res_code == rcube_storage::NOPERM) { |
| | | if ($res_code == rcube_storage::NOPERM) { |
| | | $this->output->show_message('errornoperm', 'error'); |
| | | } |
| | | else if ($res_code == rcube_storage::READONLY) { |
| | |
| | | $this->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); |
| | | } |
| | | } |
| | | else if ($err_code < 0) { |
| | | $this->output->show_message('storageerror', 'error'); |
| | | } |
| | | else if ($fallback) { |
| | | $this->output->show_message($fallback, 'error', $fallback_args); |
| | | } |
| | |
| | | * Sometimes charset string is malformed, there are also charset aliases |
| | | * but we need strict names for charset conversion (specially utf8 class) |
| | | * |
| | | * @param string Input charset name |
| | | * @param string $input Input charset name |
| | | * |
| | | * @return string The validated charset name |
| | | */ |
| | |
| | | { |
| | | static $iconv_options = null; |
| | | static $mbstring_list = null; |
| | | static $mbstring_sch = null; |
| | | static $conv = null; |
| | | |
| | | $to = empty($to) ? strtoupper(RCMAIL_CHARSET) : self::parse_charset($to); |
| | | $to = empty($to) ? strtoupper(RCMAIL_CHARSET) : $to; |
| | | $from = self::parse_charset($from); |
| | | |
| | | // It is a common case when UTF-16 charset is used with US-ASCII content (#1488654) |
| | |
| | | |
| | | if ($mbstring_list === null) { |
| | | if (extension_loaded('mbstring')) { |
| | | $mbstring_sch = mb_substitute_character(); |
| | | $mbstring_list = mb_list_encodings(); |
| | | $mbstring_list = array_map('strtoupper', $mbstring_list); |
| | | } |
| | |
| | | // convert charset using mbstring module |
| | | if ($mbstring_list !== null) { |
| | | $aliases['WINDOWS-1257'] = 'ISO-8859-13'; |
| | | // it happens that mbstring supports ASCII but not US-ASCII |
| | | if (($from == 'US-ASCII' || $to == 'US-ASCII') && !in_array('US-ASCII', $mbstring_list)) { |
| | | $aliases['US-ASCII'] = 'ASCII'; |
| | | } |
| | | |
| | | $mb_from = $aliases[$from] ? $aliases[$from] : $from; |
| | | $mb_to = $aliases[$to] ? $aliases[$to] : $to; |
| | | |
| | | // return if encoding found, string matches encoding and convert succeeded |
| | | 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; |
| | | if (mb_check_encoding($str, $mb_from)) { |
| | | // Do the same as //IGNORE with iconv |
| | | mb_substitute_character('none'); |
| | | $out = mb_convert_encoding($str, $mb_to, $mb_from); |
| | | mb_substitute_character($mbstring_sch); |
| | | |
| | | if ($out !== false) { |
| | | return $out; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | return $failover; |
| | | } |
| | | |
| | | // FIXME: the order is important, because sometimes |
| | | // FIXME: the order is important, because sometimes |
| | | // iso string is detected as euc-jp and etc. |
| | | $enc = array( |
| | | 'UTF-8', 'SJIS', 'BIG5', 'GB2312', |
| | | 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', |
| | | 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', |
| | | 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', |
| | | 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', |
| | | 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', |
| | | 'ISO-2022-KR', 'ISO-2022-JP' |
| | | ); |
| | | |
| | |
| | | $criteria = 'UNDELETED '.$criteria; |
| | | } |
| | | |
| | | // unset CHARSET if criteria string is ASCII, this way |
| | | // SEARCH won't be re-sent after "unsupported charset" response |
| | | if ($charset && $charset != 'US-ASCII' && is_ascii($criteria)) { |
| | | $charset = 'US-ASCII'; |
| | | } |
| | | |
| | | if ($this->threading) { |
| | | $threads = $this->conn->thread($folder, $this->threading, $criteria, true, $charset); |
| | | |
| | |
| | | } |
| | | |
| | | $messages = $this->conn->search($folder, |
| | | ($charset ? "CHARSET $charset " : '') . $criteria, true); |
| | | ($charset && $charset != 'US-ASCII' ? "CHARSET $charset " : '') . $criteria, true); |
| | | |
| | | // Error, try with US-ASCII (some servers may support only US-ASCII) |
| | | if ($messages->is_error() && $charset && $charset != 'US-ASCII') { |
| | |
| | | } |
| | | else { |
| | | $authc = $user; |
| | | $user = ''; |
| | | } |
| | | $auth_sasl = Auth_SASL::factory('digestmd5'); |
| | | $reply = base64_encode($auth_sasl->getResponse($authc, $pass, |
| | |
| | | } |
| | | else { |
| | | $authc = $user; |
| | | $user = ''; |
| | | } |
| | | |
| | | $reply = base64_encode($user . chr(0) . $authc . chr(0) . $pass); |
| | |
| | | for ($i=0, $len=count($data); $i<$len; $i++) { |
| | | $data_item = &$data[$i]; |
| | | if (preg_match('/^ SORT/i', $data_item)) { |
| | | // valid response, initialize raw_data for is_error() |
| | | $this->raw_data = ''; |
| | | $data_item = substr($data_item, 5); |
| | | break; |
| | | } |
| | | else if (preg_match('/^ (E?SEARCH)/i', $data_item, $m)) { |
| | | // valid response, initialize raw_data for is_error() |
| | | $this->raw_data = ''; |
| | | $data_item = substr($data_item, strlen($m[0])); |
| | | |
| | | if (strtoupper($m[1]) == 'ESEARCH') { |
| | |
| | | // ...skip unilateral untagged server responses |
| | | for ($i=0, $len=count($data); $i<$len; $i++) { |
| | | if (preg_match('/^ THREAD/i', $data[$i])) { |
| | | // valid response, initialize raw_data for is_error() |
| | | $this->raw_data = ''; |
| | | $data[$i] = substr($data[$i], 7); |
| | | break; |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Check if a string contains only ascii characters |
| | | * |
| | | * @param string $str String to check |
| | | * @param bool $control_chars Includes control characters |
| | | * |
| | | * @return bool |
| | | */ |
| | | function is_ascii($str, $control_chars = true) |
| | | { |
| | | $regexp = $control_chars ? '/[^\x00-\x7F]/' : '/[^\x20-\x7E]/'; |
| | | return preg_match($regexp, $str) ? false : true; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Remove single and double quotes from a given string |
| | | * |
| | | * @param string Input value |
| | |
| | | if ((list($key, $value) = explode('=', $attr)) && $value) { |
| | | $value = trim($value); |
| | | if ($key == 'ENCODING') { |
| | | $value = strtoupper($value); |
| | | // add next line(s) to value string if QP line end detected |
| | | if ($value == 'QUOTED-PRINTABLE') { |
| | | while (preg_match('/=$/', $lines[$i])) |
| | |
| | | } |
| | | } |
| | | |
| | | // Un-focus already focused elements |
| | | $(document.activeElement).blur(); |
| | | // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) |
| | | $(':focus:not(body)').blur(); |
| | | $('iframe').each(function() { this.blur(); }); |
| | | |
| | | if (e || (e = window.event)) |
| | |
| | | global $OUTPUT; |
| | | |
| | | $html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), '')); |
| | | $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)"), ''); |
| | | |
| | | if (!get_boolean($attrib['no-switch'])) { |
| | | $html .= html::div(array('class' => "more-headers show-headers", 'onclick' => "return ".JS_OBJECT_NAME.".command('show-headers','',this)"), ''); |
| | | } |
| | | |
| | | unset($attrib['no-switch']); |
| | | |
| | | $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); |
| | | $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); |
| | | |
| | | return html::div($attrib, $html); |
| | | return count($attrib) > 1 ? html::div($attrib, $html) : $html; |
| | | } |
| | | |
| | | |
| | |
| | | $source = $RCMAIL->storage->get_raw_headers($uid); |
| | | |
| | | if ($source !== false) { |
| | | $source = htmlspecialchars(trim($source)); |
| | | $source = trim(rcube_charset::clean($source)); |
| | | $source = htmlspecialchars($source); |
| | | $source = preg_replace( |
| | | array( |
| | | '/\n[\t\s]+/', |
| | |
| | | if (!empty($subject)) { |
| | | $search_str .= str_repeat(' OR', count($subject)-1); |
| | | foreach ($subject as $sub) |
| | | $search_str .= sprintf(" %s {%d}\r\n%s", $sub, strlen($search), $search); |
| | | $search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search); |
| | | } |
| | | |
| | | $search_str = trim($search_str); |
| | |
| | | * to this: |
| | | * |
| | | * <img src="/path/on/server/.../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> |
| | | * ... |
| | | */ |
| | | function rcmail_fix_emoticon_paths(&$mime_message) |
| | | function rcmail_fix_emoticon_paths($mime_message) |
| | | { |
| | | global $CONFIG; |
| | | |
| | |
| | | } |
| | | |
| | | $mime_message->setHTMLBody($body); |
| | | } |
| | | |
| | | return $body; |
| | | /** |
| | | * Extract image attachments from HTML content (data URIs) |
| | | */ |
| | | function rcmail_extract_inline_images($mime_message, $from) |
| | | { |
| | | $body = $mime_message->getHTMLBody(); |
| | | $offset = 0; |
| | | $list = array(); |
| | | $regexp = '# src=[\'"](data:(image/[a-z]+);base64,([a-z0-9+/=\r\n]+))([\'"])#i'; |
| | | |
| | | // get domain for the Content-ID, must be the same as in Mail_Mime::get() |
| | | if (preg_match('#@([0-9a-zA-Z\-\.]+)#', $from, $matches)) { |
| | | $domain = $matches[1]; |
| | | } else { |
| | | $domain = 'localhost'; |
| | | } |
| | | |
| | | if (preg_match_all($regexp, $body, $matches, PREG_OFFSET_CAPTURE)) { |
| | | foreach ($matches[1] as $idx => $m) { |
| | | $data = preg_replace('/\r\n/', '', $matches[3][$idx][0]); |
| | | $data = base64_decode($data); |
| | | |
| | | if (empty($data)) { |
| | | continue; |
| | | } |
| | | |
| | | $hash = md5($data) . '@' . $domain; |
| | | $mime_type = $matches[2][$idx][0]; |
| | | $name = $list[$hash]; |
| | | |
| | | // add the image to the MIME message |
| | | if (!$name) { |
| | | $ext = preg_replace('#^[^/]+/#', '', $mime_type); |
| | | $name = substr($hash, 0, 8) . '.' . $ext; |
| | | $list[$hash] = $name; |
| | | |
| | | $mime_message->addHTMLImage($data, $mime_type, $name, false, $hash); |
| | | } |
| | | |
| | | $body = substr_replace($body, $name, $m[1] + $offset, strlen($m[0])); |
| | | $offset += strlen($name) - strlen($m[0]); |
| | | } |
| | | } |
| | | |
| | | $mime_message->setHTMLBody($body); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | // look for "emoticon" images from TinyMCE and change their src paths to |
| | | // be file paths on the server instead of URL paths. |
| | | $message_body = rcmail_fix_emoticon_paths($MAIL_MIME); |
| | | rcmail_fix_emoticon_paths($MAIL_MIME); |
| | | |
| | | // Extract image Data URIs into message attachments (#1488502) |
| | | rcmail_extract_inline_images($MAIL_MIME, $from); |
| | | } |
| | | else { |
| | | $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', |
| | |
| | | else { |
| | | $deleted = $plugin['result']; |
| | | } |
| | | |
| | | // #1488692: update session |
| | | if ($deleted && $_SESSION['mbox'] === $mbox) { |
| | | $RCMAIL->session->remove('mbox'); |
| | | } |
| | | } |
| | | |
| | | if ($OUTPUT->ajax_call && $deleted) { |
| | |
| | | foreach ($a_threaded as $key => $val) { |
| | | if ($key == $oldname) { |
| | | unset($a_threaded[$key]); |
| | | $a_threaded[$newname] = true; |
| | | $a_threaded[$newname] = true; |
| | | } |
| | | else if (preg_match($oldprefix, $key)) { |
| | | unset($a_threaded[$key]); |
| | | $a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = true; |
| | | $a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = true; |
| | | } |
| | | } |
| | | $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded)); |
| | | |
| | | // #1488692: update session |
| | | if ($_SESSION['mbox'] === $oldname) { |
| | | $_SESSION['mbox'] = $newname; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | |
| | | <?php |
| | | |
| | | /* |
| | | /** |
| | | +-----------------------------------------------------------------------+ |
| | | | program/steps/settings/save_folder.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2009, The Roundcube Dev Team | |
| | | | Copyright (C) 2005-2012, The Roundcube Dev Team | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | |
| | | } |
| | | } |
| | | |
| | | if (!$error) { |
| | | if ($error) { |
| | | $OUTPUT->command('display_message', $error, 'error'); |
| | | } |
| | | else { |
| | | $folder['name'] = $name_imap; |
| | | $folder['oldname'] = $old_imap; |
| | | $folder['class'] = ''; |
| | |
| | | } |
| | | else if (preg_match($oldprefix, $key)) { |
| | | unset($a_threaded[$key]); |
| | | $a_threaded[preg_replace($oldprefix, $folder['name'].$delimiter, $key)] = true; |
| | | $a_threaded[preg_replace($oldprefix, $folder['name'].$delimiter, $key)] = true; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | $OUTPUT->show_message('folderupdated', 'confirmation'); |
| | | |
| | | if ($rename) { |
| | | // #1488692: update session |
| | | if ($_SESSION['mbox'] === $folder['oldname']) { |
| | | $_SESSION['mbox'] = $folder['name']; |
| | | } |
| | | rcmail_update_folder_row($folder['name'], $folder['oldname'], $folder['subscribe'], $folder['class']); |
| | | $OUTPUT->send('iframe'); |
| | | } |
| | |
| | | <div id="mailboxlist-container"> |
| | | <div id="mailboxlist-title" class="boxtitle"><roundcube:label name="mailboxlist" /></div> |
| | | <div class="boxlistcontent"> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" maxlength="25" /> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" maxlength="25" /> |
| | | </div> |
| | | <div class="boxfooter"> |
| | | <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="button groupactions" onclick="rcmail_ui.show_popup('mailboxmenu');return false" content=" " /> |
| | | </div> |
| | | <div class="boxfooter"></div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | var mailviewsplitv = new rcube_splitter({id:'mailviewsplitterv', p1: 'mailboxlist-container', p2: 'messageframe', orientation: 'v', relative: true, start: 165}); |
| | | rcmail.add_onload('mailviewsplitv.init()'); |
| | | </script> |
| | | |
| | | <div id="mailboxoptionsmenu" class="popupmenu"> |
| | | <ul> |
| | | <li><roundcube:button command="expunge" type="link" label="compact" classAct="active" /></li> |
| | | <li class="separator_below"><roundcube:button command="purge" type="link" label="empty" classAct="active" /></li> |
| | | <li><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li> |
| | | <roundcube:container name="mailboxoptions" id="mailboxoptionsmenu" /> |
| | | </ul> |
| | | </div> |
| | | |
| | | </body> |
| | | </html> |
| | |
| | | <div id="mailboxlist-container"> |
| | | <div class="boxtitle"><roundcube:label name="mailboxlist" /></div> |
| | | <div class="boxlistcontent"> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" folder_filter="mail" /> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" folder_filter="mail" /> |
| | | </div> |
| | | <div class="boxfooter"> |
| | | <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="button groupactions" onclick="rcmail_ui.show_popup('mailboxmenu');return false" content=" " /> |
| | | </div> |
| | | <div class="boxfooter"></div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | var mailviewsplitv = new rcube_splitter({id:'mailviewsplitterv', p1: 'mailboxlist-container', p2: 'messageframe', orientation: 'v', relative: true, start: 165}); |
| | | rcmail.add_onload('mailviewsplitv.init()'); |
| | | </script> |
| | | |
| | | <div id="mailboxoptionsmenu" class="popupmenu"> |
| | | <ul> |
| | | <li><roundcube:button command="expunge" type="link" label="compact" classAct="active" /></li> |
| | | <li class="separator_below"><roundcube:button command="purge" type="link" label="empty" classAct="active" /></li> |
| | | <li><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li> |
| | | <roundcube:container name="mailboxoptions" id="mailboxoptionsmenu" /> |
| | | </ul> |
| | | </div> |
| | | |
| | | </body> |
| | | <roundcube:endif /> |
| | |
| | | position: absolute; |
| | | top: -6px; |
| | | left: 0; |
| | | right: 260px; |
| | | height: 40px; |
| | | white-space: nowrap; |
| | | z-index: 10; |
| | |
| | | .boxfooter .listbutton .inner, |
| | | .attachmentslist li a.delete, |
| | | .attachmentslist li a.cancelupload, |
| | | #messagepreviewheader .iconlink { |
| | | #messageheader .iconlink { |
| | | /* workaround for text-indent which also offsets the background image */ |
| | | text-indent: 0; |
| | | font-size: 0; |
| | |
| | | |
| | | .pagenav a.button, |
| | | .pagenav a.button span.inner, |
| | | #messagepreviewheader .iconlink, |
| | | #messageheader .iconlink, |
| | | #uploadform a.iconlink { |
| | | display: inline; |
| | | } |
| | |
| | | text-align: left; |
| | | } |
| | | |
| | | #messagepreviewheader .iconlink { |
| | | #messageheader .iconlink { |
| | | color: #fff; |
| | | height: 14px; |
| | | } |
| | |
| | | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#005d76', endColorstr='#004558', GradientType=0); |
| | | } |
| | | |
| | | #messageheader, #partheader, #composeheaders { |
| | | #partheader, #composeheaders { |
| | | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e9e9e9', GradientType=0); |
| | | } |
| | | |
| | |
| | | bottom: 28px; |
| | | } |
| | | |
| | | #mailview-top.fullheight { |
| | | border-radius: 4px 4px 0 0; |
| | | } |
| | | |
| | | #mailview-bottom { |
| | | position: absolute; |
| | | left: 0; |
| | | bottom: 0; |
| | | width: 100%; |
| | | height: 26px; |
| | | } |
| | | |
| | | #mailview-top.fullheight { |
| | | border-radius: 4px 4px 0 0; |
| | | } |
| | | |
| | | #folderlist-header { |
| | |
| | | #messagetoolbar { |
| | | position: absolute; |
| | | top: -6px; |
| | | right: 390px; |
| | | left: 0; |
| | | height: 40px; |
| | | white-space: nowrap; |
| | |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | width: 240px; |
| | | width: 400px; |
| | | } |
| | | |
| | | #mailpreviewtoggle { |
| | |
| | | |
| | | #messagecontent { |
| | | position: absolute; |
| | | top: 140px; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | bottom: 0; |
| | | bottom: 28px; |
| | | overflow: auto; |
| | | border-radius: 4px 4px 0 0; |
| | | } |
| | | |
| | | #messageheader, |
| | | #partheader, |
| | | #composeheaders { |
| | | position: relative; |
| | |
| | | |
| | | h3.subject { |
| | | font-size: 14px; |
| | | margin: 0 8em 0 0; |
| | | margin: 0 13em 0 0; |
| | | padding: 8px 8px 4px 8px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | |
| | | background: -ms-linear-gradient(left, #fbfbfb 0, #e9e9e9 100%); |
| | | background: linear-gradient(left, #fbfbfb 0, #e9e9e9 100%); |
| | | border-right: 1px solid #dfdfdf; |
| | | border-radius: 3px 0 0 0; /* for Opera */ |
| | | } |
| | | |
| | | #previewheaderstoggle .iconlink { |
| | |
| | | |
| | | #previewheaderstoggle.remove .iconlink { |
| | | top: auto; |
| | | bottom: 5px; |
| | | bottom: 15px; |
| | | background-position: -5px -242px; |
| | | } |
| | | |
| | | div.more-headers { |
| | | cursor: pointer; |
| | | height: 10px; |
| | | background: url(images/buttons.png) center -1619px no-repeat; |
| | | #previewheaderstoggle .iconlink.allheaders { |
| | | display: none; |
| | | } |
| | | |
| | | div.hide-headers { |
| | | background-position: center -1629px; |
| | | #previewheaderstoggle.remove .iconlink.allheaders { |
| | | top: auto; |
| | | bottom: 2px; |
| | | display: inline-block; |
| | | background-position: -27px -242px; |
| | | } |
| | | |
| | | #all-headers { |
| | | position: relative; |
| | | margin: 0 10px; |
| | | margin: 2px 0; |
| | | padding: 0; |
| | | height: 180px; |
| | | border: 1px solid #bbb; |
| | | background-color: #f0f0f0; |
| | | overflow: hidden; |
| | | border-radius: 4px; |
| | | background: #fff; |
| | | } |
| | | |
| | | #headers-source { |
| | |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | padding: 2px 5px; |
| | | padding: 2px; |
| | | overflow: auto; |
| | | text-align: left; |
| | | color: #333; |
| | | color: #666; |
| | | } |
| | | |
| | | #messagepreviewheader { |
| | | #messageheader { |
| | | position: relative; |
| | | height: auto; |
| | | margin: 0 8px 0 0; |
| | | padding: 0 0 6px 72px; |
| | | padding: 0 0 0 72px; |
| | | border-bottom: 2px solid #f0f0f0; |
| | | } |
| | | |
| | | #messagepreviewheader h3.subject { |
| | | #messagecontent #messageheader { |
| | | padding: 0 0 0 90px; |
| | | min-height: 68px; |
| | | } |
| | | |
| | | #messageheader h3.subject { |
| | | padding: 8px 8px 2px 0; |
| | | } |
| | | |
| | | #messagepreviewheader #contactphoto { |
| | | #messageheader #contactphoto { |
| | | display: block; |
| | | position: absolute; |
| | | top: 11px; |
| | |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | #messagepreviewheader #contactphoto img { |
| | | #messageheader #contactphoto img { |
| | | width: 32px; |
| | | height: auto; |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | #messageheader #contactphoto { |
| | | display: block; |
| | | position: absolute; |
| | | top: 40px; |
| | | right: 10px; |
| | | #messagecontent #messageheader #contactphoto { |
| | | top: 11px; |
| | | left: 31px; |
| | | width: 48px; |
| | | height: 48px; |
| | | overflow: hidden; |
| | | background: url(images/contactpic_48px.png) center center no-repeat #fff; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | #messageheader #contactphoto img { |
| | | #messagecontent #messageheader #contactphoto img { |
| | | width: 48px; |
| | | height: auto; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | #messagepreviewheader #countcontrols, |
| | | #messageheader #countcontrols { |
| | | position: absolute; |
| | | top: 8px; |
| | | right: 8px; |
| | | width: 20em; |
| | | right: 0; |
| | | text-align: right; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | #messageheader .pagenav .countdisplay { |
| | | min-width: 0; |
| | | padding-right: 0.5em; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | #messagecontent .leftcol, |
| | | #messagepreview .leftcol { |
| | | margin-right: 252px; |
| | | overflow-x: auto; |
| | | } |
| | | |
| | | #messagecontent .rightcol, |
| | | #messagepreview .rightcol { |
| | | float: right; |
| | | /* |
| | |
| | | min-height: 200px; |
| | | background: #f0f0f0; |
| | | padding: 8px; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | #messagebody { |
| | |
| | | left: 0; |
| | | bottom: 0; |
| | | width: 100%; |
| | | min-width: 1150px; |
| | | min-width: 1024px; |
| | | } |
| | | |
| | | .scroller { |
| | |
| | | * See http://creativecommons.org/licenses/by-sa/3.0/ for details. |
| | | */ |
| | | |
| | | ini_set('error_reporting', E_ALL &~ (E_NOTICE | E_STRICT)); |
| | | |
| | | header('Content-Type: image/svg+xml'); |
| | | header("Expires: ".gmdate("D, d M Y H:i:s", time()+864000)." GMT"); |
| | | header("Cache-Control: max-age=864000"); |
| | |
| | | background-image: url(svggradient.php?c=005d76;004558); |
| | | } |
| | | |
| | | #messageheader, #partheader, #composeheaders { |
| | | #partheader, #composeheaders { |
| | | background-image: url(svggradient.php?c=ffffff;e9e9e9); |
| | | } |
| | | |
| | |
| | | |
| | | <!-- folders list --> |
| | | <div id="mailboxcontainer" class="uibox listbox"> |
| | | <div class="scroller"> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" class="listing" folder_filter="mail" unreadwrap="%s" /> |
| | | </div> |
| | | <div class="scroller"> |
| | | <roundcube:object name="mailboxlist" id="mailboxlist" class="listing" folder_filter="mail" unreadwrap="%s" /> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div><!-- end mailview-left --> |
| | | |
| | | <div id="mailview-right"> |
| | | <div id="mailview-right" class="uibox" style="top: 42px"> |
| | | |
| | | <div id="mailview-top"> |
| | | <div id="messageheader" class="uibox"> |
| | | <h2 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h2> |
| | | <roundcube:object name="messageHeaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject" /> |
| | | <roundcube:object name="messageFullHeaders" id="full-headers" /> |
| | | <div id="messagecontent"> |
| | | |
| | | <div id="messageheader"> |
| | | <h3 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h3> |
| | | |
| | | <a href="#details" id="previewheaderstoggle"><span class="iconlink"></span><span id="headerstoggleall" class="iconlink allheaders"></span></a> |
| | | |
| | | <div id="contactphoto"><roundcube:object name="contactphoto" /></div> |
| | | |
| | | <table class="headers-table" id="preview-shortheaders"><tbody><tr> |
| | | <roundcube:if condition="env:mailbox == config:drafts_mbox || env:mailbox == config:sent_mbox"> |
| | | <td class="header-title"><roundcube:label name="to" /></td> |
| | | <td class="header from"><roundcube:object name="messageHeaders" valueOf="to" addicon="/images/addcontact.png" /></td> |
| | | <roundcube:else /> |
| | | <td class="header-title"><roundcube:label name="from" /></td> |
| | | <td class="header from"><roundcube:object name="messageHeaders" valueOf="from" addicon="/images/addcontact.png" /></td> |
| | | <roundcube:endif /> |
| | | <td class="header-title"><roundcube:label name="date" /></td> |
| | | <td class="header from"><roundcube:object name="messageHeaders" valueOf="date" /></td> |
| | | </tr></tbody></table> |
| | | |
| | | <roundcube:object name="messageHeaders" id="preview-allheaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject,replyto" /> |
| | | <roundcube:object name="messageFullHeaders" no-switch="true" /> |
| | | |
| | | <!-- record navigation --> |
| | | <div id="countcontrols" class="pagenav"> |
| | |
| | | <roundcube:button command="nextmessage" type="link" class="button nextpage disabled" classAct="button nextpage" classSel="button nextpage pressed" innerClass="inner" title="nextmessage" content="&gt;" /> |
| | | </div> |
| | | |
| | | <div id="contactphoto"><roundcube:object name="contactphoto" /></div> |
| | | </div><!-- end messageheader --> |
| | | |
| | | <div id="messagepreview"> |
| | | <div class="rightcol"> |
| | | <roundcube:object name="messageAttachments" id="attachment-list" class="attachmentslist" /> |
| | | </div> |
| | | <div class="leftcol"> |
| | | <roundcube:object name="messageObjects" id="message-objects" /> |
| | | <roundcube:object name="messageBody" id="messagebody" /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div id="messagecontent" class="uibox"> |
| | | <div class="rightcol"> |
| | | <roundcube:object name="messageAttachments" id="attachment-list" class="attachmentslist" /> |
| | | </div> |
| | | <div class="leftcol"> |
| | | <roundcube:object name="messageObjects" id="message-objects" /> |
| | | <roundcube:object name="messageBody" id="messagebody" /> |
| | | </div> |
| | | </div> |
| | | </div><!-- end messagecontent --> |
| | | |
| | | </div><!-- end mailview-top --> |
| | | |
| | | <div id="mailview-bottom" class="uibox"> |
| | | <roundcube:object name="message" id="message" class="statusbar" /> |
| | | </div> |
| | | |
| | | </div><!-- end mailview-right --> |
| | | |
| | |
| | | |
| | | </div> |
| | | |
| | | <div id="mailview-right"> |
| | | |
| | | <!-- toolbar --> |
| | | <div id="messagetoolbar" class="fullwidth"> |
| | | <div id="mailtoolbar" class="toolbar"> |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <div id="mailview-top" class="uibox watermark"></div> |
| | | <div id="mailview-right" class="uibox" style="top: 42px"> |
| | | |
| | | <div id="mailview-bottom" class="uibox"> |
| | | <roundcube:object name="message" id="message" class="statusbar" /> |
| | | </div> |
| | | <div id="messagecontent" class="watermark"></div> |
| | | |
| | | <roundcube:object name="message" id="message" class="statusbar" /> |
| | | |
| | | </div><!-- end mailview-right --> |
| | | |
| | |
| | | </head> |
| | | <body class="iframe fullheight"> |
| | | |
| | | <div id="messagepreviewheader"> |
| | | <div id="messageheader"> |
| | | <h3 class="subject"><roundcube:object name="messageHeaders" valueOf="subject" /></h3> |
| | | |
| | | <a href="#details" id="previewheaderstoggle"><span class="iconlink"></span></a> |
| | | <a href="#details" id="previewheaderstoggle"><span class="iconlink"></span><span id="headerstoggleall" class="iconlink allheaders"></a> |
| | | <div id="contactphoto"><roundcube:object name="contactphoto" /></div> |
| | | |
| | | <table class="headers-table" id="preview-shortheaders"><tbody><tr> |
| | |
| | | </tr></tbody></table> |
| | | |
| | | <roundcube:object name="messageHeaders" id="preview-allheaders" class="headers-table" addicon="/images/addcontact.png" exclude="subject,replyto" /> |
| | | <roundcube:object name="messageFullHeaders" no-switch="true" /> |
| | | |
| | | <!-- record navigation --> |
| | | <div id="countcontrols" class="pagenav"> |
| | |
| | | |
| | | if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') { |
| | | layout_messageview(); |
| | | rcmail.addEventListener('aftershow-headers', function() { layout_messageview(); }); |
| | | rcmail.addEventListener('afterhide-headers', function() { layout_messageview(); }); |
| | | $('#previewheaderstoggle').click(function(e){ toggle_preview_headers(this); return false }); |
| | | $('#previewheaderstoggle').click(function(e){ toggle_preview_headers(this); return false; }); |
| | | $('#headerstoggleall').click(function(e){ toggle_all_headers(this); return false; }); |
| | | } |
| | | else if (rcmail.env.action == 'compose') { |
| | | rcmail.addEventListener('aftertoggle-editor', function(){ window.setTimeout(function(){ layout_composeview() }, 200); }); |
| | |
| | | new rcube_splitter({ id:'identviewsplitter', p1:'#identitieslist', p2:'#identity-details', |
| | | orientation:'v', relative:true, start:266, min:180, size:12 }).init(); |
| | | } |
| | | else if (rcmail.env.action == 'preferences') { |
| | | else if (rcmail.env.action == 'preferences' || !rcmail.env.action) { |
| | | new rcube_splitter({ id:'prefviewsplitter', p1:'#sectionslist', p2:'#preferences-box', |
| | | orientation:'v', relative:true, start:266, min:180, size:12 }).init(); |
| | | } |
| | |
| | | |
| | | new rcube_scroller('#directorylist-content', '#directorylist-header', '#directorylist-footer'); |
| | | } |
| | | } |
| | | |
| | | // set min-width to show all toolbar buttons |
| | | var screen = $('.minwidth'); |
| | | if (screen.length) { |
| | | screen.css('min-width', $('.toolbar').width() + $('#quicksearchbar').parent().width() + 20); |
| | | } |
| | | |
| | | // turn a group of fieldsets into tabs |
| | |
| | | */ |
| | | function layout_messageview() |
| | | { |
| | | $('#messagecontent').css('top', ($('#messageheader').outerHeight() + 10) + 'px'); |
| | | $('#message-objects div a').addClass('button'); |
| | | |
| | | if (!$('#attachment-list li').length) { |
| | |
| | | { |
| | | $('#preview-shortheaders').toggle(); |
| | | var full = $('#preview-allheaders').toggle(), |
| | | button = $('a#previewheaderstoggle'); |
| | | button = $('#previewheaderstoggle'); |
| | | |
| | | if (!$('#headerstoggleall').length) |
| | | $('#all-headers').toggle(); |
| | | |
| | | // add toggle button to full headers table |
| | | if (full.is(':visible')) |
| | | button.attr('href', '#hide').removeClass('add').addClass('remove') |
| | | else |
| | | button.attr('href', '#details').removeClass('remove').addClass('add') |
| | | if (full.is(':visible')) { |
| | | button.attr('href', '#hide').removeClass('add').addClass('remove'); |
| | | } |
| | | else { |
| | | button.attr('href', '#details').removeClass('remove').addClass('add'); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Show/hide all message headers |
| | | */ |
| | | function toggle_all_headers(button) |
| | | { |
| | | rcmail.command('show-headers', '', button); |
| | | $(button).remove(); |
| | | $('#previewheaderstoggle span').css({bottom: '5px'}); |
| | | |
| | | return false; |
| | | } |
| | | |
| | | |
| | |
| | | function data_clean() |
| | | { |
| | | return array( |
| | | array('', '', 'Empty string'), |
| | | array('', ''), |
| | | array("\xC1", ''), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_clean |
| | | */ |
| | | function test_clean($input, $output, $title) |
| | | function test_clean($input, $output) |
| | | { |
| | | $this->assertEquals(rcube_charset::clean($input), $output, $title); |
| | | $this->assertEquals($output, rcube_charset::clean($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_parse_charset() |
| | | */ |
| | | function data_parse_charset() |
| | | { |
| | | return array( |
| | | array('UTF8', 'UTF-8'), |
| | | array('WIN1250', 'WINDOWS-1250'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_parse_charset |
| | | */ |
| | | function test_parse_charset($input, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::parse_charset($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_convert() |
| | | */ |
| | | function data_convert() |
| | | { |
| | | return array( |
| | | array('ö', 'ö', 'UTF-8', 'UTF-8'), |
| | | array('ö', '', 'UTF-8', 'US-ASCII'), |
| | | array('aż', 'a', 'UTF-8', 'US-ASCII'), |
| | | array('&BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки', 'UTF7-IMAP', 'UTF-8'), |
| | | array('Рассылки', '&BCAEMARBBEEESwQ7BDoEOA-', 'UTF-8', 'UTF7-IMAP'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_convert |
| | | */ |
| | | function test_convert($input, $output, $from, $to) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::convert($input, $from, $to)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_utf7_to_utf8() |
| | | */ |
| | | function data_utf7_to_utf8() |
| | | { |
| | | return array( |
| | | array('+BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_utf7_to_utf8 |
| | | */ |
| | | function test_utf7_to_utf8($input, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::utf7_to_utf8($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_utf7imap_to_utf8() |
| | | */ |
| | | function data_utf7imap_to_utf8() |
| | | { |
| | | return array( |
| | | array('&BCAEMARBBEEESwQ7BDoEOA-', 'Рассылки'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_utf7imap_to_utf8 |
| | | */ |
| | | function test_utf7imap_to_utf8($input, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::utf7imap_to_utf8($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_utf8_to_utf7imap() |
| | | */ |
| | | function data_utf8_to_utf7imap() |
| | | { |
| | | return array( |
| | | array('Рассылки', '&BCAEMARBBEEESwQ7BDoEOA-'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_utf8_to_utf7imap |
| | | */ |
| | | function test_utf8_to_utf7imap($input, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::utf8_to_utf7imap($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_utf16_to_utf8() |
| | | */ |
| | | function data_utf16_to_utf8() |
| | | { |
| | | return array( |
| | | array(base64_decode('BCAEMARBBEEESwQ7BDoEOA=='), 'Рассылки'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_utf16_to_utf8 |
| | | */ |
| | | function test_utf16_to_utf8($input, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::utf16_to_utf8($input)); |
| | | } |
| | | |
| | | /** |
| | | * Data for test_detect() |
| | | */ |
| | | function data_detect() |
| | | { |
| | | return array( |
| | | array('', '', 'UTF-8'), |
| | | array('a', 'UTF-8', 'UTF-8'), |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * @dataProvider data_detect |
| | | */ |
| | | function test_detect($input, $fallback, $output) |
| | | { |
| | | $this->assertEquals($output, rcube_charset::detect($input, $fallback)); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | } |
| | | |
| | | /** |
| | | * rcube_shared.inc: is_ascii() |
| | | */ |
| | | function test_is_ascii() |
| | | { |
| | | $result = is_ascii("0123456789"); |
| | | $this->assertTrue($result, "Valid ASCII (numbers)"); |
| | | |
| | | $result = is_ascii("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); |
| | | $this->assertTrue($result, "Valid ASCII (letters)"); |
| | | |
| | | $result = is_ascii(" !\"#\$%&'()*+,-./:;<=>?@[\\^_`{|}~"); |
| | | $this->assertTrue($result, "Valid ASCII (special characters)"); |
| | | |
| | | $result = is_ascii("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" |
| | | ."\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"); |
| | | $this->assertTrue($result, "Valid ASCII (control characters)"); |
| | | |
| | | $result = is_ascii("\n", false); |
| | | $this->assertFalse($result, "Valid ASCII (control characters)"); |
| | | |
| | | $result = is_ascii("ż"); |
| | | $this->assertFalse($result, "Invalid ASCII (UTF-8 character)"); |
| | | |
| | | $result = is_ascii("ż", false); |
| | | $this->assertFalse($result, "Invalid ASCII (UTF-8 character [2])"); |
| | | } |
| | | |
| | | } |
| | |
| | | $this->assertEquals("Iksiñski", $vcards2[0]->surname, "Detect charset in encoded values"); |
| | | } |
| | | |
| | | function test_import_photo_encoding() |
| | | { |
| | | $input = file_get_contents($this->_srcpath('photo.vcf')); |
| | | |
| | | $vcards = rcube_vcard::import($input); |
| | | $vcard = $vcards[0]->get_assoc(); |
| | | |
| | | $this->assertCount(1, $vcards, "Detected 1 vcard"); |
| | | |
| | | // ENCODING=b case (#1488683) |
| | | $this->assertEquals("/9j/4AAQSkZJRgABAQA", substr(base64_encode($vcard['photo']), 0, 19), "Photo decoding"); |
| | | $this->assertEquals("Müller", $vcard['surname'], "Unicode characters"); |
| | | } |
| | | |
| | | function test_encodings() |
| | | { |
| | | $input = file_get_contents($this->_srcpath('utf-16_sample.vcf')); |
New file |
| | |
| | | BEGIN:VCARD
|
| | | VERSION:3.0
|
| | | N:Müller;Jörg;;;
|
| | | FN:Apple Computer AG
|
| | | ORG:Apple Computer AG;
|
| | | PHOTO;ENCODING=b:
|
| | | /9j/4AAQSkZJRgABAQAAAQABAAD/7QAcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAD/2wBDAAEB |
| | | AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB |
| | | AQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB |
| | | AQEBAQEBAQEBAQEBAQEBAQH/wAARCAAwADADAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAA |
| | | AAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEI |
| | | I0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq |
| | | c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW |
| | | 19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL |
| | | /8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLR |
| | | ChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE |
| | | hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn |
| | | 6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKAPmH43ftT+CfgzqNt4bNjeeLvGV2IHXw7 |
| | | pVxDbLZx3LBbdtU1GVLhbN7jIMFvHa3VzIpWRoY4mWQ9dDCTrrmuoQ/mavfvZXV7dW2jkr4ynQfL |
| | | Zzn1inZL1lZ6+ST87H0lp1zLe6fY3k9s1nNd2dtczWjv5j2ss8KSyWzybU3tA7mJn2JuKk7Vzgcr |
| | | Vm1e9m1fvrv8zqi+aKbVm0nbtdXt8i5SGFAHHeOfH3hH4b6DP4k8Z61a6JpUBCCW4LPNdTsCUtbK |
| | | 1iD3F5dSYO2C3jd8AuwVFZhdOnOrLlhFyf4Lzb6IzqVYUo81SSiundvslu3/AEz5i0n9u74Fanqo |
| | | 064m8UaNbvII49X1TRUGnnORvmFje3t5BGTjDtatwcyCPBrreArpX9xvqlJ3/FJP7zlWYUHKzVRL |
| | | +ZxVvnaTa+4+QLvVPgJ4U+LutfFXx78QJfi3q954iuvEOieHvBmkyzaVbO1x5ulPruq6pLawTvp1 |
| | | uLdIrK08xFmgXzl2oI67LV50o0qdP2K5VGUptKXnyxi29XfVtb6HDehGtKpUm6zcnNKCfK9brnlK |
| | | 3pZJ37pH3/8ACj9qb4T/ABd1FdD0TUr3SPETozwaJ4ht47C5vQgLONOnjnuLS8dVBYwJOt1tDMIN |
| | | oLV51XCVqK5pJSj1cW3b1uk1vvqvM9Kji6VZ8qbjJ7KVlf0abTf4n0dXMdQUAfhf+2J8UNW8ffFz |
| | | W9Cnlki0XwDqOp+GdNsFdhB9qsr6a31DUDHu2tcXbwojSEbhFCka4Uc+9hKUadGMl8VRKcn11V0v |
| | | RJng4urKpWkntTlKCXTRtN+re58n11HKFAH6PfsGfBvQfEl3rHxR8Q2y38vhrUrfT/DNpIT5FvqY |
| | | iF1carIgI8ye2R4Y7RXykbySTbS6xlfOx9aUVGlF2503N+W1vnrc9HAUYzlKrJX5GuVf3t7+dvu3 |
| | | vc/WKvIPXCgD8FP2s/BF/wCC/jd4wlu0It/Fmp6h4usJf4JINZ1G7ndVbu0UpZZBztY446V9BhZq |
| | | dCnZ/DFQfrFJHz+Kg4V6l/tSc15qTb/rzPmqug5woA++v2J/j74d+HN9rHgLxndrpmjeJr62vtJ1 |
| | | mbP2Sw1dY/s0ltfOM+Rb30Yh8u5ZTHFPEFlZEk3Dgx2HlVUZw1lBNOPVp9vNa6X22137sFiI0ZSh |
| | | N2jNpqXSLSe/k+/R+p+w1eMe0FAHxz+2P8DLr4r+CIPEPhy2Nx4y8FJdXVnaxrmfWdGlAk1DSosK |
| | | WkuozEt5p8fHmTLNADuuQR24KuqU3GTtCpbXtLo32T2b9GcWNw7qwU4q84X06yi9Wl531XfXyPxK |
| | | ME4nNsYZRciUwG3MbicTh/LMJix5glD/ACGPbv3/AC4zxXtniFvUNJ1XSmjXVNM1DTWmUvCuoWVz |
| | | ZtKgxloxcRxmRRkZZcgZGTzSTT2afo7hqtz6w/ZB+BV78UPHtl4n1eykHgfwdewajfXE0bCDVtVt |
| | | mE+n6PAzAJOBOkdxqAUssdsnlSDNwoPLi66pU3FP95NNJdk95P06d35XOvCUHWqJtfu4NOT7vdR8 |
| | | 7vfsvVH7gV4R7oUAFAHKReA/A8Gsy+IofBnhSHxBO7ST67F4d0iPWZnb7zy6mlmL2R2/iZ5yT3NX |
| | | 7Spbl9pPl/l55W+69iPZUubm9nDmvfm5I81+97XuX9a8MeGvEtsLLxF4e0PX7MMGFprWk2Gq2wZe |
| | | jCC+t54tw7HZkdqUZzg7wlKL7xk4v700OUIT0lCMl2lFS/NMuaXpOlaHZQ6Zoumafo+nW4It9P0u |
| | | yttPsoATkiG1tI4oIgTyQkagnmk5Sk7ybk+7bb+96jjGMVaMVFdopJfcjQpDP//Z
|
| | | X-ABShowAs:COMPANY
|
| | | X-ABUID:2E4CB084-4767-4C85-BBCA-805B1DCB1C8E\:ABPerson
|
| | | END:VCARD
|