diff options
author | Hugues Hiegel <root@paranoid> | 2014-08-05 16:46:22 +0200 |
---|---|---|
committer | Hugues Hiegel <root@paranoid> | 2014-08-05 16:46:22 +0200 |
commit | 59478e06c25303a790a0840ab2ac30662c4ef781 (patch) | |
tree | 8d5e964a8f94adaef41efebb0597629f11495c42 /program | |
parent | 7c494b677f9e470ee0d32e62cfa8dc709f39e748 (diff) |
c'est la merde..working
Diffstat (limited to 'program')
249 files changed, 16930 insertions, 17146 deletions
diff --git a/program/include/bc.php b/program/include/bc.php index a7d7b5ac1..af2e51210 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -62,7 +62,7 @@ function rcmail_url($action, $p=array(), $task=null) function rcmail_temp_gc() { - rcmail::get_instance()->gc_temp(); + $rcmail = rcmail::get_instance()->temp_gc(); } function rcube_charset_convert($str, $from, $to=NULL) @@ -205,9 +205,9 @@ function rcmail_quota_content($attrib = null) return rcmail::get_instance()->quota_content($attrib); } -function rcmail_display_server_error($fallback=null, $fallback_args=null, $suffix='') +function rcmail_display_server_error($fallback=null, $fallback_args=null) { - rcmail::get_instance()->display_server_error($fallback, $fallback_args, $suffix); + rcmail::get_instance()->display_server_error($fallback, $fallback_args); } function rcmail_filetype2classname($mimetype, $filename) @@ -405,16 +405,6 @@ function enriched_to_html($data) return rcube_enriched::to_html($data); } -function strip_quotes($str) -{ - return str_replace(array("'", '"'), '', $str); -} - -function strip_newlines($str) -{ - return preg_replace('/[\r\n]/', '', $str); -} - class rcube_html_page extends rcmail_html_page { } diff --git a/program/include/iniset.php b/program/include/iniset.php index 919cc7682..e4fa956ef 100644 --- a/program/include/iniset.php +++ b/program/include/iniset.php @@ -21,11 +21,11 @@ */ // application constants -define('RCMAIL_VERSION', '1.0-git'); +define('RCMAIL_VERSION', '0.9.5'); define('RCMAIL_START', microtime(true)); if (!defined('INSTALL_PATH')) { - define('INSTALL_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); + define('INSTALL_PATH', '/var/lib/roundcube/'); } if (!defined('RCMAIL_CONFIG_DIR')) { @@ -60,11 +60,6 @@ require_once 'Roundcube/bootstrap.php'; // register autoloader for rcmail app classes spl_autoload_register('rcmail_autoload'); -// include composer autoloader (if available) -if (file_exists('vendor/autoload.php')) { - require 'vendor/autoload.php'; -} - // backward compatybility (to be removed) require_once INSTALL_PATH . 'program/include/bc.php'; diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 0483f0e18..c9350bdd9 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -51,7 +51,6 @@ class rcmail extends rcube */ public $action = ''; public $comm_path = './'; - public $filename = ''; private $address_books = array(); private $action_map = array(); @@ -66,13 +65,12 @@ class rcmail extends rcube /** * This implements the 'singleton' design pattern * - * @param string Environment name to run (e.g. live, dev, test) * @return rcmail The one and only instance */ - static function get_instance($env = '') + static function get_instance() { if (!self::$instance || !is_a(self::$instance, 'rcmail')) { - self::$instance = new rcmail($env); + self::$instance = new rcmail(); self::$instance->startup(); // init AFTER object was linked with self::$instance } @@ -88,10 +86,6 @@ class rcmail extends rcube { $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS); - // set filename if not index.php - if (($basename = basename($_SERVER['SCRIPT_FILENAME'])) && $basename != 'index.php') - $this->filename = $basename; - // start session $this->session_init(); @@ -132,7 +126,7 @@ class rcmail extends rcube */ public function set_task($task) { - $task = asciiwords($task, true); + $task = asciiwords($task); if ($this->user && $this->user->ID) $task = !$task ? 'mail' : $task; @@ -168,7 +162,7 @@ class rcmail extends rcube setlocale(LC_ALL, $lang . '.utf8', $lang . '.UTF-8', 'en_US.utf8', 'en_US.UTF-8'); // workaround for http://bugs.php.net/bug.php?id=18556 - if (version_compare(PHP_VERSION, '5.5.0', '<') && in_array($lang, array('tr_TR', 'ku', 'az_AZ'))) { + if (in_array($lang, array('tr_TR', 'ku', 'az_AZ'))) { setlocale(LC_CTYPE, 'en_US.utf8', 'en_US.UTF-8'); } } @@ -289,13 +283,13 @@ class rcmail extends rcube */ public function get_address_sources($writeable = false, $skip_hidden = false) { - $abook_type = (string) $this->config->get('address_book_type'); - $ldap_config = (array) $this->config->get('ldap_public'); + $abook_type = strtolower($this->config->get('address_book_type')); + $ldap_config = $this->config->get('ldap_public'); $autocomplete = (array) $this->config->get('autocomplete_addressbooks'); - $list = array(); + $list = array(); // We are using the DB address book or a plugin address book - if (!empty($abook_type) && strtolower($abook_type) != 'ldap') { + if ($abook_type != 'ldap' && $abook_type != '') { if (!isset($this->address_books['0'])) $this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id()); $list['0'] = array( @@ -308,7 +302,8 @@ class rcmail extends rcube ); } - if (!empty($ldap_config)) { + if ($ldap_config) { + $ldap_config = (array) $ldap_config; foreach ($ldap_config as $id => $prop) { // handle misconfiguration if (empty($prop) || !is_array($prop)) { @@ -317,7 +312,7 @@ class rcmail extends rcube $list[$id] = array( 'id' => $id, 'name' => html::quote($prop['name']), - 'groups' => !empty($prop['groups']) || !empty($prop['group_filters']), + 'groups' => is_array($prop['groups']), 'readonly' => !$prop['writable'], 'hidden' => $prop['hidden'], 'autocomplete' => in_array($id, $autocomplete) @@ -481,22 +476,15 @@ class rcmail extends rcube $port = $config['default_port']; } - // Check if we need to add/force domain to username - if (!empty($config['username_domain'])) { - $domain = is_array($config['username_domain']) ? $config['username_domain'][$host] : $config['username_domain']; - - if ($domain = rcube_utils::parse_host((string)$domain, $host)) { - $pos = strpos($username, '@'); - - // force configured domains - if (!empty($config['username_domain_forced']) && $pos !== false) { - $username = substr($username, 0, $pos) . '@' . $domain; - } - // just add domain if not specified - else if ($pos === false) { - $username .= '@' . $domain; - } - } + /* Modify username with domain if required + Inspired by Marco <P0L0_notspam_binware.org> + */ + // Check if we need to add domain + if (!empty($config['username_domain']) && strpos($username, '@') === false) { + if (is_array($config['username_domain']) && isset($config['username_domain'][$host])) + $username .= '@'.rcube_utils::parse_host($config['username_domain'][$host], $host); + else if (is_string($config['username_domain'])) + $username .= '@'.rcube_utils::parse_host($config['username_domain'], $host); } if (!isset($config['login_lc'])) { @@ -631,7 +619,7 @@ class rcmail extends rcube $post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); $post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST); - list(, $domain) = explode('@', $post_user); + list($user, $domain) = explode('@', $post_user); // direct match in default_host array if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { @@ -735,6 +723,28 @@ class rcmail extends rcube /** + * Create unique authorization hash + * + * @param string Session ID + * @param int Timestamp + * @return string The generated auth hash + */ + private function get_auth_hash($sess_id, $ts) + { + $auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s', + $sess_id, + $ts, + $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***', + $_SERVER['HTTP_USER_AGENT']); + + if (function_exists('sha1')) + return sha1($auth_string); + else + return md5($auth_string); + } + + + /** * Build a valid URL to this instance of Roundcube * * @param mixed Either a string with the action or url parameters as key-value pairs @@ -754,7 +764,7 @@ class rcmail extends rcube $p['_task'] = $task; unset($p['task']); - $url = './' . $this->filename; + $url = './'; $delm = '?'; foreach (array_reverse($p) as $key => $val) { if ($val !== '' && $val !== null) { @@ -779,6 +789,11 @@ class rcmail extends rcube $book->close(); } + // before closing the database connection, write session data + if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { + session_write_close(); + } + // write performance stats to logs/console if ($this->config->get('devel_mode')) { if (function_exists('memory_get_usage')) @@ -939,6 +954,193 @@ class rcmail extends rcube /** + * Send the given message using the configured method. + * + * @param object $message Reference to Mail_MIME object + * @param string $from Sender address string + * @param array $mailto Array of recipient address strings + * @param array $error SMTP error array (reference) + * @param string $body_file Location of file with saved message body (reference), + * used when delay_file_io is enabled + * @param array $options SMTP options (e.g. DSN request) + * + * @return boolean Send status. + */ + public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) + { + $plugin = $this->plugins->exec_hook('message_before_send', array( + 'message' => $message, + 'from' => $from, + 'mailto' => $mailto, + 'options' => $options, + )); + + if ($plugin['abort']) { + return isset($plugin['result']) ? $plugin['result'] : false; + } + + $from = $plugin['from']; + $mailto = $plugin['mailto']; + $options = $plugin['options']; + $message = $plugin['message']; + $headers = $message->headers(); + + // send thru SMTP server using custom SMTP library + if ($this->config->get('smtp_server')) { + // generate list of recipients + $a_recipients = array($mailto); + + if (strlen($headers['Cc'])) + $a_recipients[] = $headers['Cc']; + if (strlen($headers['Bcc'])) + $a_recipients[] = $headers['Bcc']; + + // clean Bcc from header for recipients + $send_headers = $headers; + unset($send_headers['Bcc']); + // here too, it because txtHeaders() below use $message->_headers not only $send_headers + unset($message->_headers['Bcc']); + + $smtp_headers = $message->txtHeaders($send_headers, true); + + if ($message->getParam('delay_file_io')) { + // use common temp dir + $temp_dir = $this->config->get('temp_dir'); + $body_file = tempnam($temp_dir, 'rcmMsg'); + if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { + self::raise_error(array('code' => 650, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not create message: ".$mime_result->getMessage()), + TRUE, FALSE); + return false; + } + $msg_body = fopen($body_file, 'r'); + } + else { + $msg_body = $message->get(); + } + + // send message + if (!is_object($this->smtp)) { + $this->smtp_init(true); + } + + $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options); + $response = $this->smtp->get_response(); + $error = $this->smtp->get_error(); + + // log error + if (!$sent) { + self::raise_error(array('code' => 800, 'type' => 'smtp', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => "SMTP error: ".join("\n", $response)), TRUE, FALSE); + } + } + // send mail using PHP's mail() function + else { + // unset some headers because they will be added by the mail() function + $headers_enc = $message->headers($headers); + $headers_php = $message->_headers; + unset($headers_php['To'], $headers_php['Subject']); + + // reset stored headers and overwrite + $message->_headers = array(); + $header_str = $message->txtHeaders($headers_php); + + // #1485779 + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { + $headers_enc['To'] = implode(', ', $m[1]); + } + } + + $msg_body = $message->get(); + + if (PEAR::isError($msg_body)) { + self::raise_error(array('code' => 650, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not create message: ".$msg_body->getMessage()), + TRUE, FALSE); + } + else { + $delim = $this->config->header_delimiter(); + $to = $headers_enc['To']; + $subject = $headers_enc['Subject']; + $header_str = rtrim($header_str); + + if ($delim != "\r\n") { + $header_str = str_replace("\r\n", $delim, $header_str); + $msg_body = str_replace("\r\n", $delim, $msg_body); + $to = str_replace("\r\n", $delim, $to); + $subject = str_replace("\r\n", $delim, $subject); + } + + if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN)) + $sent = mail($to, $subject, $msg_body, $header_str); + else + $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); + } + } + + if ($sent) { + $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); + + // remove MDN headers after sending + unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); + + // get all recipients + if ($headers['Cc']) + $mailto .= $headers['Cc']; + if ($headers['Bcc']) + $mailto .= $headers['Bcc']; + if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) + $mailto = implode(', ', array_unique($m[1])); + + if ($this->config->get('smtp_log')) { + self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", + $this->user->get_username(), + $_SERVER['REMOTE_ADDR'], + $mailto, + !empty($response) ? join('; ', $response) : '')); + } + } + + if (is_resource($msg_body)) { + fclose($msg_body); + } + + $message->_headers = array(); + $message->headers($headers); + + return $sent; + } + + + /** + * Unique Message-ID generator. + * + * @return string Message-ID + */ + public function gen_message_id() + { + $local_part = md5(uniqid('rcmail'.mt_rand(),true)); + $domain_part = $this->user->get_username('domain'); + + // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) + if (!preg_match('/\.[a-z]+$/i', $domain_part)) { + foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) { + $host = preg_replace('/:[0-9]+$/', '', $host); + if ($host && preg_match('/\.[a-z]+$/i', $host)) { + $domain_part = $host; + } + } + } + + return sprintf('<%s@%s>', $local_part, $domain_part); + } + + + /** * Returns RFC2822 formatted current date in user's timezone * * @return string Date @@ -961,32 +1163,22 @@ class rcmail extends rcube /** * Write login data (name, ID, IP address) to the 'userlogins' log file. */ - public function log_login($user = null, $failed_login = false, $error_code = 0) + public function log_login() { if (!$this->config->get('log_logins')) { return; } - // failed login - if ($failed_login) { - $message = sprintf('Failed login for %s from %s in session %s (error: %d)', - $user, rcube_utils::remote_ip(), session_id(), $error_code); - } - // successful login - else { - $user_name = $this->get_user_name(); - $user_id = $this->get_user_id(); + $user_name = $this->get_user_name(); + $user_id = $this->get_user_id(); - if (!$user_id) { - return; - } - - $message = sprintf('Successful login for %s (ID: %d) from %s in session %s', - $user_name, $user_id, rcube_utils::remote_ip(), session_id()); + if (!$user_id) { + return; } - // log login - self::write_log('userlogins', $message); + self::write_log('userlogins', + sprintf('Successful login for %s (ID: %d) from %s in session %s', + $user_name, $user_id, rcube_utils::remote_ip(), session_id())); } @@ -1002,7 +1194,7 @@ class rcmail extends rcube */ public function table_output($attrib, $table_data, $a_show_cols, $id_col) { - $table = new html_table($attrib); + $table = new html_table(/*array('cols' => count($a_show_cols))*/); // add table header if (!$attrib['noheader']) { @@ -1243,7 +1435,6 @@ class rcmail extends rcube $js_mailboxlist = array(); $out = html::tag('ul', $attrib, $rcmail->render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib); - $rcmail->output->include_script('treelist.js'); $rcmail->output->add_gui_object('mailboxlist', $attrib['id']); $rcmail->output->set_env('mailboxes', $js_mailboxlist); $rcmail->output->set_env('unreadwrap', $attrib['unreadwrap']); @@ -1365,10 +1556,9 @@ class rcmail extends rcube $realnames = (bool)$attrib['realnames']; $msgcounts = $this->storage->get_cache('messagecount'); $collapsed = $this->config->get('collapsed_folders'); - $realnames = $this->config->get('show_real_foldernames'); $out = ''; - foreach ($arrFolders as $folder) { + foreach ($arrFolders as $key => $folder) { $title = null; $folder_class = $this->folder_classname($folder['id']); $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false; @@ -1423,13 +1613,14 @@ class rcmail extends rcube 'id' => "rcmli".$folder_id, 'class' => join(' ', $classes), 'noclose' => true), - html::a($link_attrib, $html_name)); - - if (!empty($folder['folders'])) { - $out .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), ' '); - } - - $jslist[$folder['id']] = array( + html::a($link_attrib, $html_name) . + (!empty($folder['folders']) ? html::div(array( + 'class' => ($is_collapsed ? 'collapsed' : 'expanded'), + 'style' => "position:absolute", + 'onclick' => sprintf("%s.command('collapse-folder', '%s')", rcmail_output::JS_OBJECT_NAME, $js_name) + ), ' ') : '')); + + $jslist[$folder_id] = array( 'id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual'] @@ -1454,7 +1645,7 @@ class rcmail extends rcube { $out = ''; - foreach ($arrFolders as $folder) { + foreach ($arrFolders as $key => $folder) { // skip exceptions (and its subfolders) if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { continue; @@ -1515,38 +1706,18 @@ class rcmail extends rcube * Try to localize the given IMAP folder name. * UTF-7 decode it in case no localized text was found * - * @param string $name Folder name - * @param bool $with_path Enable path localization + * @param string $name Folder name * * @return string Localized folder name in UTF-8 encoding */ - public function localize_foldername($name, $with_path = true) + public function localize_foldername($name) { - $realnames = $this->config->get('show_real_foldernames'); - - // try to localize path of the folder - if ($with_path && !$realnames) { - $storage = $this->get_storage(); - $delimiter = $storage->get_hierarchy_delimiter(); - $path = explode($delimiter, $name); - $count = count($path); - - if ($count > 1) { - for ($i = 0; $i < $count; $i++) { - $folder = implode($delimiter, array_slice($path, 0, -$i)); - if ($folder_class = $this->folder_classname($folder)) { - $name = implode($delimiter, array_slice($path, $count - $i)); - return $this->gettext($folder_class) . $delimiter . rcube_charset::convert($name, 'UTF7-IMAP'); - } - } - } - } - - if (!$realnames && ($folder_class = $this->folder_classname($name))) { + if ($folder_class = $this->folder_classname($name)) { return $this->gettext($folder_class); } - - return rcube_charset::convert($name, 'UTF7-IMAP'); + else { + return rcube_charset::convert($name, 'UTF7-IMAP'); + } } @@ -1601,7 +1772,11 @@ class rcmail extends rcube $quota_result = (array) $quota; $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; - if ($quota['total'] > 0) { + if (!$quota['total'] && $this->config->get('quota_zero_as_unlimited')) { + $quota_result['title'] = $this->gettext('unlimited'); + $quota_result['percent'] = 0; + } + else if ($quota['total']) { if (!isset($quota['percent'])) { $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100)); } @@ -1620,8 +1795,7 @@ class rcmail extends rcube } } else { - $unlimited = $this->config->get('quota_zero_as_unlimited'); - $quota_result['title'] = $this->gettext($unlimited ? 'unlimited' : 'unknown'); + $quota_result['title'] = $this->gettext('unknown'); $quota_result['percent'] = 0; } @@ -1634,51 +1808,32 @@ class rcmail extends rcube * * @param string $fallback Fallback message label * @param array $fallback_args Fallback message label arguments - * @param string $suffix Message label suffix */ - public function display_server_error($fallback = null, $fallback_args = null, $suffix = '') + public function display_server_error($fallback = null, $fallback_args = null) { $err_code = $this->storage->get_error_code(); $res_code = $this->storage->get_response_code(); - $args = array(); if ($res_code == rcube_storage::NOPERM) { - $error = 'errornoperm'; + $this->output->show_message('errornoperm', 'error'); } else if ($res_code == rcube_storage::READONLY) { - $error = 'errorreadonly'; - } - else if ($res_code == rcube_storage::OVERQUOTA) { - $error = 'errorroverquota'; + $this->output->show_message('errorreadonly', 'error'); } else if ($err_code && ($err_str = $this->storage->get_error_str())) { // try to detect access rights problem and display appropriate message if (stripos($err_str, 'Permission denied') !== false) { - $error = 'errornoperm'; - } - // try to detect full mailbox problem and display appropriate message - // there can be e.g. "Quota exceeded" or "quotum would exceed" - else if (stripos($err_str, 'quot') !== false && stripos($err_str, 'exceed') !== false) { - $error = 'erroroverquota'; + $this->output->show_message('errornoperm', 'error'); } else { - $error = 'servererrormsg'; - $args = array('msg' => $err_str); + $this->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); } } else if ($err_code < 0) { - $error = 'storageerror'; + $this->output->show_message('storageerror', 'error'); } else if ($fallback) { - $error = $fallback; - $args = $fallback_args; - } - - if ($error) { - if ($suffix && $this->text_exists($error . $suffix)) { - $error .= $suffix; - } - $this->output->show_message($error, 'error', $args); + $this->output->show_message($fallback, 'error', $fallback_args); } } diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index a2ec29ca3..465d92f83 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -67,7 +67,6 @@ class rcmail_output_html extends rcmail_output //$this->framed = $framed; $this->set_env('task', $task); $this->set_env('x_frame_options', $this->config->get('x_frame_options', 'sameorigin')); - $this->set_env('standard_windows', (bool) $this->config->get('standard_windows')); // add cookie info $this->set_env('cookie_domain', ini_get('session.cookie_domain')); @@ -106,6 +105,7 @@ class rcmail_output_html extends rcmail_output )); } + /** * Set environment variable * @@ -121,6 +121,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Getter for the current page title * @@ -144,17 +145,17 @@ class rcmail_output_html extends rcmail_output return $title; } + /** * Set skin */ public function set_skin($skin) { $valid = false; - $path = RCUBE_INSTALL_PATH . 'skins/'; - if (!empty($skin) && is_dir($path . $skin) && is_readable($path . $skin)) { - $skin_path = 'skins/' . $skin; - $valid = true; + if (!empty($skin) && is_dir('skins/'.$skin) && is_readable('skins/'.$skin)) { + $skin_path = 'skins/'.$skin; + $valid = true; } else { $skin_path = $this->config->get('skin_path'); @@ -182,16 +183,13 @@ class rcmail_output_html extends rcmail_output $this->skin_paths[] = $skin_path; // read meta file and check for dependecies - $meta = @file_get_contents(RCUBE_INSTALL_PATH . $skin_path . '/meta.json'); - $meta = @json_decode($meta, true); - if ($meta['extends']) { - $path = RCUBE_INSTALL_PATH . 'skins/'; - if (is_dir($path . $meta['extends']) && is_readable($path . $meta['extends'])) { - $this->load_skin('skins/' . $meta['extends']); - } + $meta = @json_decode(@file_get_contents($skin_path.'/meta.json'), true); + if ($meta['extends'] && is_dir('skins/' . $meta['extends'])) { + $this->load_skin('skins/' . $meta['extends']); } } + /** * Check if a specific template exists * @@ -200,18 +198,17 @@ class rcmail_output_html extends rcmail_output */ public function template_exists($name) { + $found = false; foreach ($this->skin_paths as $skin_path) { - $filename = RCUBE_INSTALL_PATH . $skin_path . '/templates/' . $name . '.html'; - if ((is_file($filename) && is_readable($filename)) - || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name])) - ) { - return true; - } + $filename = $skin_path . '/templates/' . $name . '.html'; + $found = (is_file($filename) && is_readable($filename)) || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name])); + if ($found) + break; } - - return false; + return $found; } + /** * Find the given file in the current skin path stack * @@ -236,6 +233,7 @@ class rcmail_output_html extends rcmail_output return false; } + /** * Register a GUI object to the client script * @@ -248,6 +246,7 @@ class rcmail_output_html extends rcmail_output $this->add_script(self::JS_OBJECT_NAME.".gui_object('$obj', '$id');"); } + /** * Call a client method * @@ -263,6 +262,7 @@ class rcmail_output_html extends rcmail_output $this->js_commands[] = $cmd; } + /** * Add a localized label to the client environment */ @@ -277,6 +277,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Invoke display_message command * @@ -303,6 +304,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Delete all stored env variables and commands * @@ -325,6 +327,7 @@ class rcmail_output_html extends rcmail_output $this->body = ''; } + /** * Redirect to a certain url * @@ -340,6 +343,7 @@ class rcmail_output_html extends rcmail_output exit; } + /** * Send the request output to the client. * This will either parse a skin tempalte or send an AJAX response @@ -373,6 +377,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Process template and write to stdOut * @@ -408,6 +413,7 @@ class rcmail_output_html extends rcmail_output $this->_write($template, $this->config->get('skin_path')); } + /** * Parse a specific skin template and deliver to stdout (or return) * @@ -532,6 +538,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Return executable javascript code for all registered commands * @@ -563,6 +570,7 @@ class rcmail_output_html extends rcmail_output return $out; } + /** * Make URLs starting with a slash point to skin directory * @@ -582,6 +590,7 @@ class rcmail_output_html extends rcmail_output return $str; } + /** * Show error page and terminate script execution * @@ -616,6 +625,7 @@ class rcmail_output_html extends rcmail_output array($this, 'globals_callback'), $input); } + /** * Callback funtion for preg_replace_callback() in parse_with_globals() */ @@ -624,6 +634,7 @@ class rcmail_output_html extends rcmail_output return $GLOBALS[$matches[1]]; } + /** * Correct absolute paths in images and other tags * add timestamp to .js and .css filename @@ -635,6 +646,7 @@ class rcmail_output_html extends rcmail_output array($this, 'file_callback'), $output); } + /** * Callback function for preg_replace_callback in write() * @@ -643,7 +655,7 @@ class rcmail_output_html extends rcmail_output protected function file_callback($matches) { $file = $matches[3]; - $file = preg_replace('!^/this/!', '/', $file); + $file[0] = preg_replace('!^/this/!', '/', $file[0]); // correct absolute paths if ($file[0] == '/') { @@ -660,6 +672,7 @@ class rcmail_output_html extends rcmail_output return $matches[1] . '=' . $matches[2] . $file . $matches[4]; } + /** * Public wrapper to dipp into template parsing. * @@ -676,6 +689,7 @@ class rcmail_output_html extends rcmail_output return $input; } + /** * Parse for conditional tags * @@ -713,18 +727,21 @@ class rcmail_output_html extends rcmail_output return $input; } + /** * Determines if a given condition is met * + * @todo Get rid off eval() once I understand what this does. * @todo Extend this to allow real conditions, not just "set" * @param string Condition statement * @return boolean True if condition is met, False if not */ protected function check_condition($condition) { - return $this->eval_expression($condition); + return eval("return (".$this->parse_expression($condition).");"); } + /** * Inserts hidden field with CSRF-prevention-token into POST forms */ @@ -741,16 +758,16 @@ class rcmail_output_html extends rcmail_output return $out; } + /** - * Parse & evaluate a given expression and return its result. - * - * @param string Expression statement + * Parses expression and replaces variables * - * @return mixed Expression result + * @param string Expression statement + * @return string Expression value */ - protected function eval_expression ($expression) + protected function parse_expression($expression) { - $expression = preg_replace( + return preg_replace( array( '/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', @@ -762,31 +779,17 @@ class rcmail_output_html extends rcmail_output ), array( "\$_SESSION['\\1']", - "\$app->config->get('\\1',rcube_utils::get_boolean('\\3'))", - "\$env['\\1']", + "\$this->app->config->get('\\1',rcube_utils::get_boolean('\\3'))", + "\$this->env['\\1']", "rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)", "\$_COOKIE['\\1']", - "\$browser->{'\\1'}", + "\$this->browser->{'\\1'}", $this->template_name, ), - $expression - ); - - $fn = create_function('$app,$browser,$env', "return ($expression);"); - if (!$fn) { - rcube::raise_error(array( - 'code' => 505, - 'type' => 'php', - 'file' => __FILE__, - 'line' => __LINE__, - 'message' => "Expression parse error on: ($expression)"), true, false); - - return null; - } - - return $fn($this->app, $this->browser, $this->env); + $expression); } + /** * Search for special tags in input and replace them * with the appropriate content @@ -801,6 +804,7 @@ class rcmail_output_html extends rcmail_output return preg_replace_callback('/<roundcube:([-_a-z]+)\s+((?:[^>]|\\\\>)+)(?<!\\\\)>/Ui', array($this, 'xml_command'), $input); } + /** * Callback function for parsing an xml command tag * and turn it into real html content @@ -835,7 +839,7 @@ class rcmail_output_html extends rcmail_output // show a label case 'label': if ($attrib['expression']) - $attrib['name'] = $this->eval_expression($attrib['expression']); + $attrib['name'] = eval("return " . $this->parse_expression($attrib['expression']) .";"); if ($attrib['name'] || $attrib['command']) { // @FIXME: 'noshow' is useless, remove? @@ -967,7 +971,8 @@ class rcmail_output_html extends rcmail_output // return code for a specified eval expression case 'exp': - return html::quote($this->eval_expression($attrib['expression'])); + $value = $this->parse_expression($attrib['expression']); + return eval("return html::quote($value);"); // return variable case 'var': @@ -1004,13 +1009,12 @@ class rcmail_output_html extends rcmail_output } return html::quote($value); - - case 'form': - return $this->form_tag($attrib); + break; } return ''; } + /** * Include a specific file and return it's contents * @@ -1027,6 +1031,7 @@ class rcmail_output_html extends rcmail_output return $out; } + /** * Create and register a button * @@ -1175,13 +1180,10 @@ class rcmail_output_html extends rcmail_output $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content); } - if ($attrib['wrapper']) { - $out = html::tag($attrib['wrapper'], null, $out); - } - return $out; } + /** * Link an external script file * @@ -1212,6 +1214,7 @@ class rcmail_output_html extends rcmail_output $this->script_files[$position][] = $file; } + /** * Add inline javascript code * @@ -1228,6 +1231,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Link an external css file * @@ -1238,6 +1242,7 @@ class rcmail_output_html extends rcmail_output $this->css_files[] = $file; } + /** * Add HTML code to the page header * @@ -1248,6 +1253,7 @@ class rcmail_output_html extends rcmail_output $this->header .= "\n" . $str; } + /** * Add HTML code to the page footer * To be added right befor </body> @@ -1259,6 +1265,7 @@ class rcmail_output_html extends rcmail_output $this->footer .= "\n" . $str; } + /** * Process template and write to stdOut * @@ -1267,7 +1274,12 @@ class rcmail_output_html extends rcmail_output */ public function _write($templ = '', $base_path = '') { - $output = empty($templ) ? $this->default_template : trim($templ); + $output = trim($templ); + + if (empty($output)) { + $output = $this->default_template; + $is_empty = true; + } // set default page title if (empty($this->pagetitle)) { @@ -1358,8 +1370,8 @@ class rcmail_output_html extends rcmail_output } // add css files in head, before scripts, for speed up with parallel downloads - if (!empty($this->css_files) && - (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>'))) + if (!empty($this->css_files) && !$is_empty + && (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>'))) ) { $css = ''; foreach ($this->css_files as $file) { @@ -1383,6 +1395,7 @@ class rcmail_output_html extends rcmail_output } } + /** * Returns iframe object, registers some related env variables * @@ -1413,6 +1426,7 @@ class rcmail_output_html extends rcmail_output /* ************* common functions delivering gui objects ************** */ + /** * Create a form tag with the necessary hidden fields * @@ -1434,11 +1448,12 @@ class rcmail_output_html extends rcmail_output $attrib['noclose'] = true; return html::tag('form', - $attrib + array('action' => $this->app->comm_path, 'method' => "get"), + $attrib + array('action' => "./", 'method' => "get"), $hidden . $content, array('id','class','style','name','method','action','enctype','onsubmit')); } + /** * Build a form tag with a unique request token * @@ -1469,6 +1484,7 @@ class rcmail_output_html extends rcmail_output return $this->form_tag($attrib, $hidden->show() . $content); } + /** * GUI object 'username' * Showing IMAP username of the current session @@ -1500,6 +1516,7 @@ class rcmail_output_html extends rcmail_output return rcube_utils::idn_to_utf8($username); } + /** * GUI object 'loginform' * Returns code for the webmail login form @@ -1531,9 +1548,9 @@ class rcmail_output_html extends rcmail_output $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login')); $input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_')); $input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url)); - $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'required' => 'required') + $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser') + $attrib + $user_attrib); - $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'required' => 'required') + $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd') + $attrib + $pass_attrib); $input_host = null; @@ -1599,6 +1616,7 @@ class rcmail_output_html extends rcmail_output return $out; } + /** * GUI object 'preloader' * Loads javascript code for images preloading @@ -1621,6 +1639,7 @@ class rcmail_output_html extends rcmail_output }', 'docready'); } + /** * GUI object 'searchform' * Returns code for search function @@ -1659,6 +1678,7 @@ class rcmail_output_html extends rcmail_output return $out; } + /** * Builder for GUI object 'message' * @@ -1676,6 +1696,7 @@ class rcmail_output_html extends rcmail_output return html::div($attrib, ''); } + /** * GUI object 'charsetselector' * diff --git a/program/js/app.js b/program/js/app.js index 42c661144..efefd3a64 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1,7015 +1 @@ -/* - +-----------------------------------------------------------------------+ - | Roundcube Webmail Client Script | - | | - | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2013, The Roundcube Dev Team | - | Copyright (C) 2011-2013, Kolab Systems AG | - | | - | Licensed under the GNU General Public License version 3 or | - | any later version with exceptions for skins & plugins. | - | See the README file for a full license statement. | - | | - +-----------------------------------------------------------------------+ - | Authors: Thomas Bruederli <roundcube@gmail.com> | - | Aleksander 'A.L.E.C' Machniak <alec@alec.pl> | - | Charles McNulty <charles@charlesmcnulty.com> | - +-----------------------------------------------------------------------+ - | Requires: jquery.js, common.js, list.js | - +-----------------------------------------------------------------------+ -*/ - -function rcube_webmail() -{ - this.labels = {}; - this.buttons = {}; - this.buttons_sel = {}; - this.gui_objects = {}; - this.gui_containers = {}; - this.commands = {}; - this.command_handlers = {}; - this.onloads = []; - this.messages = {}; - this.group2expand = {}; - - // webmail client settings - this.dblclick_time = 500; - this.message_time = 4000; - this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); - - // environment defaults - this.env = { - request_timeout: 180, // seconds - draft_autosave: 0, // seconds - comm_path: './', - blankpage: 'program/resources/blank.gif', - recipients_separator: ',', - recipients_delimiter: ', ', - popup_width: 1150, - popup_width_small: 900 - }; - - // create protected reference to myself - this.ref = 'rcmail'; - var ref = this; - - // set jQuery ajax options - $.ajaxSetup({ - cache: false, - timeout: this.env.request_timeout * 1000, - error: function(request, status, err){ ref.http_error(request, status, err); }, - beforeSend: function(xmlhttp){ xmlhttp.setRequestHeader('X-Roundcube-Request', ref.env.request_token); } - }); - - // unload fix - $(window).bind('beforeunload', function() { rcmail.unload = true; }); - - // set environment variable(s) - this.set_env = function(p, value) - { - if (p != null && typeof p === 'object' && !value) - for (var n in p) - this.env[n] = p[n]; - else - this.env[p] = value; - }; - - // add a localized label to the client environment - this.add_label = function(p, value) - { - if (typeof p == 'string') - this.labels[p] = value; - else if (typeof p == 'object') - $.extend(this.labels, p); - }; - - // add a button to the button list - this.register_button = function(command, id, type, act, sel, over) - { - var button_prop = {id:id, type:type}; - - if (act) button_prop.act = act; - if (sel) button_prop.sel = sel; - if (over) button_prop.over = over; - - if (!this.buttons[command]) - this.buttons[command] = []; - - this.buttons[command].push(button_prop); - - if (this.loaded) - init_button(command, button_prop); - }; - - // register a specific gui object - this.gui_object = function(name, id) - { - this.gui_objects[name] = this.loaded ? rcube_find_object(id) : id; - }; - - // register a container object - this.gui_container = function(name, id) - { - this.gui_containers[name] = id; - }; - - // add a GUI element (html node) to a specified container - this.add_element = function(elm, container) - { - if (this.gui_containers[container] && this.gui_containers[container].jquery) - this.gui_containers[container].append(elm); - }; - - // register an external handler for a certain command - this.register_command = function(command, callback, enable) - { - this.command_handlers[command] = callback; - - if (enable) - this.enable_command(command, true); - }; - - // execute the given script on load - this.add_onload = function(f) - { - this.onloads.push(f); - }; - - // initialize webmail client - this.init = function() - { - var n, p = this; - this.task = this.env.task; - - // check browser - if (!bw.dom || !bw.xmlhttp_test() || (bw.mz && bw.vendver < 1.9)) { - this.goto_url('error', '_code=0x199'); - return; - } - - // find all registered gui containers - for (n in this.gui_containers) - this.gui_containers[n] = $('#'+this.gui_containers[n]); - - // find all registered gui objects - for (n in this.gui_objects) - this.gui_objects[n] = rcube_find_object(this.gui_objects[n]); - - // clickjacking protection - if (this.env.x_frame_options) { - try { - // bust frame if not allowed - if (this.env.x_frame_options == 'deny' && top.location.href != self.location.href) - top.location.href = self.location.href; - else if (top.location.hostname != self.location.hostname) - throw 1; - } catch (e) { - // possible clickjacking attack: disable all form elements - $('form').each(function(){ ref.lock_form(this, true); }); - this.display_message("Blocked: possible clickjacking attack!", 'error'); - return; - } - } - - // init registered buttons - this.init_buttons(); - - // tell parent window that this frame is loaded - if (this.is_framed()) { - parent.rcmail.set_busy(false, null, parent.rcmail.env.frame_lock); - parent.rcmail.env.frame_lock = null; - } - - // enable general commands - this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', - 'compose', 'undo', 'about', 'switch-task', 'menu-open', 'menu-save', true); - - if (this.env.permaurl) - this.enable_command('permaurl', 'extwin', true); - - switch (this.task) { - - case 'mail': - // enable mail commands - this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', 'import-messages', true); - - if (this.gui_objects.messagelist) { - this.message_list = new rcube_list_widget(this.gui_objects.messagelist, { - multiselect:true, multiexpand:true, draggable:true, keyboard:true, - column_movable:this.env.col_movable, dblclick_time:this.dblclick_time - }); - this.message_list.row_init = function(o){ p.init_message_row(o); }; - this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); }); - this.message_list.addEventListener('click', function(o){ p.msglist_click(o); }); - this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); }); - this.message_list.addEventListener('select', function(o){ p.msglist_select(o); }); - this.message_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); - this.message_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); - this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); }); - this.message_list.addEventListener('expandcollapse', function(e){ p.msglist_expand(e); }); - this.message_list.addEventListener('column_replace', function(e){ p.msglist_set_coltypes(e); }); - this.message_list.addEventListener('listupdate', function(e){ p.triggerEvent('listupdate', e); }); - - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; - - this.message_list.init(); - this.enable_command('toggle_status', 'toggle_flag', 'sort', true); - - // load messages - this.command('list'); - } - - if (this.gui_objects.qsearchbox) { - if (this.env.search_text != null) - this.gui_objects.qsearchbox.value = this.env.search_text; - $(this.gui_objects.qsearchbox).focusin(function() { rcmail.message_list && rcmail.message_list.blur(); }); - } - - this.set_button_titles(); - - this.env.message_commands = ['show', 'reply', 'reply-all', 'reply-list', - 'move', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', - 'print', 'load-attachment', 'download-attachment', 'show-headers', 'hide-headers', 'download', - 'forward', 'forward-inline', 'forward-attachment', 'change-format']; - - if (this.env.action == 'show' || this.env.action == 'preview') { - this.enable_command(this.env.message_commands, this.env.uid); - this.enable_command('reply-list', this.env.list_post); - - if (this.env.action == 'show') { - this.http_request('pagenav', {_uid: this.env.uid, _mbox: this.env.mailbox, _search: this.env.search_request}, - this.display_message('', 'loading')); - } - - if (this.env.blockedobjects) { - if (this.gui_objects.remoteobjectsmsg) - this.gui_objects.remoteobjectsmsg.style.display = 'block'; - this.enable_command('load-images', 'always-load', true); - } - - // make preview/message frame visible - if (this.env.action == 'preview' && this.is_framed()) { - this.enable_command('compose', 'add-contact', false); - parent.rcmail.show_contentframe(true); - } - } - else if (this.env.action == 'compose') { - this.env.address_group_stack = []; - this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'pushgroup', 'search', 'reset-search', 'extwin']; - - if (this.env.drafts_mailbox) - this.env.compose_commands.push('savedraft') - - this.enable_command(this.env.compose_commands, 'identities', true); - - // add more commands (not enabled) - $.merge(this.env.compose_commands, ['add-recipient', 'firstpage', 'previouspage', 'nextpage', 'lastpage']); - - if (this.env.spellcheck) { - this.env.spellcheck.spelling_state_observer = function(s) { ref.spellcheck_state(); }; - this.env.compose_commands.push('spellcheck') - this.enable_command('spellcheck', true); - } - - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - - // init message compose form - this.init_messageform(); - } - else if (this.env.action == 'get') - this.enable_command('download', 'print', true); - // show printing dialog - else if (this.env.action == 'print' && this.env.uid) { - if (bw.safari) - setTimeout('window.print()', 10); - else - window.print(); - } - - // get unread count for each mailbox - if (this.gui_objects.mailboxlist) { - this.env.unread_counts = {}; - this.gui_objects.folderlist = this.gui_objects.mailboxlist; - this.http_request('getunread'); - } - - // init address book widget - if (this.gui_objects.contactslist) { - this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, - { multiselect:true, draggable:false, keyboard:false }); - this.contact_list.addEventListener('select', function(o){ ref.compose_recipient_select(o); }); - this.contact_list.addEventListener('dblclick', function(o){ ref.compose_add_recipient('to'); }); - this.contact_list.init(); - } - - if (this.gui_objects.addressbookslist) { - this.gui_objects.folderlist = this.gui_objects.addressbookslist; - this.enable_command('list-adresses', true); - } - - // ask user to send MDN - if (this.env.mdn_request && this.env.uid) { - var postact = 'sendmdn', - postdata = {_uid: this.env.uid, _mbox: this.env.mailbox}; - if (!confirm(this.get_label('mdnrequest'))) { - postdata._flag = 'mdnsent'; - postact = 'mark'; - } - this.http_post(postact, postdata); - } - - // detect browser capabilities - if (!this.is_framed() && !this.env.extwin) - this.browser_capabilities_check(); - - break; - - case 'addressbook': - this.env.address_group_stack = []; - - if (this.gui_objects.folderlist) - this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups); - - this.enable_command('add', 'import', this.env.writable_source); - this.enable_command('list', 'listgroup', 'pushgroup', 'popgroup', 'listsearch', 'advanced-search', true); - - if (this.gui_objects.contactslist) { - this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, - {multiselect:true, draggable:this.gui_objects.folderlist?true:false, keyboard:true}); - this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); }; - this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); }); - this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); }); - this.contact_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); - this.contact_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); - this.contact_list.addEventListener('dragend', function(e){ p.drag_end(e); }); - this.contact_list.init(); - - if (this.env.cid) - this.contact_list.highlight_row(this.env.cid); - - this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - if (this.gui_objects.qsearchbox) - $(this.gui_objects.qsearchbox).focusin(function() { rcmail.contact_list.blur(); }); - - this.update_group_commands(); - this.command('list'); - } - - this.set_page_buttons(); - - if (this.env.cid) { - this.enable_command('show', 'edit', true); - // register handlers for group assignment via checkboxes - if (this.gui_objects.editform) { - $('input.groupmember').change(function() { - ref.group_member_change(this.checked ? 'add' : 'del', ref.env.cid, ref.env.source, this.value); - }); - } - } - - if (this.gui_objects.editform) { - this.enable_command('save', true); - if (this.env.action == 'add' || this.env.action == 'edit' || this.env.action == 'search') - this.init_contact_form(); - } - - if (this.gui_objects.qsearchbox) - this.enable_command('search', 'reset-search', true); - - break; - - case 'settings': - this.enable_command('preferences', 'identities', 'save', 'folders', true); - - if (this.env.action == 'identities') { - this.enable_command('add', this.env.identities_level < 2); - } - else if (this.env.action == 'edit-identity' || this.env.action == 'add-identity') { - this.enable_command('save', 'edit', 'toggle-editor', true); - this.enable_command('delete', this.env.identities_level < 2); - - if (this.env.action == 'add-identity') - $("input[type='text']").first().select(); - } - else if (this.env.action == 'folders') { - this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', true); - } - else if (this.env.action == 'edit-folder' && this.gui_objects.editform) { - this.enable_command('save', 'folder-size', true); - parent.rcmail.env.exists = this.env.messagecount; - parent.rcmail.enable_command('purge', this.env.messagecount); - $("input[type='text']").first().select(); - } - - if (this.gui_objects.identitieslist) { - this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false}); - this.identity_list.addEventListener('select', function(o){ p.identity_select(o); }); - this.identity_list.init(); - this.identity_list.focus(); - - if (this.env.iid) - this.identity_list.highlight_row(this.env.iid); - } - else if (this.gui_objects.sectionslist) { - this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:false}); - this.sections_list.addEventListener('select', function(o){ p.section_select(o); }); - this.sections_list.init(); - this.sections_list.focus(); - } - else if (this.gui_objects.subscriptionlist) - this.init_subscription_list(); - - break; - - case 'login': - var input_user = $('#rcmloginuser'); - input_user.bind('keyup', function(e){ return rcmail.login_user_keyup(e); }); - - if (input_user.val() == '') - input_user.focus(); - else - $('#rcmloginpwd').focus(); - - // detect client timezone - if (window.jstz && !bw.ie6) { - var timezone = jstz.determine(); - if (timezone.name()) - $('#rcmlogintz').val(timezone.name()); - } - else { - $('#rcmlogintz').val(new Date().getStdTimezoneOffset() / -60); - } - - // display 'loading' message on form submit, lock submit button - $('form').submit(function () { - $('input[type=submit]', this).prop('disabled', true); - rcmail.clear_messages(); - rcmail.display_message('', 'loading'); - }); - - this.enable_command('login', true); - break; - } - - // unset contentframe variable if preview_pane is enabled - if (this.env.contentframe && !$('#' + this.env.contentframe).is(':visible')) - this.env.contentframe = null; - - // prevent from form submit with Enter key in file input fields - if (bw.ie) - $('input[type=file]').keydown(function(e) { if (e.keyCode == '13') e.preventDefault(); }); - - // flag object as complete - this.loaded = true; - - // show message - if (this.pending_message) - this.display_message(this.pending_message[0], this.pending_message[1], this.pending_message[2]); - - // map implicit containers - if (this.gui_objects.folderlist) { - this.gui_containers.foldertray = $(this.gui_objects.folderlist); - - // init treelist widget - if (window.rcube_treelist_widget) { - this.treelist = new rcube_treelist_widget(this.gui_objects.folderlist, { - id_prefix: 'rcmli', - id_encode: this.html_identifier_encode, - id_decode: this.html_identifier_decode, - check_droptarget: function(node){ return !node.virtual && ref.check_droptarget(node.id) } - }); - this.treelist.addEventListener('collapse', function(node){ ref.folder_collapsed(node) }); - this.treelist.addEventListener('expand', function(node){ ref.folder_collapsed(node) }); - this.treelist.addEventListener('select', function(node){ ref.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }) }); - } - } - - // activate html5 file drop feature (if browser supports it and if configured) - if (this.gui_objects.filedrop && this.env.filedrop && ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData)) { - $(document.body).bind('dragover dragleave drop', function(e){ return ref.document_drag_hover(e, e.type == 'dragover'); }); - $(this.gui_objects.filedrop).addClass('droptarget') - .bind('dragover dragleave', function(e){ return ref.file_drag_hover(e, e.type == 'dragover'); }) - .get(0).addEventListener('drop', function(e){ return ref.file_dropped(e); }, false); - } - - // trigger init event hook - this.triggerEvent('init', { task:this.task, action:this.env.action }); - - // execute all foreign onload scripts - // @deprecated - for (var i in this.onloads) { - if (typeof this.onloads[i] === 'string') - eval(this.onloads[i]); - else if (typeof this.onloads[i] === 'function') - this.onloads[i](); - } - - // start keep-alive and refresh intervals - this.start_refresh(); - this.start_keepalive(); - }; - - this.log = function(msg) - { - if (window.console && console.log) - console.log(msg); - }; - - /*********************************************************/ - /********* client command interface *********/ - /*********************************************************/ - - // execute a specific command on the web client - this.command = function(command, props, obj, event) - { - var ret, uid, cid, url, flag; - - if (obj && obj.blur) - obj.blur(); - - if (this.busy) - return false; - - // let the browser handle this click (shift/ctrl usually opens the link in a new window/tab) - if ((obj && obj.href && String(obj.href).indexOf('#') < 0) && rcube_event.get_modifier(event)) { - return true; - } - - // command not supported or allowed - if (!this.commands[command]) { - // pass command to parent window - if (this.is_framed()) - parent.rcmail.command(command, props); - - return false; - } - - // check input before leaving compose step - if (this.task == 'mail' && this.env.action == 'compose' && $.inArray(command, this.env.compose_commands)<0) { - if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning'))) - return false; - } - - // process external commands - if (typeof this.command_handlers[command] === 'function') { - ret = this.command_handlers[command](props, obj); - return ret !== undefined ? ret : (obj ? false : true); - } - else if (typeof this.command_handlers[command] === 'string') { - ret = window[this.command_handlers[command]](props, obj); - return ret !== undefined ? ret : (obj ? false : true); - } - - // trigger plugin hooks - this.triggerEvent('actionbefore', {props:props, action:command}); - ret = this.triggerEvent('before'+command, props); - if (ret !== undefined) { - // abort if one of the handlers returned false - if (ret === false) - return false; - else - props = ret; - } - - ret = undefined; - - // process internal command - switch (command) { - - case 'login': - if (this.gui_objects.loginform) - this.gui_objects.loginform.submit(); - break; - - // commands to switch task - case 'mail': - case 'addressbook': - case 'settings': - case 'logout': - this.switch_task(command); - break; - - case 'about': - this.redirect('?_task=settings&_action=about', false); - break; - - case 'permaurl': - if (obj && obj.href && obj.target) - return true; - else if (this.env.permaurl) - parent.location.href = this.env.permaurl; - break; - - case 'extwin': - if (this.env.action == 'compose') { - var form = this.gui_objects.messageform, - win = this.open_window(''); - - $("input[name='_action']", form).val('compose'); - form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 }); - form.target = win.name; - form.submit(); - } - else { - this.open_window(this.env.permaurl, true); - } - break; - - case 'change-format': - url = this.env.permaurl + '&_format=' + props; - - if (this.env.action == 'preview') - url = url.replace(/_action=show/, '_action=preview') + '&_framed=1'; - if (this.env.extwin) - url += '&_extwin=1'; - - location.href = url; - break; - - case 'menu-open': - if (props && props.menu == 'attachmentmenu') { - var mimetype = this.env.attachments[props.id]; - this.enable_command('open-attachment', mimetype && this.env.mimetypes && $.inArray(mimetype, this.env.mimetypes) >= 0); - } - - case 'menu-save': - this.triggerEvent(command, {props:props}); - return false; - - case 'open': - if (uid = this.get_single_uid()) { - obj.href = this.url('show', {_mbox: this.env.mailbox, _uid: uid}); - return true; - } - break; - - case 'close': - if (this.env.extwin) - window.close(); - break; - - case 'list': - if (props && props != '') - this.reset_qsearch(); - if (this.env.action == 'compose' && this.env.extwin) - window.close(); - else if (this.task == 'mail') { - this.list_mailbox(props); - this.set_button_titles(); - } - else if (this.task == 'addressbook') - this.list_contacts(props); - break; - - case 'sort': - var sort_order = this.env.sort_order, - sort_col = !this.env.disabled_sort_col ? props : this.env.sort_col; - - if (!this.env.disabled_sort_order) - sort_order = this.env.sort_col == sort_col && sort_order == 'ASC' ? 'DESC' : 'ASC'; - - // set table header and update env - this.set_list_sorting(sort_col, sort_order); - - // reload message list - this.list_mailbox('', '', sort_col+'_'+sort_order); - break; - - case 'nextpage': - this.list_page('next'); - break; - - case 'lastpage': - this.list_page('last'); - break; - - case 'previouspage': - this.list_page('prev'); - break; - - case 'firstpage': - this.list_page('first'); - break; - - case 'expunge': - if (this.env.exists) - this.expunge_mailbox(this.env.mailbox); - break; - - case 'purge': - case 'empty-mailbox': - if (this.env.exists) - this.purge_mailbox(this.env.mailbox); - break; - - // common commands used in multiple tasks - case 'show': - if (this.task == 'mail') { - uid = this.get_single_uid(); - if (uid && (!this.env.uid || uid != this.env.uid)) { - if (this.env.mailbox == this.env.drafts_mailbox) - this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox }); - else - this.show_message(uid); - } - } - else if (this.task == 'addressbook') { - cid = props ? props : this.get_single_cid(); - if (cid && !(this.env.action == 'show' && cid == this.env.cid)) - this.load_contact(cid, 'show'); - } - break; - - case 'add': - if (this.task == 'addressbook') - this.load_contact(0, 'add'); - else if (this.task == 'settings') { - this.identity_list.clear_selection(); - this.load_identity(0, 'add-identity'); - } - break; - - case 'edit': - if (this.task == 'addressbook' && (cid = this.get_single_cid())) - this.load_contact(cid, 'edit'); - else if (this.task == 'settings' && props) - this.load_identity(props, 'edit-identity'); - else if (this.task == 'mail' && (cid = this.get_single_uid())) { - url = { _mbox: this.env.mailbox }; - url[this.env.mailbox == this.env.drafts_mailbox && props != 'new' ? '_draft_uid' : '_uid'] = cid; - this.open_compose_step(url); - } - break; - - case 'save': - var input, form = this.gui_objects.editform; - if (form) { - // adv. search - if (this.env.action == 'search') { - } - // user prefs - else if ((input = $("input[name='_pagesize']", form)) && input.length && isNaN(parseInt(input.val()))) { - alert(this.get_label('nopagesizewarning')); - input.focus(); - break; - } - // contacts/identities - else { - // reload form - if (props == 'reload') { - form.action += '?_reload=1'; - } - else if (this.task == 'settings' && (this.env.identities_level % 2) == 0 && - (input = $("input[name='_email']", form)) && input.length && !rcube_check_email(input.val()) - ) { - alert(this.get_label('noemailwarning')); - input.focus(); - break; - } - - // clear empty input fields - $('input.placeholder').each(function(){ if (this.value == this._placeholder) this.value = ''; }); - } - - // add selected source (on the list) - if (parent.rcmail && parent.rcmail.env.source) - form.action = this.add_url(form.action, '_orig_source', parent.rcmail.env.source); - - form.submit(); - } - break; - - case 'delete': - // mail task - if (this.task == 'mail') - this.delete_messages(event); - // addressbook task - else if (this.task == 'addressbook') - this.delete_contacts(); - // user settings task - else if (this.task == 'settings') - this.delete_identity(); - break; - - // mail task commands - case 'move': - case 'moveto': // deprecated - if (this.task == 'mail') - this.move_messages(props); - else if (this.task == 'addressbook') - this.move_contacts(props); - break; - - case 'copy': - if (this.task == 'mail') - this.copy_messages(props); - else if (this.task == 'addressbook') - this.copy_contacts(props); - break; - - case 'mark': - if (props) - this.mark_message(props); - break; - - case 'toggle_status': - if (props && !props._row) - break; - - flag = 'read'; - - if (props._row.uid) { - uid = props._row.uid; - - // toggle read/unread - if (this.message_list.rows[uid].deleted) - flag = 'undelete'; - else if (!this.message_list.rows[uid].unread) - flag = 'unread'; - } - - this.mark_message(flag, uid); - break; - - case 'toggle_flag': - if (props && !props._row) - break; - - flag = 'flagged'; - - if (props._row.uid) { - uid = props._row.uid; - // toggle flagged/unflagged - if (this.message_list.rows[uid].flagged) - flag = 'unflagged'; - } - this.mark_message(flag, uid); - break; - - case 'always-load': - if (this.env.uid && this.env.sender) { - this.add_contact(this.env.sender); - setTimeout(function(){ ref.command('load-images'); }, 300); - break; - } - - case 'load-images': - if (this.env.uid) - this.show_message(this.env.uid, true, this.env.action=='preview'); - break; - - case 'load-attachment': - case 'open-attachment': - case 'download-attachment': - var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props, - mimetype = this.env.attachments[props]; - - // open attachment in frame if it's of a supported mimetype - if (command != 'download-attachment' && mimetype && this.env.mimetypes && $.inArray(mimetype, this.env.mimetypes) >= 0) { - if (this.open_window(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1')) - break; - } - - this.goto_url('get', qstring+'&_download=1', false); - break; - - case 'select-all': - this.select_all_mode = props ? false : true; - this.dummy_select = true; // prevent msg opening if there's only one msg on the list - if (props == 'invert') - this.message_list.invert_selection(); - else - this.message_list.select_all(props == 'page' ? '' : props); - this.dummy_select = null; - break; - - case 'select-none': - this.select_all_mode = false; - this.message_list.clear_selection(); - break; - - case 'expand-all': - this.env.autoexpand_threads = 1; - this.message_list.expand_all(); - break; - - case 'expand-unread': - this.env.autoexpand_threads = 2; - this.message_list.collapse_all(); - this.expand_unread(); - break; - - case 'collapse-all': - this.env.autoexpand_threads = 0; - this.message_list.collapse_all(); - break; - - case 'nextmessage': - if (this.env.next_uid) - this.show_message(this.env.next_uid, false, this.env.action == 'preview'); - break; - - case 'lastmessage': - if (this.env.last_uid) - this.show_message(this.env.last_uid); - break; - - case 'previousmessage': - if (this.env.prev_uid) - this.show_message(this.env.prev_uid, false, this.env.action == 'preview'); - break; - - case 'firstmessage': - if (this.env.first_uid) - this.show_message(this.env.first_uid); - break; - - case 'compose': - url = {}; - - if (this.task == 'mail') { - url._mbox = this.env.mailbox; - if (props) - url._to = props; - // also send search request so we can go back to search result after message is sent - if (this.env.search_request) - url._search = this.env.search_request; - } - // modify url if we're in addressbook - else if (this.task == 'addressbook') { - // switch to mail compose step directly - if (props && props.indexOf('@') > 0) { - url._to = props; - } - else { - var a_cids = []; - // use contact id passed as command parameter - if (props) - a_cids.push(props); - // get selected contacts - else if (this.contact_list) - a_cids = this.contact_list.get_selection(); - - if (a_cids.length) - this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true); - else if (this.env.group) - this.http_post('mailto', { _gid: this.env.group, _source: this.env.source }, true); - - break; - } - } - else if (props) - url._to = props; - - this.open_compose_step(url); - break; - - case 'spellcheck': - if (this.spellcheck_state()) { - this.stop_spellchecking(); - } - else { - if (window.tinyMCE && tinyMCE.get(this.env.composebody)) { - tinyMCE.execCommand('mceSpellCheck', true); - } - else if (this.env.spellcheck && this.env.spellcheck.spellCheck) { - this.env.spellcheck.spellCheck(); - } - } - this.spellcheck_state(); - break; - - case 'savedraft': - // Reset the auto-save timer - clearTimeout(this.save_timer); - - // compose form did not change (and draft wasn't saved already) - if (this.env.draft_id && this.cmp_hash == this.compose_field_hash()) { - this.auto_save_start(); - break; - } - - this.submit_messageform(true); - break; - - case 'send': - if (!props.nocheck && !this.check_compose_input(command)) - break; - - // Reset the auto-save timer - clearTimeout(this.save_timer); - - this.submit_messageform(); - break; - - case 'send-attachment': - // Reset the auto-save timer - clearTimeout(this.save_timer); - - this.upload_file(props || this.gui_objects.uploadform, 'upload'); - break; - - case 'insert-sig': - this.change_identity($("[name='_from']")[0], true); - break; - - case 'list-adresses': - this.list_contacts(props); - this.enable_command('add-recipient', false); - break; - - case 'add-recipient': - this.compose_add_recipient(props); - break; - - case 'reply-all': - case 'reply-list': - case 'reply': - if (uid = this.get_single_uid()) { - url = {_reply_uid: uid, _mbox: this.env.mailbox}; - if (command == 'reply-all') - // do reply-list, when list is detected and popup menu wasn't used - url._all = (!props && this.commands['reply-list'] ? 'list' : 'all'); - else if (command == 'reply-list') - url._all = 'list'; - - this.open_compose_step(url); - } - break; - - case 'forward-attachment': - case 'forward-inline': - case 'forward': - var uids = this.env.uid ? [this.env.uid] : (this.message_list ? this.message_list.get_selection() : []); - if (uids.length) { - url = { _forward_uid: this.uids_to_list(uids), _mbox: this.env.mailbox }; - if (command == 'forward-attachment' || (!props && this.env.forward_attachment) || uids.length > 1) - url._attachment = 1; - this.open_compose_step(url); - } - break; - - case 'print': - if (this.env.action == 'get') { - this.gui_objects.messagepartframe.contentWindow.print(); - } - else if (uid = this.get_single_uid()) { - ref.printwin = this.open_window(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''), true, true); - if (this.printwin) { - if (this.env.action != 'show') - this.mark_message('read', uid); - } - } - break; - - case 'viewsource': - if (uid = this.get_single_uid()) - this.open_window(this.env.comm_path+'&_action=viewsource&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true, true); - break; - - case 'download': - if (this.env.action == 'get') { - location.href = location.href.replace(/_frame=/, '_download='); - } - else if (uid = this.get_single_uid()) - this.goto_url('viewsource', { _uid: uid, _mbox: this.env.mailbox, _save: 1 }); - break; - - // quicksearch - case 'search': - if (!props && this.gui_objects.qsearchbox) - props = this.gui_objects.qsearchbox.value; - if (props) { - this.qsearch(props); - break; - } - - // reset quicksearch - case 'reset-search': - var n, s = this.env.search_request || this.env.qsearch; - - this.reset_qsearch(); - this.select_all_mode = false; - - if (s && this.env.action == 'compose') { - if (this.contact_list) - this.list_contacts_clear(); - } - else if (s && this.env.mailbox) { - this.list_mailbox(this.env.mailbox, 1); - } - else if (s && this.task == 'addressbook') { - if (this.env.source == '') { - for (n in this.env.address_sources) break; - this.env.source = n; - this.env.group = ''; - } - this.list_contacts(this.env.source, this.env.group, 1); - } - break; - - case 'pushgroup': - // add group ID to stack - this.env.address_group_stack.push(props.id); - if (obj && event) - rcube_event.cancel(event); - - case 'listgroup': - this.reset_qsearch(); - this.list_contacts(props.source, props.id); - break; - - case 'popgroup': - if (this.env.address_group_stack.length > 1) { - this.env.address_group_stack.pop(); - this.reset_qsearch(); - this.list_contacts(props.source, this.env.address_group_stack[this.env.address_group_stack.length-1]); - } - break; - - case 'import-messages': - var form = props || this.gui_objects.importform; - $('input[name="_unlock"]', form).val(this.set_busy(true, 'importwait')); - this.upload_file(form, 'import'); - break; - - case 'import': - if (this.env.action == 'import' && this.gui_objects.importform) { - var file = document.getElementById('rcmimportfile'); - if (file && !file.value) { - alert(this.get_label('selectimportfile')); - break; - } - this.gui_objects.importform.submit(); - this.set_busy(true, 'importwait'); - this.lock_form(this.gui_objects.importform, true); - } - else - this.goto_url('import', (this.env.source ? '_target='+urlencode(this.env.source)+'&' : '')); - break; - - case 'export': - if (this.contact_list.rowcount > 0) { - this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }); - } - break; - - case 'export-selected': - if (this.contact_list.rowcount > 0) { - this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _cid: this.contact_list.get_selection().join(',') }); - } - break; - - case 'upload-photo': - this.upload_contact_photo(props || this.gui_objects.uploadform); - break; - - case 'delete-photo': - this.replace_contact_photo('-del-'); - break; - - // user settings commands - case 'preferences': - case 'identities': - case 'folders': - this.goto_url('settings/' + command); - break; - - case 'undo': - this.http_request('undo', '', this.display_message('', 'loading')); - break; - - // unified command call (command name == function name) - default: - var func = command.replace(/-/g, '_'); - if (this[func] && typeof this[func] === 'function') { - ret = this[func](props, obj); - } - break; - } - - if (this.triggerEvent('after'+command, props) === false) - ret = false; - this.triggerEvent('actionafter', {props:props, action:command}); - - return ret === false ? false : obj ? false : true; - }; - - // set command(s) enabled or disabled - this.enable_command = function() - { - var i, n, args = Array.prototype.slice.call(arguments), - enable = args.pop(), cmd; - - for (n=0; n<args.length; n++) { - cmd = args[n]; - // argument of type array - if (typeof cmd === 'string') { - this.commands[cmd] = enable; - this.set_button(cmd, (enable ? 'act' : 'pas')); - this.triggerEvent('enable-command', {command: cmd, status: enable}); - } - // push array elements into commands array - else { - for (i in cmd) - args.push(cmd[i]); - } - } - }; - - // lock/unlock interface - this.set_busy = function(a, message, id) - { - if (a && message) { - var msg = this.get_label(message); - if (msg == message) - msg = 'Loading...'; - - id = this.display_message(msg, 'loading'); - } - else if (!a && id) { - this.hide_message(id); - } - - this.busy = a; - //document.body.style.cursor = a ? 'wait' : 'default'; - - if (this.gui_objects.editform) - this.lock_form(this.gui_objects.editform, a); - - return id; - }; - - // return a localized string - this.get_label = function(name, domain) - { - if (domain && this.labels[domain+'.'+name]) - return this.labels[domain+'.'+name]; - else if (this.labels[name]) - return this.labels[name]; - else - return name; - }; - - // alias for convenience reasons - this.gettext = this.get_label; - - // switch to another application task - this.switch_task = function(task) - { - if (this.task===task && task!='mail') - return; - - var url = this.get_task_url(task); - if (task=='mail') - url += '&_mbox=INBOX'; - - this.redirect(url); - }; - - this.get_task_url = function(task, url) - { - if (!url) - url = this.env.comm_path; - - return url.replace(/_task=[a-z0-9_-]+/i, '_task='+task); - }; - - this.reload = function(delay) - { - if (this.is_framed()) - parent.rcmail.reload(delay); - else if (delay) - setTimeout(function(){ rcmail.reload(); }, delay); - else if (window.location) - location.href = this.env.comm_path + (this.env.action ? '&_action='+this.env.action : ''); - }; - - // Add variable to GET string, replace old value if exists - this.add_url = function(url, name, value) - { - value = urlencode(value); - - if (/(\?.*)$/.test(url)) { - var urldata = RegExp.$1, - datax = RegExp('((\\?|&)'+RegExp.escape(name)+'=[^&]*)'); - - if (datax.test(urldata)) { - urldata = urldata.replace(datax, RegExp.$2 + name + '=' + value); - } - else - urldata += '&' + name + '=' + value - - return url.replace(/(\?.*)$/, urldata); - } - - return url + '?' + name + '=' + value; - }; - - this.is_framed = function() - { - return (this.env.framed && parent.rcmail && parent.rcmail != this && parent.rcmail.command); - }; - - this.save_pref = function(prop) - { - var request = {'_name': prop.name, '_value': prop.value}; - - if (prop.session) - request['_session'] = prop.session; - if (prop.env) - this.env[prop.env] = prop.value; - - this.http_post('save-pref', request); - }; - - this.html_identifier = function(str, encode) - { - return encode ? this.html_identifier_encode(str) : String(str).replace(this.identifier_expr, '_'); - }; - - this.html_identifier_encode = function(str) - { - return Base64.encode(String(str)).replace(/=+$/, '').replace(/\+/g, '-').replace(/\//g, '_'); - }; - - this.html_identifier_decode = function(str) - { - str = String(str).replace(/-/g, '+').replace(/_/g, '/'); - - while (str.length % 4) str += '='; - - return Base64.decode(str); - }; - - - /*********************************************************/ - /********* event handling methods *********/ - /*********************************************************/ - - this.drag_menu = function(e, target) - { - var modkey = rcube_event.get_modifier(e), - menu = this.gui_objects.dragmenu; - - if (menu && modkey == SHIFT_KEY && this.commands['copy']) { - var pos = rcube_event.get_mouse_pos(e); - this.env.drag_target = target; - $(menu).css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); - return true; - } - - return false; - }; - - this.drag_menu_action = function(action) - { - var menu = this.gui_objects.dragmenu; - if (menu) { - $(menu).hide(); - } - this.command(action, this.env.drag_target); - this.env.drag_target = null; - }; - - this.drag_start = function(list) - { - var model = this.task == 'mail' ? this.env.mailboxes : this.env.contactfolders; - - this.drag_active = true; - - if (this.preview_timer) - clearTimeout(this.preview_timer); - if (this.preview_read_timer) - clearTimeout(this.preview_read_timer); - - // prepare treelist widget for dragging interactions - if (this.treelist) - this.treelist.drag_start(); - }; - - this.drag_end = function(e) - { - this.drag_active = false; - this.env.last_folder_target = null; - - if (this.treelist) - this.treelist.drag_end(); - }; - - this.drag_move = function(e) - { - if (this.gui_objects.folderlist) { - var drag_target, oldclass, - layerclass = 'draglayernormal', - mouse = rcube_event.get_mouse_pos(e); - - if (this.contact_list && this.contact_list.draglayer) - oldclass = this.contact_list.draglayer.attr('class'); - - // mouse intersects a valid drop target on the treelist - if (this.treelist && (drag_target = this.treelist.intersects(mouse, true))) { - this.env.last_folder_target = drag_target; - layerclass = 'draglayer' + (this.check_droptarget(drag_target) > 1 ? 'copy' : 'normal'); - } - else { - // Clear target, otherwise drag end will trigger move into last valid droptarget - this.env.last_folder_target = null; - } - - if (layerclass != oldclass && this.contact_list && this.contact_list.draglayer) - this.contact_list.draglayer.attr('class', layerclass); - } - }; - - this.collapse_folder = function(name) - { - if (this.treelist) - this.treelist.toggle(name); - }; - - this.folder_collapsed = function(node) - { - var prefname = this.env.task == 'addressbook' ? 'collapsed_abooks' : 'collapsed_folders'; - - if (node.collapsed) { - this.env[prefname] = this.env[prefname] + '&'+urlencode(node.id)+'&'; - - // select the folder if one of its childs is currently selected - // don't select if it's virtual (#1488346) - if (this.env.mailbox && this.env.mailbox.indexOf(name + this.env.delimiter) == 0 && !node.virtual) - this.command('list', name); - } - else { - var reg = new RegExp('&'+urlencode(node.id)+'&'); - this.env[prefname] = this.env[prefname].replace(reg, ''); - } - - if (!this.drag_active) { - this.command('save-pref', { name: prefname, value: this.env[prefname] }); - - if (this.env.unread_counts) - this.set_unread_count_display(node.id, false); - } - }; - - this.doc_mouse_up = function(e) - { - var model, list, id; - - // ignore event if jquery UI dialog is open - if ($(rcube_event.get_target(e)).closest('.ui-dialog, .ui-widget-overlay').length) - return; - - if (list = this.message_list) - model = this.env.mailboxes; - else if (list = this.contact_list) - model = this.env.contactfolders; - else if (this.ksearch_value) - this.ksearch_blur(); - - if (list && !rcube_mouse_is_over(e, list.list.parentNode)) - list.blur(); - - // handle mouse release when dragging - if (this.drag_active && model && this.env.last_folder_target) { - var target = model[this.env.last_folder_target]; - - this.env.last_folder_target = null; - list.draglayer.hide(); - this.drag_end(e); - - if (this.contact_list) { - if (!this.contacts_drag_menu(e, target)) - this.command('move', target); - } - else if (!this.drag_menu(e, target)) - this.command('move', target); - } - - // reset 'pressed' buttons - if (this.buttons_sel) { - for (id in this.buttons_sel) - if (typeof id !== 'function') - this.button_out(this.buttons_sel[id], id); - this.buttons_sel = {}; - } - }; - - this.click_on_list = function(e) - { - if (this.gui_objects.qsearchbox) - this.gui_objects.qsearchbox.blur(); - - if (this.message_list) - this.message_list.focus(); - else if (this.contact_list) - this.contact_list.focus(); - - return true; - }; - - this.msglist_select = function(list) - { - if (this.preview_timer) - clearTimeout(this.preview_timer); - if (this.preview_read_timer) - clearTimeout(this.preview_read_timer); - - var selected = list.get_single_selection(); - - this.enable_command(this.env.message_commands, selected != null); - if (selected) { - // Hide certain command buttons when Drafts folder is selected - if (this.env.mailbox == this.env.drafts_mailbox) - this.enable_command('reply', 'reply-all', 'reply-list', 'forward', 'forward-attachment', 'forward-inline', false); - // Disable reply-list when List-Post header is not set - else { - var msg = this.env.messages[selected]; - if (!msg.ml) - this.enable_command('reply-list', false); - } - } - // Multi-message commands - this.enable_command('delete', 'move', 'copy', 'mark', 'forward', 'forward-attachment', list.selection.length > 0); - - // reset all-pages-selection - if (selected || (list.selection.length && list.selection.length != list.rowcount)) - this.select_all_mode = false; - - // start timer for message preview (wait for double click) - if (selected && this.env.contentframe && !list.multi_selecting && !this.dummy_select) - this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time); - else if (this.env.contentframe) - this.show_contentframe(false); - }; - - // This allow as to re-select selected message and display it in preview frame - this.msglist_click = function(list) - { - if (list.multi_selecting || !this.env.contentframe) - return; - - if (list.get_single_selection()) - return; - - var win = this.get_frame_window(this.env.contentframe); - - if (win && win.location.href.indexOf(this.env.blankpage) >= 0) { - if (this.preview_timer) - clearTimeout(this.preview_timer); - if (this.preview_read_timer) - clearTimeout(this.preview_read_timer); - - this.preview_timer = setTimeout(function() { ref.msglist_get_preview(); }, this.dblclick_time); - } - }; - - this.msglist_dbl_click = function(list) - { - if (this.preview_timer) - clearTimeout(this.preview_timer); - if (this.preview_read_timer) - clearTimeout(this.preview_read_timer); - - var uid = list.get_single_selection(); - - if (uid && this.env.mailbox == this.env.drafts_mailbox) - this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox }); - else if (uid) - this.show_message(uid, false, false); - }; - - this.msglist_keypress = function(list) - { - if (list.modkey == CONTROL_KEY) - return; - - if (list.key_pressed == list.ENTER_KEY) - this.command('show'); - else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) - this.command('delete'); - else if (list.key_pressed == 33) - this.command('previouspage'); - else if (list.key_pressed == 34) - this.command('nextpage'); - }; - - this.msglist_get_preview = function() - { - var uid = this.get_single_uid(); - if (uid && this.env.contentframe && !this.drag_active) - this.show_message(uid, false, true); - else if (this.env.contentframe) - this.show_contentframe(false); - }; - - this.msglist_expand = function(row) - { - if (this.env.messages[row.uid]) - this.env.messages[row.uid].expanded = row.expanded; - $(row.obj)[row.expanded?'addClass':'removeClass']('expanded'); - }; - - this.msglist_set_coltypes = function(list) - { - var i, found, name, cols = list.thead.rows[0].cells; - - this.env.coltypes = []; - - for (i=0; i<cols.length; i++) - if (cols[i].id && cols[i].id.match(/^rcm/)) { - name = cols[i].id.replace(/^rcm/, ''); - this.env.coltypes.push(name); - } - - if ((found = $.inArray('flag', this.env.coltypes)) >= 0) - this.env.flagged_col = found; - - if ((found = $.inArray('subject', this.env.coltypes)) >= 0) - this.env.subject_col = found; - - this.command('save-pref', { name: 'list_cols', value: this.env.coltypes, session: 'list_attrib/columns' }); - }; - - this.check_droptarget = function(id) - { - switch (this.task) { - case 'mail': - return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual) ? 1 : 0; - - case 'settings': - return id != this.env.mailbox ? 1 : 0; - - case 'addressbook': - var target; - if (id != this.env.source && (target = this.env.contactfolders[id])) { - // droptarget is a group - if (target.type == 'group') { - if (target.id != this.env.group && !this.env.contactfolders[target.source].readonly) { - var is_other = this.env.selection_sources.length > 1 || $.inArray(target.source, this.env.selection_sources) == -1; - return !is_other || this.commands.move ? 1 : 2; - } - } - // droptarget is a (writable) addressbook and it's not the source - else if (!target.readonly && (this.env.selection_sources.length > 1 || $.inArray(id, this.env.selection_sources) == -1)) { - return this.commands.move ? 1 : 2; - } - } - } - - return 0; - }; - - // open popup window - this.open_window = function(url, small, toolbar) - { - var wname = 'rcmextwin' + new Date().getTime(); - - url += (url.match(/\?/) ? '&' : '?') + '_extwin=1'; - - if (this.env.standard_windows) - extwin = window.open(url, wname); - else { - var win = this.is_framed() ? parent.window : window, - page = $(win), - page_width = page.width(), - page_height = bw.mz ? $('body', win).height() : page.height(), - w = Math.min(small ? this.env.popup_width_small : this.env.popup_width, page_width), - h = page_height, // always use same height - l = (win.screenLeft || win.screenX) + 20, - t = (win.screenTop || win.screenY) + 20, - extwin = window.open(url, wname, - 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,location=no,scrollbars=yes' - +(toolbar ? ',toolbar=yes,menubar=yes,status=yes' : ',toolbar=no,menubar=no,status=no')); - } - - // write loading... message to empty windows - if (!url && extwin.document) { - extwin.document.write('<html><body>' + this.get_label('loading') + '</body></html>'); - } - - // focus window, delayed to bring to front - window.setTimeout(function() { extwin.focus(); }, 10); - - return extwin; - }; - - - /*********************************************************/ - /********* (message) list functionality *********/ - /*********************************************************/ - - this.init_message_row = function(row) - { - var expando, self = this, uid = row.uid, - status_icon = (this.env.status_col != null ? 'status' : 'msg') + 'icn' + row.uid; - - if (uid && this.env.messages[uid]) - $.extend(row, this.env.messages[uid]); - - // set eventhandler to status icon - if (row.icon = document.getElementById(status_icon)) { - row.icon._row = row.obj; - row.icon.onmousedown = function(e) { self.command('toggle_status', this); rcube_event.cancel(e); }; - } - - // save message icon position too - if (this.env.status_col != null) - row.msgicon = document.getElementById('msgicn'+row.uid); - else - row.msgicon = row.icon; - - // set eventhandler to flag icon, if icon found - if (this.env.flagged_col != null && (row.flagicon = document.getElementById('flagicn'+row.uid))) { - row.flagicon._row = row.obj; - row.flagicon.onmousedown = function(e) { self.command('toggle_flag', this); rcube_event.cancel(e); }; - } - - if (!row.depth && row.has_children && (expando = document.getElementById('rcmexpando'+row.uid))) { - row.expando = expando; - expando.onmousedown = function(e) { return self.expand_message_row(e, uid); }; - if (bw.touch) { - expando.addEventListener('touchend', function(e) { - if (e.changedTouches.length == 1) { - self.expand_message_row(e, uid); - return rcube_event.cancel(e); - } - }, false); - } - } - - this.triggerEvent('insertrow', { uid:uid, row:row }); - }; - - // create a table row in the message list - this.add_message_row = function(uid, cols, flags, attop) - { - if (!this.gui_objects.messagelist || !this.message_list) - return false; - - // Prevent from adding messages from different folder (#1487752) - if (flags.mbox != this.env.mailbox && !flags.skip_mbox_check) - return false; - - if (!this.env.messages[uid]) - this.env.messages[uid] = {}; - - // merge flags over local message object - $.extend(this.env.messages[uid], { - deleted: flags.deleted?1:0, - replied: flags.answered?1:0, - unread: !flags.seen?1:0, - forwarded: flags.forwarded?1:0, - flagged: flags.flagged?1:0, - has_children: flags.has_children?1:0, - depth: flags.depth?flags.depth:0, - unread_children: flags.unread_children?flags.unread_children:0, - parent_uid: flags.parent_uid?flags.parent_uid:0, - selected: this.select_all_mode || this.message_list.in_selection(uid), - ml: flags.ml?1:0, - ctype: flags.ctype, - // flags from plugins - flags: flags.extra_flags - }); - - var c, n, col, html, css_class, - tree = '', expando = '', - list = this.message_list, - rows = list.rows, - message = this.env.messages[uid], - row_class = 'message' - + (!flags.seen ? ' unread' : '') - + (flags.deleted ? ' deleted' : '') - + (flags.flagged ? ' flagged' : '') - + (message.selected ? ' selected' : ''), - row = { cols:[], style:{}, id:'rcmrow'+uid }; - - // message status icons - css_class = 'msgicon'; - if (this.env.status_col === null) { - css_class += ' status'; - if (flags.deleted) - css_class += ' deleted'; - else if (!flags.seen) - css_class += ' unread'; - else if (flags.unread_children > 0) - css_class += ' unreadchildren'; - } - if (flags.answered) - css_class += ' replied'; - if (flags.forwarded) - css_class += ' forwarded'; - - // update selection - if (message.selected && !list.in_selection(uid)) - list.selection.push(uid); - - // threads - if (this.env.threading) { - if (message.depth) { - // This assumes that div width is hardcoded to 15px, - tree += '<span id="rcmtab' + uid + '" class="branch" style="width:' + (message.depth * 15) + 'px;"> </span>'; - - if ((rows[message.parent_uid] && rows[message.parent_uid].expanded === false) - || ((this.env.autoexpand_threads == 0 || this.env.autoexpand_threads == 2) && - (!rows[message.parent_uid] || !rows[message.parent_uid].expanded)) - ) { - row.style.display = 'none'; - message.expanded = false; - } - else - message.expanded = true; - - row_class += ' thread expanded'; - } - else if (message.has_children) { - if (message.expanded === undefined && (this.env.autoexpand_threads == 1 || (this.env.autoexpand_threads == 2 && message.unread_children))) { - message.expanded = true; - } - - expando = '<div id="rcmexpando' + uid + '" class="' + (message.expanded ? 'expanded' : 'collapsed') + '"> </div>'; - row_class += ' thread' + (message.expanded? ' expanded' : ''); - } - - if (flags.unread_children && flags.seen && !message.expanded) - row_class += ' unroot'; - } - - tree += '<span id="msgicn'+uid+'" class="'+css_class+'"> </span>'; - row.className = row_class; - - // build subject link - if (!bw.ie && cols.subject) { - var action = flags.mbox == this.env.drafts_mailbox ? 'compose' : 'show'; - var uid_param = flags.mbox == this.env.drafts_mailbox ? '_draft_uid' : '_uid'; - cols.subject = '<a href="./?_task=mail&_action='+action+'&_mbox='+urlencode(flags.mbox)+'&'+uid_param+'='+uid+'"'+ - ' onclick="return rcube_event.cancel(event)" onmouseover="rcube_webmail.long_subject_title(this,'+(message.depth+1)+')">'+cols.subject+'</a>'; - } - - // add each submitted col - for (n in this.env.coltypes) { - c = this.env.coltypes[n]; - col = { className: String(c).toLowerCase() }; - - if (c == 'flag') { - css_class = (flags.flagged ? 'flagged' : 'unflagged'); - html = '<span id="flagicn'+uid+'" class="'+css_class+'"> </span>'; - } - else if (c == 'attachment') { - if (/application\/|multipart\/(m|signed)/.test(flags.ctype)) - html = '<span class="attachment"> </span>'; - else if (/multipart\/report/.test(flags.ctype)) - html = '<span class="report"> </span>'; - else - html = ' '; - } - else if (c == 'status') { - if (flags.deleted) - css_class = 'deleted'; - else if (!flags.seen) - css_class = 'unread'; - else if (flags.unread_children > 0) - css_class = 'unreadchildren'; - else - css_class = 'msgicon'; - html = '<span id="statusicn'+uid+'" class="'+css_class+'"> </span>'; - } - else if (c == 'threads') - html = expando; - else if (c == 'subject') { - if (bw.ie) { - col.onmouseover = function() { rcube_webmail.long_subject_title_ie(this, message.depth+1); }; - if (bw.ie8) - tree = '<span></span>' + tree; // #1487821 - } - html = tree + cols[c]; - } - else if (c == 'priority') { - if (flags.prio > 0 && flags.prio < 6) - html = '<span class="prio'+flags.prio+'"> </span>'; - else - html = ' '; - } - else - html = cols[c]; - - col.innerHTML = html; - row.cols.push(col); - } - - list.insert_row(row, attop); - - // remove 'old' row - if (attop && this.env.pagesize && list.rowcount > this.env.pagesize) { - var uid = list.get_last_row(); - list.remove_row(uid); - list.clear_selection(uid); - } - }; - - this.set_list_sorting = function(sort_col, sort_order) - { - // set table header class - $('#rcm'+this.env.sort_col).removeClass('sorted'+(this.env.sort_order.toUpperCase())); - if (sort_col) - $('#rcm'+sort_col).addClass('sorted'+sort_order); - - this.env.sort_col = sort_col; - this.env.sort_order = sort_order; - }; - - this.set_list_options = function(cols, sort_col, sort_order, threads) - { - var update, post_data = {}; - - if (sort_col === undefined) - sort_col = this.env.sort_col; - if (!sort_order) - sort_order = this.env.sort_order; - - if (this.env.sort_col != sort_col || this.env.sort_order != sort_order) { - update = 1; - this.set_list_sorting(sort_col, sort_order); - } - - if (this.env.threading != threads) { - update = 1; - post_data._threads = threads; - } - - if (cols && cols.length) { - // make sure new columns are added at the end of the list - var i, idx, name, newcols = [], oldcols = this.env.coltypes; - for (i=0; i<oldcols.length; i++) { - name = oldcols[i]; - idx = $.inArray(name, cols); - if (idx != -1) { - newcols.push(name); - delete cols[idx]; - } - } - for (i=0; i<cols.length; i++) - if (cols[i]) - newcols.push(cols[i]); - - if (newcols.join() != oldcols.join()) { - update = 1; - post_data._cols = newcols.join(','); - } - } - - if (update) - this.list_mailbox('', '', sort_col+'_'+sort_order, post_data); - }; - - // when user double-clicks on a row - this.show_message = function(id, safe, preview) - { - if (!id) - return; - - var win, target = window, - action = preview ? 'preview': 'show', - url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox); - - if (preview && (win = this.get_frame_window(this.env.contentframe))) { - target = win; - url += '&_framed=1'; - } - - if (safe) - url += '&_safe=1'; - - // also send search request to get the right messages - if (this.env.search_request) - url += '&_search='+this.env.search_request; - - // add browser capabilities, so we can properly handle attachments - url += '&_caps='+urlencode(this.browser_capabilities()); - - if (this.env.extwin) - url += '&_extwin=1'; - - if (preview && String(target.location.href).indexOf(url) >= 0) { - this.show_contentframe(true); - } - else { - if (!preview && this.env.message_extwin && !this.env.extwin) - this.open_window(this.env.comm_path+url, true); - else - this.location_href(this.env.comm_path+url, target, true); - - // mark as read and change mbox unread counter - if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) { - this.preview_read_timer = setTimeout(function() { - ref.set_message(id, 'unread', false); - ref.update_thread_root(id, 'read'); - if (ref.env.unread_counts[ref.env.mailbox]) { - ref.env.unread_counts[ref.env.mailbox] -= 1; - ref.set_unread_count(ref.env.mailbox, ref.env.unread_counts[ref.env.mailbox], ref.env.mailbox == 'INBOX'); - } - if (ref.env.preview_pane_mark_read > 0) - ref.http_post('mark', {_uid: id, _flag: 'read', _quiet: 1}); - }, this.env.preview_pane_mark_read * 1000); - } - } - }; - - this.show_contentframe = function(show) - { - var frame, win, name = this.env.contentframe; - - if (name && (frame = this.get_frame_element(name))) { - if (!show && (win = this.get_frame_window(name))) { - if (win.stop) - win.stop(); - else // IE - win.document.execCommand('Stop'); - - win.location.href = this.env.blankpage; - } - else if (!bw.safari && !bw.konq) - $(frame)[show ? 'show' : 'hide'](); - } - - if (!show && this.env.frame_lock) - this.set_busy(false, null, this.env.frame_lock); - }; - - this.get_frame_element = function(id) - { - var frame; - - if (id && (frame = document.getElementById(id))) - return frame; - }; - - this.get_frame_window = function(id) - { - var frame = this.get_frame_element(id); - - if (frame && frame.name && window.frames) - return window.frames[frame.name]; - }; - - this.lock_frame = function() - { - if (!this.env.frame_lock) - (this.is_framed() ? parent.rcmail : this).env.frame_lock = this.set_busy(true, 'loading'); - }; - - // list a specific page - this.list_page = function(page) - { - if (page == 'next') - page = this.env.current_page+1; - else if (page == 'last') - page = this.env.pagecount; - else if (page == 'prev' && this.env.current_page > 1) - page = this.env.current_page-1; - else if (page == 'first' && this.env.current_page > 1) - page = 1; - - if (page > 0 && page <= this.env.pagecount) { - this.env.current_page = page; - - if (this.task == 'addressbook' || this.contact_list) - this.list_contacts(this.env.source, this.env.group, page); - else if (this.task == 'mail') - this.list_mailbox(this.env.mailbox, page); - } - }; - - // sends request to check for recent messages - this.checkmail = function() - { - var lock = this.set_busy(true, 'checkingmail'), - params = this.check_recent_params(); - - this.http_request('check-recent', params, lock); - }; - - // list messages of a specific mailbox using filter - this.filter_mailbox = function(filter) - { - var lock = this.set_busy(true, 'searching'); - - this.clear_message_list(); - - // reset vars - this.env.current_page = 1; - this.http_request('search', this.search_params(false, filter), lock); - }; - - // list messages of a specific mailbox - this.list_mailbox = function(mbox, page, sort, url) - { - var win, target = window; - - if (typeof url != 'object') - url = {}; - - if (!mbox) - mbox = this.env.mailbox ? this.env.mailbox : 'INBOX'; - - // add sort to url if set - if (sort) - url._sort = sort; - - // also send search request to get the right messages - if (this.env.search_request) - url._search = this.env.search_request; - - // set page=1 if changeing to another mailbox - if (this.env.mailbox != mbox) { - page = 1; - this.env.current_page = page; - this.select_all_mode = false; - } - - // unselect selected messages and clear the list and message data - this.clear_message_list(); - - if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort)) - url._refresh = 1; - - this.select_folder(mbox, '', true); - this.unmark_folder(mbox, 'recent', '', true); - this.env.mailbox = mbox; - - // load message list remotely - if (this.gui_objects.messagelist) { - this.list_mailbox_remote(mbox, page, url); - return; - } - - if (win = this.get_frame_window(this.env.contentframe)) { - target = win; - url._framed = 1; - } - - // load message list to target frame/window - if (mbox) { - this.set_busy(true, 'loading'); - url._mbox = mbox; - if (page) - url._page = page; - this.location_href(url, target); - } - }; - - this.clear_message_list = function() - { - this.env.messages = {}; - this.last_selected = 0; - - this.show_contentframe(false); - if (this.message_list) - this.message_list.clear(true); - }; - - // send remote request to load message list - this.list_mailbox_remote = function(mbox, page, post_data) - { - // clear message list first - this.message_list.clear(); - - var lock = this.set_busy(true, 'loading'); - - if (typeof post_data != 'object') - post_data = {}; - post_data._mbox = mbox; - if (page) - post_data._page = page; - - this.http_request('list', post_data, lock); - }; - - // removes messages that doesn't exists from list selection array - this.update_selection = function() - { - var selected = this.message_list.selection, - rows = this.message_list.rows, - i, selection = []; - - for (i in selected) - if (rows[selected[i]]) - selection.push(selected[i]); - - this.message_list.selection = selection; - } - - // expand all threads with unread children - this.expand_unread = function() - { - var r, tbody = this.gui_objects.messagelist.tBodies[0], - new_row = tbody.firstChild; - - while (new_row) { - if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) && r.unread_children) { - this.message_list.expand_all(r); - this.set_unread_children(r.uid); - } - new_row = new_row.nextSibling; - } - return false; - }; - - // thread expanding/collapsing handler - this.expand_message_row = function(e, uid) - { - var row = this.message_list.rows[uid]; - - // handle unread_children mark - row.expanded = !row.expanded; - this.set_unread_children(uid); - row.expanded = !row.expanded; - - this.message_list.expand_row(e, uid); - }; - - // message list expanding - this.expand_threads = function() - { - if (!this.env.threading || !this.env.autoexpand_threads || !this.message_list) - return; - - switch (this.env.autoexpand_threads) { - case 2: this.expand_unread(); break; - case 1: this.message_list.expand_all(); break; - } - }; - - // Initializes threads indicators/expanders after list update - this.init_threads = function(roots, mbox) - { - // #1487752 - if (mbox && mbox != this.env.mailbox) - return false; - - for (var n=0, len=roots.length; n<len; n++) - this.add_tree_icons(roots[n]); - this.expand_threads(); - }; - - // adds threads tree icons to the list (or specified thread) - this.add_tree_icons = function(root) - { - var i, l, r, n, len, pos, tmp = [], uid = [], - row, rows = this.message_list.rows; - - if (root) - row = rows[root] ? rows[root].obj : null; - else - row = this.message_list.tbody.firstChild; - - while (row) { - if (row.nodeType == 1 && (r = rows[row.uid])) { - if (r.depth) { - for (i=tmp.length-1; i>=0; i--) { - len = tmp[i].length; - if (len > r.depth) { - pos = len - r.depth; - if (!(tmp[i][pos] & 2)) - tmp[i][pos] = tmp[i][pos] ? tmp[i][pos]+2 : 2; - } - else if (len == r.depth) { - if (!(tmp[i][0] & 2)) - tmp[i][0] += 2; - } - if (r.depth > len) - break; - } - - tmp.push(new Array(r.depth)); - tmp[tmp.length-1][0] = 1; - uid.push(r.uid); - } - else { - if (tmp.length) { - for (i in tmp) { - this.set_tree_icons(uid[i], tmp[i]); - } - tmp = []; - uid = []; - } - if (root && row != rows[root].obj) - break; - } - } - row = row.nextSibling; - } - - if (tmp.length) { - for (i in tmp) { - this.set_tree_icons(uid[i], tmp[i]); - } - } - }; - - // adds tree icons to specified message row - this.set_tree_icons = function(uid, tree) - { - var i, divs = [], html = '', len = tree.length; - - for (i=0; i<len; i++) { - if (tree[i] > 2) - divs.push({'class': 'l3', width: 15}); - else if (tree[i] > 1) - divs.push({'class': 'l2', width: 15}); - else if (tree[i] > 0) - divs.push({'class': 'l1', width: 15}); - // separator div - else if (divs.length && !divs[divs.length-1]['class']) - divs[divs.length-1].width += 15; - else - divs.push({'class': null, width: 15}); - } - - for (i=divs.length-1; i>=0; i--) { - if (divs[i]['class']) - html += '<div class="tree '+divs[i]['class']+'" />'; - else - html += '<div style="width:'+divs[i].width+'px" />'; - } - - if (html) - $('#rcmtab'+uid).html(html); - }; - - // update parent in a thread - this.update_thread_root = function(uid, flag) - { - if (!this.env.threading) - return; - - var root = this.message_list.find_root(uid); - - if (uid == root) - return; - - var p = this.message_list.rows[root]; - - if (flag == 'read' && p.unread_children) { - p.unread_children--; - } - else if (flag == 'unread' && p.has_children) { - // unread_children may be undefined - p.unread_children = p.unread_children ? p.unread_children + 1 : 1; - } - else { - return; - } - - this.set_message_icon(root); - this.set_unread_children(root); - }; - - // update thread indicators for all messages in a thread below the specified message - // return number of removed/added root level messages - this.update_thread = function (uid) - { - if (!this.env.threading) - return 0; - - var r, parent, count = 0, - rows = this.message_list.rows, - row = rows[uid], - depth = rows[uid].depth, - roots = []; - - if (!row.depth) // root message: decrease roots count - count--; - else if (row.unread) { - // update unread_children for thread root - parent = this.message_list.find_root(uid); - rows[parent].unread_children--; - this.set_unread_children(parent); - } - - parent = row.parent_uid; - - // childrens - row = row.obj.nextSibling; - while (row) { - if (row.nodeType == 1 && (r = rows[row.uid])) { - if (!r.depth || r.depth <= depth) - break; - - r.depth--; // move left - // reset width and clear the content of a tab, icons will be added later - $('#rcmtab'+r.uid).width(r.depth * 15).html(''); - if (!r.depth) { // a new root - count++; // increase roots count - r.parent_uid = 0; - if (r.has_children) { - // replace 'leaf' with 'collapsed' - $('#rcmrow'+r.uid+' '+'.leaf:first') - .attr('id', 'rcmexpando' + r.uid) - .attr('class', (r.obj.style.display != 'none' ? 'expanded' : 'collapsed')) - .bind('mousedown', {uid:r.uid, p:this}, - function(e) { return e.data.p.expand_message_row(e, e.data.uid); }); - - r.unread_children = 0; - roots.push(r); - } - // show if it was hidden - if (r.obj.style.display == 'none') - $(r.obj).show(); - } - else { - if (r.depth == depth) - r.parent_uid = parent; - if (r.unread && roots.length) - roots[roots.length-1].unread_children++; - } - } - row = row.nextSibling; - } - - // update unread_children for roots - for (var i=0; i<roots.length; i++) - this.set_unread_children(roots[i].uid); - - return count; - }; - - this.delete_excessive_thread_rows = function() - { - var rows = this.message_list.rows, - tbody = this.message_list.tbody, - row = tbody.firstChild, - cnt = this.env.pagesize + 1; - - while (row) { - if (row.nodeType == 1 && (r = rows[row.uid])) { - if (!r.depth && cnt) - cnt--; - - if (!cnt) - this.message_list.remove_row(row.uid); - } - row = row.nextSibling; - } - }; - - // set message icon - this.set_message_icon = function(uid) - { - var css_class, - row = this.message_list.rows[uid]; - - if (!row) - return false; - - if (row.icon) { - css_class = 'msgicon'; - if (row.deleted) - css_class += ' deleted'; - else if (row.unread) - css_class += ' unread'; - else if (row.unread_children) - css_class += ' unreadchildren'; - if (row.msgicon == row.icon) { - if (row.replied) - css_class += ' replied'; - if (row.forwarded) - css_class += ' forwarded'; - css_class += ' status'; - } - - row.icon.className = css_class; - } - - if (row.msgicon && row.msgicon != row.icon) { - css_class = 'msgicon'; - if (!row.unread && row.unread_children) - css_class += ' unreadchildren'; - if (row.replied) - css_class += ' replied'; - if (row.forwarded) - css_class += ' forwarded'; - - row.msgicon.className = css_class; - } - - if (row.flagicon) { - css_class = (row.flagged ? 'flagged' : 'unflagged'); - row.flagicon.className = css_class; - } - }; - - // set message status - this.set_message_status = function(uid, flag, status) - { - var row = this.message_list.rows[uid]; - - if (!row) - return false; - - if (flag == 'unread') - row.unread = status; - else if(flag == 'deleted') - row.deleted = status; - else if (flag == 'replied') - row.replied = status; - else if (flag == 'forwarded') - row.forwarded = status; - else if (flag == 'flagged') - row.flagged = status; - }; - - // set message row status, class and icon - this.set_message = function(uid, flag, status) - { - var row = this.message_list && this.message_list.rows[uid]; - - if (!row) - return false; - - if (flag) - this.set_message_status(uid, flag, status); - - var rowobj = $(row.obj); - - if (row.unread && !rowobj.hasClass('unread')) - rowobj.addClass('unread'); - else if (!row.unread && rowobj.hasClass('unread')) - rowobj.removeClass('unread'); - - if (row.deleted && !rowobj.hasClass('deleted')) - rowobj.addClass('deleted'); - else if (!row.deleted && rowobj.hasClass('deleted')) - rowobj.removeClass('deleted'); - - if (row.flagged && !rowobj.hasClass('flagged')) - rowobj.addClass('flagged'); - else if (!row.flagged && rowobj.hasClass('flagged')) - rowobj.removeClass('flagged'); - - this.set_unread_children(uid); - this.set_message_icon(uid); - }; - - // sets unroot (unread_children) class of parent row - this.set_unread_children = function(uid) - { - var row = this.message_list.rows[uid]; - - if (row.parent_uid) - return; - - if (!row.unread && row.unread_children && !row.expanded) - $(row.obj).addClass('unroot'); - else - $(row.obj).removeClass('unroot'); - }; - - // copy selected messages to the specified mailbox - this.copy_messages = function(mbox) - { - if (mbox && typeof mbox === 'object') - mbox = mbox.id; - - // exit if current or no mailbox specified - if (!mbox || mbox == this.env.mailbox) - return; - - var post_data = this.selection_post_data({_target_mbox: mbox}); - - // exit if selection is empty - if (!post_data._uid) - return; - - // send request to server - this.http_post('copy', post_data, this.display_message(this.get_label('copyingmessage'), 'loading')); - }; - - // move selected messages to the specified mailbox - this.move_messages = function(mbox) - { - if (mbox && typeof mbox === 'object') - mbox = mbox.id; - - // exit if current or no mailbox specified - if (!mbox || mbox == this.env.mailbox) - return; - - var lock = false, post_data = this.selection_post_data({_target_mbox: mbox}); - - // exit if selection is empty - if (!post_data._uid) - return; - - // show wait message - if (this.env.action == 'show') - lock = this.set_busy(true, 'movingmessage'); - else - this.show_contentframe(false); - - // Hide message command buttons until a message is selected - this.enable_command(this.env.message_commands, false); - - this._with_selected_messages('move', post_data, lock); - }; - - // delete selected messages from the current mailbox - this.delete_messages = function(event) - { - var uid, i, len, trash = this.env.trash_mailbox, - list = this.message_list, - selection = list ? list.get_selection() : []; - - // exit if no mailbox specified or if selection is empty - if (!this.env.uid && !selection.length) - return; - - // also select childs of collapsed rows - for (i=0, len=selection.length; i<len; i++) { - uid = selection[i]; - if (list.rows[uid].has_children && !list.rows[uid].expanded) - list.select_children(uid); - } - - // if config is set to flag for deletion - if (this.env.flag_for_deletion) { - this.mark_message('delete'); - return false; - } - // if there isn't a defined trash mailbox or we are in it - else if (!trash || this.env.mailbox == trash) - this.permanently_remove_messages(); - // we're in Junk folder and delete_junk is enabled - else if (this.env.delete_junk && this.env.junk_mailbox && this.env.mailbox == this.env.junk_mailbox) - this.permanently_remove_messages(); - // if there is a trash mailbox defined and we're not currently in it - else { - // if shift was pressed delete it immediately - if ((list && list.modkey == SHIFT_KEY) || (event && rcube_event.get_modifier(event) == SHIFT_KEY)) { - if (confirm(this.get_label('deletemessagesconfirm'))) - this.permanently_remove_messages(); - } - else - this.move_messages(trash); - } - - return true; - }; - - // delete the selected messages permanently - this.permanently_remove_messages = function() - { - var post_data = this.selection_post_data(); - - // exit if selection is empty - if (!post_data._uid) - return; - - this.show_contentframe(false); - this._with_selected_messages('delete', post_data); - }; - - // Send a specifc move/delete request with UIDs of all selected messages - // @private - this._with_selected_messages = function(action, post_data, lock) - { - var count = 0, msg; - - // update the list (remove rows, clear selection) - if (this.message_list) { - var n, id, root, roots = [], - selection = this.message_list.get_selection(); - - for (n=0, len=selection.length; n<len; n++) { - id = selection[n]; - - if (this.env.threading) { - count += this.update_thread(id); - root = this.message_list.find_root(id); - if (root != id && $.inArray(root, roots) < 0) { - roots.push(root); - } - } - this.message_list.remove_row(id, (this.env.display_next && n == selection.length-1)); - } - // make sure there are no selected rows - if (!this.env.display_next) - this.message_list.clear_selection(); - // update thread tree icons - for (n=0, len=roots.length; n<len; n++) { - this.add_tree_icons(roots[n]); - } - } - - if (this.env.display_next && this.env.next_uid) - post_data._next_uid = this.env.next_uid; - - if (count < 0) - post_data._count = (count*-1); - // remove threads from the end of the list - else if (count > 0) - this.delete_excessive_thread_rows(); - - if (!lock) { - msg = action == 'move' ? 'movingmessage' : 'deletingmessage'; - lock = this.display_message(this.get_label(msg), 'loading'); - } - - // send request to server - this.http_post(action, post_data, lock); - }; - - // build post data for message delete/move/copy/flag requests - this.selection_post_data = function(data) - { - if (typeof(data) != 'object') - data = {}; - - data._mbox = this.env.mailbox; - - if (!data._uid) { - var uids = this.env.uid ? [this.env.uid] : this.message_list.get_selection(); - data._uid = this.uids_to_list(uids); - } - - if (this.env.action) - data._from = this.env.action; - - // also send search request to get the right messages - if (this.env.search_request) - data._search = this.env.search_request; - - return data; - }; - - // set a specific flag to one or more messages - this.mark_message = function(flag, uid) - { - var a_uids = [], r_uids = [], len, n, id, - list = this.message_list; - - if (uid) - a_uids[0] = uid; - else if (this.env.uid) - a_uids[0] = this.env.uid; - else if (list) - a_uids = list.get_selection(); - - if (!list) - r_uids = a_uids; - else { - list.focus(); - for (n=0, len=a_uids.length; n<len; n++) { - id = a_uids[n]; - if ((flag == 'read' && list.rows[id].unread) - || (flag == 'unread' && !list.rows[id].unread) - || (flag == 'delete' && !list.rows[id].deleted) - || (flag == 'undelete' && list.rows[id].deleted) - || (flag == 'flagged' && !list.rows[id].flagged) - || (flag == 'unflagged' && list.rows[id].flagged)) - { - r_uids.push(id); - } - } - } - - // nothing to do - if (!r_uids.length && !this.select_all_mode) - return; - - switch (flag) { - case 'read': - case 'unread': - this.toggle_read_status(flag, r_uids); - break; - case 'delete': - case 'undelete': - this.toggle_delete_status(r_uids); - break; - case 'flagged': - case 'unflagged': - this.toggle_flagged_status(flag, a_uids); - break; - } - }; - - // set class to read/unread - this.toggle_read_status = function(flag, a_uids) - { - var i, len = a_uids.length, - post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: flag}), - lock = this.display_message(this.get_label('markingmessage'), 'loading'); - - // mark all message rows as read/unread - for (i=0; i<len; i++) - this.set_message(a_uids[i], 'unread', (flag == 'unread' ? true : false)); - - this.http_post('mark', post_data, lock); - - for (i=0; i<len; i++) - this.update_thread_root(a_uids[i], flag); - }; - - // set image to flagged or unflagged - this.toggle_flagged_status = function(flag, a_uids) - { - var i, len = a_uids.length, - post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: flag}), - lock = this.display_message(this.get_label('markingmessage'), 'loading'); - - // mark all message rows as flagged/unflagged - for (i=0; i<len; i++) - this.set_message(a_uids[i], 'flagged', (flag == 'flagged' ? true : false)); - - this.http_post('mark', post_data, lock); - }; - - // mark all message rows as deleted/undeleted - this.toggle_delete_status = function(a_uids) - { - var len = a_uids.length, - i, uid, all_deleted = true, - rows = this.message_list ? this.message_list.rows : []; - - if (len == 1) { - if (!rows.length || (rows[a_uids[0]] && !rows[a_uids[0]].deleted)) - this.flag_as_deleted(a_uids); - else - this.flag_as_undeleted(a_uids); - - return true; - } - - for (i=0; i<len; i++) { - uid = a_uids[i]; - if (rows[uid] && !rows[uid].deleted) { - all_deleted = false; - break; - } - } - - if (all_deleted) - this.flag_as_undeleted(a_uids); - else - this.flag_as_deleted(a_uids); - - return true; - }; - - this.flag_as_undeleted = function(a_uids) - { - var i, len = a_uids.length, - post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: 'undelete'}), - lock = this.display_message(this.get_label('markingmessage'), 'loading'); - - for (i=0; i<len; i++) - this.set_message(a_uids[i], 'deleted', false); - - this.http_post('mark', post_data, lock); - }; - - this.flag_as_deleted = function(a_uids) - { - var r_uids = [], - post_data = this.selection_post_data({_uid: this.uids_to_list(a_uids), _flag: 'delete'}), - lock = this.display_message(this.get_label('markingmessage'), 'loading'), - rows = this.message_list ? this.message_list.rows : [], - count = 0; - - for (var i=0, len=a_uids.length; i<len; i++) { - uid = a_uids[i]; - if (rows[uid]) { - if (rows[uid].unread) - r_uids[r_uids.length] = uid; - - if (this.env.skip_deleted) { - count += this.update_thread(uid); - this.message_list.remove_row(uid, (this.env.display_next && i == this.message_list.selection.length-1)); - } - else - this.set_message(uid, 'deleted', true); - } - } - - // make sure there are no selected rows - if (this.env.skip_deleted && this.message_list) { - if(!this.env.display_next) - this.message_list.clear_selection(); - if (count < 0) - post_data._count = (count*-1); - else if (count > 0) - // remove threads from the end of the list - this.delete_excessive_thread_rows(); - } - - // ?? - if (r_uids.length) - post_data._ruid = this.uids_to_list(r_uids); - - if (this.env.skip_deleted && this.env.display_next && this.env.next_uid) - post_data._next_uid = this.env.next_uid; - - this.http_post('mark', post_data, lock); - }; - - // flag as read without mark request (called from backend) - // argument should be a coma-separated list of uids - this.flag_deleted_as_read = function(uids) - { - var icn_src, uid, i, len, - rows = this.message_list ? this.message_list.rows : []; - - uids = String(uids).split(','); - - for (i=0, len=uids.length; i<len; i++) { - uid = uids[i]; - if (rows[uid]) - this.set_message(uid, 'unread', false); - } - }; - - // Converts array of message UIDs to comma-separated list for use in URL - // with select_all mode checking - this.uids_to_list = function(uids) - { - return this.select_all_mode ? '*' : uids.join(','); - }; - - // Sets title of the delete button - this.set_button_titles = function() - { - var label = 'deletemessage'; - - if (!this.env.flag_for_deletion - && this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox - && (!this.env.delete_junk || !this.env.junk_mailbox || this.env.mailbox != this.env.junk_mailbox) - ) - label = 'movemessagetotrash'; - - this.set_alttext('delete', label); - }; - - /*********************************************************/ - /********* mailbox folders methods *********/ - /*********************************************************/ - - this.expunge_mailbox = function(mbox) - { - var lock, post_data = {_mbox: mbox}; - - // lock interface if it's the active mailbox - if (mbox == this.env.mailbox) { - lock = this.set_busy(true, 'loading'); - post_data._reload = 1; - if (this.env.search_request) - post_data._search = this.env.search_request; - } - - // send request to server - this.http_post('expunge', post_data, lock); - }; - - this.purge_mailbox = function(mbox) - { - var lock, post_data = {_mbox: mbox}; - - if (!confirm(this.get_label('purgefolderconfirm'))) - return false; - - // lock interface if it's the active mailbox - if (mbox == this.env.mailbox) { - lock = this.set_busy(true, 'loading'); - post_data._reload = 1; - } - - // send request to server - this.http_post('purge', post_data, lock); - }; - - // test if purge command is allowed - this.purge_mailbox_test = function() - { - return (this.env.exists && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox - || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) - || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))); - }; - - - /*********************************************************/ - /********* login form methods *********/ - /*********************************************************/ - - // handler for keyboard events on the _user field - this.login_user_keyup = function(e) - { - var key = rcube_event.get_keycode(e); - var passwd = $('#rcmloginpwd'); - - // enter - if (key == 13 && passwd.length && !passwd.val()) { - passwd.focus(); - return rcube_event.cancel(e); - } - - return true; - }; - - - /*********************************************************/ - /********* message compose methods *********/ - /*********************************************************/ - - this.open_compose_step = function(p) - { - var url = this.url('mail/compose', p); - - // open new compose window - if (this.env.compose_extwin && !this.env.extwin) { - this.open_window(url); - } - else { - this.redirect(url); - if (this.env.extwin) - window.resizeTo(Math.max(this.env.popup_width, $(window).width()), $(window).height() + 24); - } - }; - - // init message compose form: set focus and eventhandlers - this.init_messageform = function() - { - if (!this.gui_objects.messageform) - return false; - - var input_from = $("[name='_from']"), - input_to = $("[name='_to']"), - input_subject = $("input[name='_subject']"), - input_message = $("[name='_message']").get(0), - html_mode = $("input[name='_is_html']").val() == '1', - ac_fields = ['cc', 'bcc', 'replyto', 'followupto'], - ac_props, opener_rc = this.opener(); - - // close compose step in opener - if (opener_rc && opener_rc.env.action == 'compose') { - setTimeout(function(){ opener.history.back(); }, 100); - this.env.opened_extwin = true; - } - - // configure parallel autocompletion - if (this.env.autocomplete_threads > 0) { - ac_props = { - threads: this.env.autocomplete_threads, - sources: this.env.autocomplete_sources - }; - } - - // init live search events - this.init_address_input_events(input_to, ac_props); - for (var i in ac_fields) { - this.init_address_input_events($("[name='_"+ac_fields[i]+"']"), ac_props); - } - - if (!html_mode) { - this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length); - // add signature according to selected identity - // if we have HTML editor, signature is added in callback - if (input_from.prop('type') == 'select-one') { - this.change_identity(input_from[0]); - } - } - - if (input_to.val() == '') - input_to.focus(); - else if (input_subject.val() == '') - input_subject.focus(); - else if (input_message) - input_message.focus(); - - this.env.compose_focus_elem = document.activeElement; - - // get summary of all field values - this.compose_field_hash(true); - - // start the auto-save timer - this.auto_save_start(); - }; - - this.init_address_input_events = function(obj, props) - { - this.env.recipients_delimiter = this.env.recipients_separator + ' '; - - obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); }) - .attr('autocomplete', 'off'); - }; - - this.submit_messageform = function(draft) - { - var form = this.gui_objects.messageform; - - if (!form) - return; - - // all checks passed, send message - var msgid = this.set_busy(true, draft ? 'savingmessage' : 'sendingmessage'), - lang = this.spellcheck_lang(), - files = []; - - // send files list - $('li', this.gui_objects.attachmentlist).each(function() { files.push(this.id.replace(/^rcmfile/, '')); }); - $('input[name="_attachments"]', form).val(files.join()); - - form.target = 'savetarget'; - form._draft.value = draft ? '1' : ''; - form.action = this.add_url(form.action, '_unlock', msgid); - form.action = this.add_url(form.action, '_lang', lang); - - // register timer to notify about connection timeout - this.submit_timer = setTimeout(function(){ - ref.set_busy(false, null, msgid); - ref.display_message(ref.get_label('requesttimedout'), 'error'); - }, this.env.request_timeout * 1000); - - form.submit(); - }; - - this.compose_recipient_select = function(list) - { - var id, n, recipients = 0; - for (n=0; n < list.selection.length; n++) { - id = list.selection[n]; - if (this.env.contactdata[id]) - recipients++; - } - this.enable_command('add-recipient', recipients); - }; - - this.compose_add_recipient = function(field) - { - var recipients = [], input = $('#_'+field), delim = this.env.recipients_delimiter; - - if (this.contact_list && this.contact_list.selection.length) { - for (var id, n=0; n < this.contact_list.selection.length; n++) { - id = this.contact_list.selection[n]; - if (id && this.env.contactdata[id]) { - recipients.push(this.env.contactdata[id]); - - // group is added, expand it - if (id.charAt(0) == 'E' && this.env.contactdata[id].indexOf('@') < 0 && input.length) { - var gid = id.substr(1); - this.group2expand[gid] = { name:this.env.contactdata[id], input:input.get(0) }; - this.http_request('group-expand', {_source: this.env.source, _gid: gid}, false); - } - } - } - } - - if (recipients.length && input.length) { - var oldval = input.val(), rx = new RegExp(RegExp.escape(delim) + '\\s*$'); - if (oldval && !rx.test(oldval)) - oldval += delim + ' '; - input.val(oldval + recipients.join(delim + ' ') + delim + ' '); - this.triggerEvent('add-recipient', { field:field, recipients:recipients }); - } - }; - - // checks the input fields before sending a message - this.check_compose_input = function(cmd) - { - // check input fields - var ed, input_to = $("[name='_to']"), - input_cc = $("[name='_cc']"), - input_bcc = $("[name='_bcc']"), - input_from = $("[name='_from']"), - input_subject = $("[name='_subject']"), - input_message = $("[name='_message']"); - - // check sender (if have no identities) - if (input_from.prop('type') == 'text' && !rcube_check_email(input_from.val(), true)) { - alert(this.get_label('nosenderwarning')); - input_from.focus(); - return false; - } - - // check for empty recipient - var recipients = input_to.val() ? input_to.val() : (input_cc.val() ? input_cc.val() : input_bcc.val()); - if (!rcube_check_email(recipients.replace(/^\s+/, '').replace(/[\s,;]+$/, ''), true)) { - alert(this.get_label('norecipientwarning')); - input_to.focus(); - return false; - } - - // check if all files has been uploaded - for (var key in this.env.attachments) { - if (typeof this.env.attachments[key] === 'object' && !this.env.attachments[key].complete) { - alert(this.get_label('notuploadedwarning')); - return false; - } - } - - // display localized warning for missing subject - if (input_subject.val() == '') { - var myprompt = $('<div class="prompt">').html('<div class="message">' + this.get_label('nosubjectwarning') + '</div>').appendTo(document.body); - var prompt_value = $('<input>').attr('type', 'text').attr('size', 30).appendTo(myprompt).val(this.get_label('nosubject')); - - var buttons = {}; - buttons[this.get_label('cancel')] = function(){ - input_subject.focus(); - $(this).dialog('close'); - }; - buttons[this.get_label('sendmessage')] = function(){ - input_subject.val(prompt_value.val()); - $(this).dialog('close'); - ref.command(cmd, { nocheck:true }); // repeat command which triggered this - }; - - myprompt.dialog({ - modal: true, - resizable: false, - buttons: buttons, - close: function(event, ui) { $(this).remove() } - }); - prompt_value.select(); - return false; - } - - // Apply spellcheck changes if spell checker is active - this.stop_spellchecking(); - - if (window.tinyMCE) - ed = tinyMCE.get(this.env.composebody); - - // check for empty body - if (!ed && input_message.val() == '' && !confirm(this.get_label('nobodywarning'))) { - input_message.focus(); - return false; - } - else if (ed) { - if (!ed.getContent() && !confirm(this.get_label('nobodywarning'))) { - ed.focus(); - return false; - } - // move body from html editor to textarea (just to be sure, #1485860) - tinyMCE.triggerSave(); - } - - return true; - }; - - this.toggle_editor = function(props) - { - this.stop_spellchecking(); - - if (props.mode == 'html') { - this.plain2html($('#'+props.id).val(), props.id); - tinyMCE.execCommand('mceAddControl', false, props.id); - - if (this.env.default_font) - setTimeout(function() { - $(tinyMCE.get(props.id).getBody()).css('font-family', rcmail.env.default_font); - }, 500); - } - else { - var thisMCE = tinyMCE.get(props.id), existingHtml; - - if (existingHtml = thisMCE.getContent()) { - if (!confirm(this.get_label('editorwarning'))) { - return false; - } - this.html2plain(existingHtml, props.id); - } - tinyMCE.execCommand('mceRemoveControl', false, props.id); - } - - return true; - }; - - this.stop_spellchecking = function() - { - var ed; - - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) { - if (ed.plugins && ed.plugins.spellchecker && ed.plugins.spellchecker.active) - ed.execCommand('mceSpellCheck'); - } - else if (ed = this.env.spellcheck) { - if (ed.state && ed.state != 'ready' && ed.state != 'no_error_found') - $(ed.spell_span).trigger('click'); - } - - this.spellcheck_state(); - }; - - this.spellcheck_state = function() - { - var ed, active; - - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins && ed.plugins.spellchecker) - active = ed.plugins.spellchecker.active; - else if ((ed = this.env.spellcheck) && ed.state) - active = ed.state != 'ready' && ed.state != 'no_error_found'; - - if (rcmail.buttons.spellcheck) - $('#'+rcmail.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected'); - - return active; - }; - - // get selected language - this.spellcheck_lang = function() - { - var ed; - - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins && ed.plugins.spellchecker) - return ed.plugins.spellchecker.selectedLang; - else if (this.env.spellcheck) - return GOOGIE_CUR_LANG; - }; - - this.spellcheck_lang_set = function(lang) - { - var ed; - - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins) - ed.plugins.spellchecker.selectedLang = lang; - else if (this.env.spellcheck) - this.env.spellcheck.setCurrentLanguage(lang); - }; - - // resume spellchecking, highlight provided mispellings without new ajax request - this.spellcheck_resume = function(ishtml, data) - { - if (ishtml) { - var ed = tinyMCE.get(this.env.composebody); - sp = ed.plugins.spellchecker; - - sp.active = 1; - sp._markWords(data); - ed.nodeChanged(); - } - else { - var sp = this.env.spellcheck; - sp.prepare(false, true); - sp.processData(data); - } - - this.spellcheck_state(); - } - - this.set_draft_id = function(id) - { - var rc; - - if (!this.env.draft_id && id && (rc = this.opener())) { - // refresh the drafts folder in opener window - if (rc.env.task == 'mail' && rc.env.action == '' && rc.env.mailbox == this.env.drafts_mailbox) - rc.command('checkmail'); - } - - this.env.draft_id = id; - $("input[name='_draft_saveid']").val(id); - }; - - this.auto_save_start = function() - { - if (this.env.draft_autosave) - this.save_timer = setTimeout(function(){ ref.command("savedraft"); }, this.env.draft_autosave * 1000); - - // Unlock interface now that saving is complete - this.busy = false; - }; - - this.compose_field_hash = function(save) - { - // check input fields - var ed, i, val, str = '', hash_fields = ['to', 'cc', 'bcc', 'subject']; - - for (i=0; i<hash_fields.length; i++) - if (val = $('[name="_' + hash_fields[i] + '"]').val()) - str += val + ':'; - - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) - str += ed.getContent(); - else - str += $("[name='_message']").val(); - - if (this.env.attachments) - for (var upload_id in this.env.attachments) - str += upload_id; - - if (save) - this.cmp_hash = str; - - return str; - }; - - this.change_identity = function(obj, show_sig) - { - if (!obj || !obj.options) - return false; - - if (!show_sig) - show_sig = this.env.show_sig; - - // first function execution - if (!this.env.identities_initialized) { - this.env.identities_initialized = true; - if (this.env.show_sig_later) - this.env.show_sig = true; - if (this.env.opened_extwin) - return; - } - - var i, rx, cursor_pos, p = -1, - id = obj.options[obj.selectedIndex].value, - input_message = $("[name='_message']"), - message = input_message.val(), - is_html = ($("input[name='_is_html']").val() == '1'), - sig = this.env.identity, - delim = this.env.recipients_delimiter, - headers = ['replyto', 'bcc']; - - // update reply-to/bcc fields with addresses defined in identities - for (i in headers) { - var key = headers[i], - old_val = sig && this.env.identities[sig] ? this.env.identities[sig][key] : '', - new_val = id && this.env.identities[id] ? this.env.identities[id][key] : '', - input = $('[name="_'+key+'"]'), input_val = input.val(); - - // remove old address(es) - if (old_val && input_val) { - rx = new RegExp('\\s*' + RegExp.escape(old_val) + '\\s*'); - input_val = input_val.replace(rx, ''); - } - - // cleanup - rx = new RegExp(RegExp.escape(delim) + '\\s*' + RegExp(delim), 'g'); - input_val = input_val.replace(rx, delim) - rx = new RegExp('^\\s*' + RegExp.escape(delim) + '\\s*$'); - input_val = input_val.replace(rx, '') - - // add new address(es) - if (new_val) { - rx = new RegExp(RegExp.escape(delim) + '\\s*$'); - if (input_val && !rx.test(input_val)) - input_val += delim + ' '; - input_val += new_val + delim + ' '; - } - - if (old_val || new_val) - input.val(input_val).change(); - } - - // enable manual signature insert - if (this.env.signatures && this.env.signatures[id]) { - this.enable_command('insert-sig', true); - this.env.compose_commands.push('insert-sig'); - } - else - this.enable_command('insert-sig', false); - - if (!is_html) { - // remove the 'old' signature - if (show_sig && sig && this.env.signatures && this.env.signatures[sig]) { - sig = this.env.signatures[sig].text; - sig = sig.replace(/\r\n/g, '\n'); - - p = this.env.top_posting ? message.indexOf(sig) : message.lastIndexOf(sig); - if (p >= 0) - message = message.substring(0, p) + message.substring(p+sig.length, message.length); - } - // add the new signature string - if (show_sig && this.env.signatures && this.env.signatures[id]) { - sig = this.env.signatures[id].text; - sig = sig.replace(/\r\n/g, '\n'); - - if (this.env.top_posting) { - if (p >= 0) { // in place of removed signature - message = message.substring(0, p) + sig + message.substring(p, message.length); - cursor_pos = p - 1; - } - else if (!message) { // empty message - cursor_pos = 0; - message = '\n\n' + sig; - } - else if (pos = this.get_caret_pos(input_message.get(0))) { // at cursor position - message = message.substring(0, pos) + '\n' + sig + '\n\n' + message.substring(pos, message.length); - cursor_pos = pos; - } - else { // on top - cursor_pos = 0; - message = '\n\n' + sig + '\n\n' + message.replace(/^[\r\n]+/, ''); - } - } - else { - message = message.replace(/[\r\n]+$/, ''); - cursor_pos = !this.env.top_posting && message.length ? message.length+1 : 0; - message += '\n\n' + sig; - } - } - else - cursor_pos = this.env.top_posting ? 0 : message.length; - - input_message.val(message); - - // move cursor before the signature - this.set_caret_pos(input_message.get(0), cursor_pos); - } - else if (show_sig && this.env.signatures) { // html - var editor = tinyMCE.get(this.env.composebody), - sigElem = editor.dom.get('_rc_sig'); - - // Append the signature as a div within the body - if (!sigElem) { - var body = editor.getBody(), - doc = editor.getDoc(); - - sigElem = doc.createElement('div'); - sigElem.setAttribute('id', '_rc_sig'); - - if (this.env.top_posting) { - // if no existing sig and top posting then insert at caret pos - editor.getWin().focus(); // correct focus in IE & Chrome - - var node = editor.selection.getNode(); - if (node.nodeName == 'BODY') { - // no real focus, insert at start - body.insertBefore(sigElem, body.firstChild); - body.insertBefore(doc.createElement('br'), body.firstChild); - } - else { - body.insertBefore(sigElem, node.nextSibling); - body.insertBefore(doc.createElement('br'), node.nextSibling); - } - } - else { - if (bw.ie) // add empty line before signature on IE - body.appendChild(doc.createElement('br')); - - body.appendChild(sigElem); - } - } - - if (this.env.signatures[id]) - sigElem.innerHTML = this.env.signatures[id].html; - } - - this.env.identity = id; - return true; - }; - - // upload (attachment) file - this.upload_file = function(form, action) - { - if (!form) - return false; - - // count files and size on capable browser - var size = 0, numfiles = 0; - - $('input[type=file]', form).each(function(i, field) { - var files = field.files ? field.files.length : (field.value ? 1 : 0); - - // check file size - if (field.files) { - for (var i=0; i < files; i++) - size += field.files[i].size; - } - - numfiles += files; - }); - - // create hidden iframe and post upload form - if (numfiles) { - if (this.env.max_filesize && this.env.filesizeerror && size > this.env.max_filesize) { - this.display_message(this.env.filesizeerror, 'error'); - return; - } - - var frame_name = this.async_upload_form(form, action || 'upload', function(e) { - var d, content = ''; - try { - if (this.contentDocument) { - d = this.contentDocument; - } else if (this.contentWindow) { - d = this.contentWindow.document; - } - content = d.childNodes[0].innerHTML; - } catch (err) {} - - if (!content.match(/add2attachment/) && (!bw.opera || (rcmail.env.uploadframe && rcmail.env.uploadframe == e.data.ts))) { - if (!content.match(/display_message/)) - rcmail.display_message(rcmail.get_label('fileuploaderror'), 'error'); - rcmail.remove_from_attachment_list(e.data.ts); - } - // Opera hack: handle double onload - if (bw.opera) - rcmail.env.uploadframe = e.data.ts; - }); - - // display upload indicator and cancel button - var content = '<span>' + this.get_label('uploading' + (numfiles > 1 ? 'many' : '')) + '</span>', - ts = frame_name.replace(/^rcmupload/, ''); - - this.add2attachment_list(ts, { name:'', html:content, classname:'uploading', frame:frame_name, complete:false }); - - // upload progress support - if (this.env.upload_progress_time) { - this.upload_progress_start('upload', ts); - } - } - - // set reference to the form object - this.gui_objects.attachmentform = form; - return true; - }; - - // add file name to attachment list - // called from upload page - this.add2attachment_list = function(name, att, upload_id) - { - if (!this.gui_objects.attachmentlist) - return false; - - if (!att.complete && ref.env.loadingicon) - att.html = '<img src="'+ref.env.loadingicon+'" alt="" class="uploading" />' + att.html; - - if (!att.complete && att.frame) - att.html = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+name+'\', \''+att.frame+'\');" href="#cancelupload" class="cancelupload">' - + (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="" />' : this.get_label('cancel')) + '</a>' + att.html; - - var indicator, li = $('<li>').attr('id', name).addClass(att.classname).html(att.html); - - // replace indicator's li - if (upload_id && (indicator = document.getElementById(upload_id))) { - li.replaceAll(indicator); - } - else { // add new li - li.appendTo(this.gui_objects.attachmentlist); - } - - if (upload_id && this.env.attachments[upload_id]) - delete this.env.attachments[upload_id]; - - this.env.attachments[name] = att; - - return true; - }; - - this.remove_from_attachment_list = function(name) - { - delete this.env.attachments[name]; - $('#'+name).remove(); - }; - - this.remove_attachment = function(name) - { - if (name && this.env.attachments[name]) - this.http_post('remove-attachment', { _id:this.env.compose_id, _file:name }); - - return true; - }; - - this.cancel_attachment_upload = function(name, frame_name) - { - if (!name || !frame_name) - return false; - - this.remove_from_attachment_list(name); - $("iframe[name='"+frame_name+"']").remove(); - return false; - }; - - this.upload_progress_start = function(action, name) - { - setTimeout(function() { rcmail.http_request(action, {_progress: name}); }, - this.env.upload_progress_time * 1000); - }; - - this.upload_progress_update = function(param) - { - var elem = $('#'+param.name + '> span'); - - if (!elem.length || !param.text) - return; - - elem.text(param.text); - - if (!param.done) - this.upload_progress_start(param.action, param.name); - }; - - // send remote request to add a new contact - this.add_contact = function(value) - { - if (value) - this.http_post('addcontact', {_address: value}); - - return true; - }; - - // send remote request to search mail or contacts - this.qsearch = function(value) - { - if (value != '') { - var r, lock = this.set_busy(true, 'searching'), - url = this.search_params(value); - - if (this.message_list) - this.clear_message_list(); - else if (this.contact_list) - this.list_contacts_clear(); - - if (this.env.source) - url._source = this.env.source; - if (this.env.group) - url._gid = this.env.group; - - // reset vars - this.env.current_page = 1; - - var action = this.env.action == 'compose' && this.contact_list ? 'search-contacts' : 'search'; - r = this.http_request(action, url, lock); - - this.env.qsearch = {lock: lock, request: r}; - } - }; - - // build URL params for search - this.search_params = function(search, filter) - { - var n, url = {}, mods_arr = [], - mods = this.env.search_mods, - mbox = this.env.mailbox; - - if (!filter && this.gui_objects.search_filter) - filter = this.gui_objects.search_filter.value; - - if (!search && this.gui_objects.qsearchbox) - search = this.gui_objects.qsearchbox.value; - - if (filter) - url._filter = filter; - - if (search) { - url._q = search; - - if (mods && this.message_list) - mods = mods[mbox] ? mods[mbox] : mods['*']; - - if (mods) { - for (n in mods) - mods_arr.push(n); - url._headers = mods_arr.join(','); - } - } - - if (mbox) - url._mbox = mbox; - - return url; - }; - - // reset quick-search form - this.reset_qsearch = function() - { - if (this.gui_objects.qsearchbox) - this.gui_objects.qsearchbox.value = ''; - - if (this.env.qsearch) - this.abort_request(this.env.qsearch); - - this.env.qsearch = null; - this.env.search_request = null; - this.env.search_id = null; - }; - - this.sent_successfully = function(type, msg, folders) - { - this.display_message(msg, type); - - if (this.env.extwin) { - var rc = this.opener(); - this.lock_form(this.gui_objects.messageform); - if (rc) { - rc.display_message(msg, type); - // refresh the folder where sent message was saved or replied message comes from - if (folders && rc.env.task == 'mail' && rc.env.action == '' && $.inArray(rc.env.mailbox, folders) >= 0) { - // @TODO: try with 'checkmail' here when #1485186 is fixed. See also #1489249. - rc.command('list', rc.env.mailbox); - } - } - setTimeout(function(){ window.close() }, 1000); - } - else { - // before redirect we need to wait some time for Chrome (#1486177) - setTimeout(function(){ ref.list_mailbox(); }, 500); - } - }; - - - /*********************************************************/ - /********* keyboard live-search methods *********/ - /*********************************************************/ - - // handler for keyboard events on address-fields - this.ksearch_keydown = function(e, obj, props) - { - if (this.ksearch_timer) - clearTimeout(this.ksearch_timer); - - var highlight, - key = rcube_event.get_keycode(e), - mod = rcube_event.get_modifier(e); - - switch (key) { - case 38: // arrow up - case 40: // arrow down - if (!this.ksearch_visible()) - break; - - var dir = key==38 ? 1 : 0; - - highlight = document.getElementById('rcmksearchSelected'); - if (!highlight) - highlight = this.ksearch_pane.__ul.firstChild; - - if (highlight) - this.ksearch_select(dir ? highlight.previousSibling : highlight.nextSibling); - - return rcube_event.cancel(e); - - case 9: // tab - if (mod == SHIFT_KEY || !this.ksearch_visible()) { - this.ksearch_hide(); - return; - } - - case 13: // enter - if (!this.ksearch_visible()) - return false; - - // insert selected address and hide ksearch pane - this.insert_recipient(this.ksearch_selected); - this.ksearch_hide(); - - return rcube_event.cancel(e); - - case 27: // escape - this.ksearch_hide(); - return; - - case 37: // left - case 39: // right - if (mod != SHIFT_KEY) - return; - } - - // start timer - this.ksearch_timer = setTimeout(function(){ ref.ksearch_get_results(props); }, 200); - this.ksearch_input = obj; - - return true; - }; - - this.ksearch_visible = function() - { - return (this.ksearch_selected !== null && this.ksearch_selected !== undefined && this.ksearch_value); - }; - - this.ksearch_select = function(node) - { - var current = $('#rcmksearchSelected'); - if (current[0] && node) { - current.removeAttr('id').removeClass('selected'); - } - - if (node) { - $(node).attr('id', 'rcmksearchSelected').addClass('selected'); - this.ksearch_selected = node._rcm_id; - } - }; - - this.insert_recipient = function(id) - { - if (id === null || !this.env.contacts[id] || !this.ksearch_input) - return; - - // get cursor pos - var inp_value = this.ksearch_input.value, - cpos = this.get_caret_pos(this.ksearch_input), - p = inp_value.lastIndexOf(this.ksearch_value, cpos), - trigger = false, - insert = '', - // replace search string with full address - pre = inp_value.substring(0, p), - end = inp_value.substring(p+this.ksearch_value.length, inp_value.length); - - this.ksearch_destroy(); - - // insert all members of a group - if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) { - insert += this.env.contacts[id].name + this.env.recipients_delimiter; - this.group2expand[this.env.contacts[id].id] = $.extend({ input: this.ksearch_input }, this.env.contacts[id]); - this.http_request('mail/group-expand', {_source: this.env.contacts[id].source, _gid: this.env.contacts[id].id}, false); - } - else if (typeof this.env.contacts[id] === 'string') { - insert = this.env.contacts[id] + this.env.recipients_delimiter; - trigger = true; - } - - this.ksearch_input.value = pre + insert + end; - - // set caret to insert pos - cpos = p+insert.length; - if (this.ksearch_input.setSelectionRange) - this.ksearch_input.setSelectionRange(cpos, cpos); - - if (trigger) - this.triggerEvent('autocomplete_insert', { field:this.ksearch_input, insert:insert }); - }; - - this.replace_group_recipients = function(id, recipients) - { - if (this.group2expand[id]) { - this.group2expand[id].input.value = this.group2expand[id].input.value.replace(this.group2expand[id].name, recipients); - this.triggerEvent('autocomplete_insert', { field:this.group2expand[id].input, insert:recipients }); - this.group2expand[id] = null; - } - }; - - // address search processor - this.ksearch_get_results = function(props) - { - var inp_value = this.ksearch_input ? this.ksearch_input.value : null; - - if (inp_value === null) - return; - - if (this.ksearch_pane && this.ksearch_pane.is(":visible")) - this.ksearch_pane.hide(); - - // get string from current cursor pos to last comma - var cpos = this.get_caret_pos(this.ksearch_input), - p = inp_value.lastIndexOf(this.env.recipients_separator, cpos-1), - q = inp_value.substring(p+1, cpos), - min = this.env.autocomplete_min_length, - ac = this.ksearch_data; - - // trim query string - q = $.trim(q); - - // Don't (re-)search if the last results are still active - if (q == this.ksearch_value) - return; - - this.ksearch_destroy(); - - if (q.length && q.length < min) { - if (!this.ksearch_info) { - this.ksearch_info = this.display_message( - this.get_label('autocompletechars').replace('$min', min)); - } - return; - } - - var old_value = this.ksearch_value; - this.ksearch_value = q; - - // ...string is empty - if (!q.length) - return; - - // ...new search value contains old one and previous search was not finished or its result was empty - if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || ac.num <= 0) && this.env.contacts && !this.env.contacts.length) - return; - - var i, lock, source, xhr, reqid = new Date().getTime(), - post_data = {_search: q, _id: reqid}, - threads = props && props.threads ? props.threads : 1, - sources = props && props.sources ? props.sources : [], - action = props && props.action ? props.action : 'mail/autocomplete'; - - this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, - locks: [], requests: [], num: sources.length}; - - for (i=0; i<threads; i++) { - source = this.ksearch_data.sources.shift(); - if (threads > 1 && source === undefined) - break; - - post_data._source = source ? source : ''; - lock = this.display_message(this.get_label('searching'), 'loading'); - xhr = this.http_post(action, post_data, lock); - - this.ksearch_data.locks.push(lock); - this.ksearch_data.requests.push(xhr); - } - }; - - this.ksearch_query_results = function(results, search, reqid) - { - // search stopped in meantime? - if (!this.ksearch_value) - return; - - // ignore this outdated search response - if (this.ksearch_input && search != this.ksearch_value) - return; - - // display search results - var i, len, ul, li, text, init, - value = this.ksearch_value, - data = this.ksearch_data, - maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15; - - // create results pane if not present - if (!this.ksearch_pane) { - ul = $('<ul>'); - this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane') - .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); - this.ksearch_pane.__ul = ul[0]; - } - - ul = this.ksearch_pane.__ul; - - // remove all search results or add to existing list if parallel search - if (reqid && this.ksearch_pane.data('reqid') == reqid) { - maxlen -= ul.childNodes.length; - } - else { - this.ksearch_pane.data('reqid', reqid); - init = 1; - // reset content - ul.innerHTML = ''; - this.env.contacts = []; - // move the results pane right under the input box - var pos = $(this.ksearch_input).offset(); - this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'}); - } - - // add each result line to list - if (results && (len = results.length)) { - for (i=0; i < len && maxlen > 0; i++) { - text = typeof results[i] === 'object' ? results[i].name : results[i]; - li = document.createElement('LI'); - li.innerHTML = text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>'); - li.onmouseover = function(){ ref.ksearch_select(this); }; - li.onmouseup = function(){ ref.ksearch_click(this) }; - li._rcm_id = this.env.contacts.length + i; - ul.appendChild(li); - maxlen -= 1; - } - } - - if (ul.childNodes.length) { - this.ksearch_pane.show(); - // select the first - if (!this.env.contacts.length) { - $('li:first', ul).attr('id', 'rcmksearchSelected').addClass('selected'); - this.ksearch_selected = 0; - } - } - - if (len) - this.env.contacts = this.env.contacts.concat(results); - - // run next parallel search - if (data.id == reqid) { - data.num--; - if (maxlen > 0 && data.sources.length) { - var lock, xhr, source = data.sources.shift(), post_data; - if (source) { - post_data = {_search: value, _id: reqid, _source: source}; - lock = this.display_message(this.get_label('searching'), 'loading'); - xhr = this.http_post(data.action, post_data, lock); - - this.ksearch_data.locks.push(lock); - this.ksearch_data.requests.push(xhr); - } - } - else if (!maxlen) { - if (!this.ksearch_msg) - this.ksearch_msg = this.display_message(this.get_label('autocompletemore')); - // abort pending searches - this.ksearch_abort(); - } - } - }; - - this.ksearch_click = function(node) - { - if (this.ksearch_input) - this.ksearch_input.focus(); - - this.insert_recipient(node._rcm_id); - this.ksearch_hide(); - }; - - this.ksearch_blur = function() - { - if (this.ksearch_timer) - clearTimeout(this.ksearch_timer); - - this.ksearch_input = null; - this.ksearch_hide(); - }; - - this.ksearch_hide = function() - { - this.ksearch_selected = null; - this.ksearch_value = ''; - - if (this.ksearch_pane) - this.ksearch_pane.hide(); - - this.ksearch_destroy(); - }; - - // Clears autocomplete data/requests - this.ksearch_destroy = function() - { - this.ksearch_abort(); - - if (this.ksearch_info) - this.hide_message(this.ksearch_info); - - if (this.ksearch_msg) - this.hide_message(this.ksearch_msg); - - this.ksearch_data = null; - this.ksearch_info = null; - this.ksearch_msg = null; - } - - // Aborts pending autocomplete requests - this.ksearch_abort = function() - { - var i, len, ac = this.ksearch_data; - - if (!ac) - return; - - for (i=0, len=ac.locks.length; i<len; i++) - this.abort_request({request: ac.requests[i], lock: ac.locks[i]}); - }; - - - /*********************************************************/ - /********* address book methods *********/ - /*********************************************************/ - - this.contactlist_keypress = function(list) - { - if (list.key_pressed == list.DELETE_KEY) - this.command('delete'); - }; - - this.contactlist_select = function(list) - { - if (this.preview_timer) - clearTimeout(this.preview_timer); - - var n, id, sid, contact, ref = this, writable = false, - source = this.env.source ? this.env.address_sources[this.env.source] : null; - - // we don't have dblclick handler here, so use 200 instead of this.dblclick_time - if (id = list.get_single_selection()) - this.preview_timer = setTimeout(function(){ ref.load_contact(id, 'show'); }, 200); - else if (this.env.contentframe) - this.show_contentframe(false); - - if (list.selection.length) { - list.draggable = false; - - // no source = search result, we'll need to detect if any of - // selected contacts are in writable addressbook to enable edit/delete - // we'll also need to know sources used in selection for copy - // and group-addmember operations (drag&drop) - this.env.selection_sources = []; - - if (source) { - this.env.selection_sources.push(this.env.source); - } - - for (n in list.selection) { - contact = list.data[list.selection[n]]; - if (!source) { - sid = String(list.selection[n]).replace(/^[^-]+-/, ''); - if (sid && this.env.address_sources[sid]) { - writable = writable || (!this.env.address_sources[sid].readonly && !contact.readonly); - this.env.selection_sources.push(sid); - } - } - else { - writable = writable || (!source.readonly && !contact.readonly); - } - - if (contact._type != 'group') - list.draggable = true; - } - - this.env.selection_sources = $.unique(this.env.selection_sources); - } - - // if a group is currently selected, and there is at least one contact selected - // thend we can enable the group-remove-selected command - this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0 && writable); - this.enable_command('compose', this.env.group || list.selection.length > 0); - this.enable_command('export-selected', 'copy', list.selection.length > 0); - this.enable_command('edit', id && writable); - this.enable_command('delete', 'move', list.selection.length > 0 && writable); - - return false; - }; - - this.list_contacts = function(src, group, page) - { - var win, folder, url = {}, - target = window; - - if (!src) - src = this.env.source; - - if (page && this.current_page == page && src == this.env.source && group == this.env.group) - return false; - - if (src != this.env.source) { - page = this.env.current_page = 1; - this.reset_qsearch(); - } - else if (group != this.env.group) - page = this.env.current_page = 1; - - if (this.env.search_id) - folder = 'S'+this.env.search_id; - else if (!this.env.search_request) - folder = group ? 'G'+src+group : src; - - this.env.source = src; - this.env.group = group; - - // truncate groups listing stack - var index = $.inArray(this.env.group, this.env.address_group_stack); - if (index < 0) - this.env.address_group_stack = []; - else - this.env.address_group_stack = this.env.address_group_stack.slice(0,index); - - // make sure the current group is on top of the stack - if (this.env.group) { - this.env.address_group_stack.push(this.env.group); - - // mark the first group on the stack as selected in the directory list - folder = 'G'+src+this.env.address_group_stack[0]; - } - else if (this.gui_objects.addresslist_title) { - $(this.gui_objects.addresslist_title).html(this.get_label('contacts')); - } - - this.select_folder(folder, '', true); - - // load contacts remotely - if (this.gui_objects.contactslist) { - this.list_contacts_remote(src, group, page); - return; - } - - if (win = this.get_frame_window(this.env.contentframe)) { - target = win; - url._framed = 1; - } - - if (group) - url._gid = group; - if (page) - url._page = page; - if (src) - url._source = src; - - // also send search request to get the correct listing - if (this.env.search_request) - url._search = this.env.search_request; - - this.set_busy(true, 'loading'); - this.location_href(url, target); - }; - - // send remote request to load contacts list - this.list_contacts_remote = function(src, group, page) - { - // clear message list first - this.list_contacts_clear(); - - // send request to server - var url = {}, lock = this.set_busy(true, 'loading'); - - if (src) - url._source = src; - if (page) - url._page = page; - if (group) - url._gid = group; - - this.env.source = src; - this.env.group = group; - - // also send search request to get the right records - if (this.env.search_request) - url._search = this.env.search_request; - - this.http_request(this.env.task == 'mail' ? 'list-contacts' : 'list', url, lock); - }; - - this.list_contacts_clear = function() - { - this.contact_list.data = {}; - this.contact_list.clear(true); - this.show_contentframe(false); - this.enable_command('delete', 'move', 'copy', false); - this.enable_command('compose', this.env.group ? true : false); - }; - - this.set_group_prop = function(prop) - { - if (this.gui_objects.addresslist_title) { - var boxtitle = $(this.gui_objects.addresslist_title).html(''); // clear contents - - // add link to pop back to parent group - if (this.env.address_group_stack.length > 1) { - $('<a href="#list">...</a>') - .addClass('poplink') - .appendTo(boxtitle) - .click(function(e){ return ref.command('popgroup','',this); }); - boxtitle.append(' » '); - } - - boxtitle.append($('<span>'+prop.name+'</span>')); - } - - this.triggerEvent('groupupdate', prop); - }; - - // load contact record - this.load_contact = function(cid, action, framed) - { - var win, url = {}, target = window, - rec = this.contact_list ? this.contact_list.data[cid] : null; - - if (win = this.get_frame_window(this.env.contentframe)) { - url._framed = 1; - target = win; - this.show_contentframe(true); - - // load dummy content, unselect selected row(s) - if (!cid) - this.contact_list.clear_selection(); - - this.enable_command('compose', rec && rec.email); - this.enable_command('export-selected', rec && rec._type != 'group'); - } - else if (framed) - return false; - - if (action && (cid || action=='add') && !this.drag_active) { - if (this.env.group) - url._gid = this.env.group; - - url._action = action; - url._source = this.env.source; - url._cid = cid; - - this.location_href(url, target, true); - } - - return true; - }; - - // add/delete member to/from the group - this.group_member_change = function(what, cid, source, gid) - { - what = what == 'add' ? 'add' : 'del'; - var label = this.get_label(what == 'add' ? 'addingmember' : 'removingmember'), - lock = this.display_message(label, 'loading'), - post_data = {_cid: cid, _source: source, _gid: gid}; - - this.http_post('group-'+what+'members', post_data, lock); - }; - - this.contacts_drag_menu = function(e, to) - { - var dest = to.type == 'group' ? to.source : to.id, - source = this.env.source; - - if (!this.env.address_sources[dest] || this.env.address_sources[dest].readonly) - return true; - - // search result may contain contacts from many sources, but if there is only one... - if (source == '' && this.env.selection_sources.length == 1) - source = this.env.selection_sources[0]; - - if (to.type == 'group' && dest == source) { - var cid = this.contact_list.get_selection().join(','); - this.group_member_change('add', cid, dest, to.id); - return true; - } - // move action is not possible, "redirect" to copy if menu wasn't requested - else if (!this.commands.move && rcube_event.get_modifier(e) != SHIFT_KEY) { - this.copy_contacts(to); - return true; - } - - return this.drag_menu(e, to); - }; - - // copy contact(s) to the specified target (group or directory) - this.copy_contacts = function(to) - { - var n, dest = to.type == 'group' ? to.source : to.id, - source = this.env.source, - group = this.env.group ? this.env.group : '', - cid = this.contact_list.get_selection().join(','); - - if (!cid || !this.env.address_sources[dest] || this.env.address_sources[dest].readonly) - return; - - // search result may contain contacts from many sources, but if there is only one... - if (source == '' && this.env.selection_sources.length == 1) - source = this.env.selection_sources[0]; - - // tagret is a group - if (to.type == 'group') { - if (dest == source) - return; - - var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: this.env.source, _to: dest, _togid: to.id, _gid: group}; - - this.http_post('copy', post_data, lock); - } - // target is an addressbook - else if (to.id != source) { - var lock = this.display_message(this.get_label('copyingcontact'), 'loading'), - post_data = {_cid: cid, _source: this.env.source, _to: to.id, _gid: group}; - - this.http_post('copy', post_data, lock); - } - }; - - // move contact(s) to the specified target (group or directory) - this.move_contacts = function(to) - { - var dest = to.type == 'group' ? to.source : to.id, - source = this.env.source, - group = this.env.group ? this.env.group : ''; - - if (!this.env.address_sources[dest] || this.env.address_sources[dest].readonly) - return; - - // search result may contain contacts from many sources, but if there is only one... - if (source == '' && this.env.selection_sources.length == 1) - source = this.env.selection_sources[0]; - - if (to.type == 'group') { - if (dest == source) - return; - - this._with_selected_contacts('move', {_to: dest, _togid: to.id}); - } - // target is an addressbook - else if (to.id != source) - this._with_selected_contacts('move', {_to: to.id}); - }; - - // delete contact(s) - this.delete_contacts = function() - { - var undelete = this.env.source && this.env.address_sources[this.env.source].undelete; - - if (!undelete && !confirm(this.get_label('deletecontactconfirm'))) - return; - - return this._with_selected_contacts('delete'); - }; - - this._with_selected_contacts = function(action, post_data) - { - var selection = this.contact_list ? this.contact_list.get_selection() : []; - - // exit if no mailbox specified or if selection is empty - if (!selection.length && !this.env.cid) - return; - - var n, a_cids = [], - label = action == 'delete' ? 'contactdeleting' : 'movingcontact', - lock = this.display_message(this.get_label(label), 'loading'); - if (this.env.cid) - a_cids.push(this.env.cid); - else { - for (n=0; n<selection.length; n++) { - id = selection[n]; - a_cids.push(id); - this.contact_list.remove_row(id, (n == selection.length-1)); - } - - // hide content frame if we delete the currently displayed contact - if (selection.length == 1) - this.show_contentframe(false); - } - - if (!post_data) - post_data = {}; - - post_data._source = this.env.source; - post_data._from = this.env.action; - post_data._cid = a_cids.join(','); - - if (this.env.group) - post_data._gid = this.env.group; - - // also send search request to get the right records from the next page - if (this.env.search_request) - post_data._search = this.env.search_request; - - // send request to server - this.http_post(action, post_data, lock) - - return true; - }; - - // update a contact record in the list - this.update_contact_row = function(cid, cols_arr, newcid, source, data) - { - var c, row, list = this.contact_list; - - cid = this.html_identifier(cid); - - // when in searching mode, concat cid with the source name - if (!list.rows[cid]) { - cid = cid+'-'+source; - if (newcid) - newcid = newcid+'-'+source; - } - - list.update_row(cid, cols_arr, newcid, true); - list.data[cid] = data; - }; - - // add row to contacts list - this.add_contact_row = function(cid, cols, classes, data) - { - if (!this.gui_objects.contactslist) - return false; - - var c, col, list = this.contact_list, - row = { cols:[] }; - - row.id = 'rcmrow'+this.html_identifier(cid); - row.className = 'contact ' + (classes || ''); - - if (list.in_selection(cid)) - row.className += ' selected'; - - // add each submitted col - for (c in cols) { - col = {}; - col.className = String(c).toLowerCase(); - col.innerHTML = cols[c]; - row.cols.push(col); - } - - // store data in list member - list.data[cid] = data; - list.insert_row(row); - - this.enable_command('export', list.rowcount > 0); - }; - - this.init_contact_form = function() - { - var ref = this, col; - - if (this.env.coltypes) { - this.set_photo_actions($('#ff_photo').val()); - for (col in this.env.coltypes) - this.init_edit_field(col, null); - } - - $('.contactfieldgroup .row a.deletebutton').click(function() { - ref.delete_edit_field(this); - return false; - }); - - $('select.addfieldmenu').change(function(e) { - ref.insert_edit_field($(this).val(), $(this).attr('rel'), this); - this.selectedIndex = 0; - }); - - // enable date pickers on date fields - if ($.datepicker && this.env.date_format) { - $.datepicker.setDefaults({ - dateFormat: this.env.date_format, - changeMonth: true, - changeYear: true, - yearRange: '-100:+10', - showOtherMonths: true, - selectOtherMonths: true, - onSelect: function(dateText) { $(this).focus().val(dateText) } - }); - $('input.datepicker').datepicker(); - } - - $("input[type='text']:visible").first().focus(); - - // Submit search form on Enter - if (this.env.action == 'search') - $(this.gui_objects.editform).append($('<input type="submit">').hide()) - .submit(function() { $('input.mainaction').click(); return false; }); - }; - - this.group_create = function() - { - this.add_input_row('contactgroup'); - }; - - this.group_rename = function() - { - if (!this.env.group || !this.gui_objects.folderlist) - return; - - if (!this.name_input) { - this.enable_command('list', 'listgroup', false); - this.name_input = $('<input>').attr('type', 'text').val(this.env.contactgroups['G'+this.env.source+this.env.group].name); - this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); - this.env.group_renaming = true; - - var link, li = this.get_folder_li('G'+this.env.source+this.env.group,'',true); - if (li && (link = li.firstChild)) { - $(link).hide().before(this.name_input); - } - } - - this.name_input.select().focus(); - }; - - this.group_delete = function() - { - if (this.env.group && confirm(this.get_label('deletegroupconfirm'))) { - var lock = this.set_busy(true, 'groupdeleting'); - this.http_post('group-delete', {_source: this.env.source, _gid: this.env.group}, lock); - } - }; - - // callback from server upon group-delete command - this.remove_group_item = function(prop) - { - var key = 'G'+prop.source+prop.id; - if (this.treelist.remove(key)) { - delete this.env.contactfolders[key]; - delete this.env.contactgroups[key]; - } - - this.list_contacts(prop.source, 0); - }; - - // @TODO: maybe it would be better to use popup instead of inserting input to the list? - this.add_input_row = function(type) - { - if (!this.gui_objects.folderlist) - return; - - if (!this.name_input) { - this.name_input = $('<input>').attr('type', 'text').data('tt', type); - this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); - this.name_input_li = $('<li>').addClass(type).append(this.name_input); - - var ul, li; - - // find list (UL) element - if (type == 'contactsearch') - ul = this.gui_objects.folderlist; - else - ul = $('ul.groups', this.get_folder_li(this.env.source,'',true)); - - // append to the list - li = $('li:last', ul); - if (li.length) - this.name_input_li.insertAfter(li); - else { - this.name_input_li.appendTo(ul); - ul.show(); // make sure the list is visible - } - } - - this.name_input.select().focus(); - }; - - //remove selected contacts from current active group - this.group_remove_selected = function() - { - ref.http_post('group-delmembers', {_cid: this.contact_list.selection, - _source: this.env.source, _gid: this.env.group}); - }; - - //callback after deleting contact(s) from current group - this.remove_group_contacts = function(props) - { - if('undefined' != typeof this.env.group && (this.env.group === props.gid)){ - var n, selection = this.contact_list.get_selection(); - for (n=0; n<selection.length; n++) { - id = selection[n]; - this.contact_list.remove_row(id, (n == selection.length-1)); - } - } - } - - // handler for keyboard events on the input field - this.add_input_keydown = function(e) - { - var key = rcube_event.get_keycode(e), - input = $(e.target), itype = input.data('tt'); - - // enter - if (key == 13) { - var newname = input.val(); - - if (newname) { - var lock = this.set_busy(true, 'loading'); - - if (itype == 'contactsearch') - this.http_post('search-create', {_search: this.env.search_request, _name: newname}, lock); - else if (this.env.group_renaming) - this.http_post('group-rename', {_source: this.env.source, _gid: this.env.group, _name: newname}, lock); - else - this.http_post('group-create', {_source: this.env.source, _name: newname}, lock); - } - return false; - } - // escape - else if (key == 27) - this.reset_add_input(); - - return true; - }; - - this.reset_add_input = function() - { - if (this.name_input) { - var li = this.name_input.parent(); - if (this.env.group_renaming) { - li.children().last().show(); - this.env.group_renaming = false; - } - else if ($('li', li.parent()).length == 1) - li.parent().hide(); - - this.name_input.remove(); - - if (this.name_input_li) - this.name_input_li.remove(); - - this.name_input = this.name_input_li = null; - } - - this.enable_command('list', 'listgroup', true); - }; - - // callback for creating a new contact group - this.insert_contact_group = function(prop) - { - this.reset_add_input(); - - prop.type = 'group'; - var key = 'G'+prop.source+prop.id, - link = $('<a>').attr('href', '#') - .attr('rel', prop.source+':'+prop.id) - .click(function() { return rcmail.command('listgroup', prop, this); }) - .html(prop.name); - - this.env.contactfolders[key] = this.env.contactgroups[key] = prop; - this.treelist.insert({ id:key, html:link, classes:['contactgroup'] }, prop.source, true); - - this.triggerEvent('group_insert', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key) }); - }; - - // callback for renaming a contact group - this.update_contact_group = function(prop) - { - this.reset_add_input(); - - var key = 'G'+prop.source+prop.id, - newnode = {}; - - // group ID has changed, replace link node and identifiers - if (prop.newid) { - var newkey = 'G'+prop.source+prop.newid, - newprop = $.extend({}, prop); - - this.env.contactfolders[newkey] = this.env.contactfolders[key]; - this.env.contactfolders[newkey].id = prop.newid; - this.env.group = prop.newid; - - delete this.env.contactfolders[key]; - delete this.env.contactgroups[key]; - - newprop.id = prop.newid; - newprop.type = 'group'; - - newnode.id = newkey; - newnode.html = $('<a>').attr('href', '#') - .attr('rel', prop.source+':'+prop.newid) - .click(function() { return rcmail.command('listgroup', newprop, this); }) - .html(prop.name); - } - // update displayed group name - else { - $(this.treelist.get_item(key)).children().first().html(prop.name); - this.env.contactfolders[key].name = this.env.contactgroups[key].name = prop.name; - } - - // update list node and re-sort it - this.treelist.update(key, newnode, true); - - this.triggerEvent('group_update', { id:prop.id, source:prop.source, name:prop.name, li:this.treelist.get_item(key), newid:prop.newid }); - }; - - this.update_group_commands = function() - { - var source = this.env.source != '' ? this.env.address_sources[this.env.source] : null; - this.enable_command('group-create', (source && source.groups && !source.readonly)); - this.enable_command('group-rename', 'group-delete', (source && source.groups && this.env.group && !source.readonly)); - }; - - this.init_edit_field = function(col, elem) - { - var label = this.env.coltypes[col].label; - - if (!elem) - elem = $('.ff_' + col); - - if (label) - elem.placeholder(label); - }; - - this.insert_edit_field = function(col, section, menu) - { - // just make pre-defined input field visible - var elem = $('#ff_'+col); - if (elem.length) { - elem.show().focus(); - $(menu).children('option[value="'+col+'"]').prop('disabled', true); - } - else { - var lastelem = $('.ff_'+col), - appendcontainer = $('#contactsection'+section+' .contactcontroller'+col); - - if (!appendcontainer.length) { - var sect = $('#contactsection'+section), - lastgroup = $('.contactfieldgroup', sect).last(); - appendcontainer = $('<fieldset>').addClass('contactfieldgroup contactcontroller'+col); - if (lastgroup.length) - appendcontainer.insertAfter(lastgroup); - else - sect.prepend(appendcontainer); - } - - if (appendcontainer.length && appendcontainer.get(0).nodeName == 'FIELDSET') { - var input, colprop = this.env.coltypes[col], - row = $('<div>').addClass('row'), - cell = $('<div>').addClass('contactfieldcontent data'), - label = $('<div>').addClass('contactfieldlabel label'); - - if (colprop.subtypes_select) - label.html(colprop.subtypes_select); - else - label.html(colprop.label); - - var name_suffix = colprop.limit != 1 ? '[]' : ''; - if (colprop.type == 'text' || colprop.type == 'date') { - input = $('<input>') - .addClass('ff_'+col) - .attr({type: 'text', name: '_'+col+name_suffix, size: colprop.size}) - .appendTo(cell); - - this.init_edit_field(col, input); - - if (colprop.type == 'date' && $.datepicker) - input.datepicker(); - } - else if (colprop.type == 'textarea') { - input = $('<textarea>') - .addClass('ff_'+col) - .attr({ name: '_'+col+name_suffix, cols:colprop.size, rows:colprop.rows }) - .appendTo(cell); - - this.init_edit_field(col, input); - } - else if (colprop.type == 'composite') { - var childcol, cp, first, templ, cols = [], suffices = []; - // read template for composite field order - if ((templ = this.env[col+'_template'])) { - for (var j=0; j < templ.length; j++) { - cols.push(templ[j][1]); - suffices.push(templ[j][2]); - } - } - else { // list fields according to appearance in colprop - for (childcol in colprop.childs) - cols.push(childcol); - } - - for (var i=0; i < cols.length; i++) { - childcol = cols[i]; - cp = colprop.childs[childcol]; - input = $('<input>') - .addClass('ff_'+childcol) - .attr({ type: 'text', name: '_'+childcol+name_suffix, size: cp.size }) - .appendTo(cell); - cell.append(suffices[i] || " "); - this.init_edit_field(childcol, input); - if (!first) first = input; - } - input = first; // set focus to the first of this composite fields - } - else if (colprop.type == 'select') { - input = $('<select>') - .addClass('ff_'+col) - .attr('name', '_'+col+name_suffix) - .appendTo(cell); - - var options = input.attr('options'); - options[options.length] = new Option('---', ''); - if (colprop.options) - $.each(colprop.options, function(i, val){ options[options.length] = new Option(val, i); }); - } - - if (input) { - var delbutton = $('<a href="#del"></a>') - .addClass('contactfieldbutton deletebutton') - .attr({title: this.get_label('delete'), rel: col}) - .html(this.env.delbutton) - .click(function(){ ref.delete_edit_field(this); return false }) - .appendTo(cell); - - row.append(label).append(cell).appendTo(appendcontainer.show()); - input.first().focus(); - - // disable option if limit reached - if (!colprop.count) colprop.count = 0; - if (++colprop.count == colprop.limit && colprop.limit) - $(menu).children('option[value="'+col+'"]').prop('disabled', true); - } - } - } - }; - - this.delete_edit_field = function(elem) - { - var col = $(elem).attr('rel'), - colprop = this.env.coltypes[col], - fieldset = $(elem).parents('fieldset.contactfieldgroup'), - addmenu = fieldset.parent().find('select.addfieldmenu'); - - // just clear input but don't hide the last field - if (--colprop.count <= 0 && colprop.visible) - $(elem).parent().children('input').val('').blur(); - else { - $(elem).parents('div.row').remove(); - // hide entire fieldset if no more rows - if (!fieldset.children('div.row').length) - fieldset.hide(); - } - - // enable option in add-field selector or insert it if necessary - if (addmenu.length) { - var option = addmenu.children('option[value="'+col+'"]'); - if (option.length) - option.prop('disabled', false); - else - option = $('<option>').attr('value', col).html(colprop.label).appendTo(addmenu); - addmenu.show(); - } - }; - - this.upload_contact_photo = function(form) - { - if (form && form.elements._photo.value) { - this.async_upload_form(form, 'upload-photo', function(e) { - rcmail.set_busy(false, null, rcmail.file_upload_id); - }); - - // display upload indicator - this.file_upload_id = this.set_busy(true, 'uploading'); - } - }; - - this.replace_contact_photo = function(id) - { - var img_src = id == '-del-' ? this.env.photo_placeholder : - this.env.comm_path + '&_action=photo&_source=' + this.env.source + '&_cid=' + (this.env.cid || 0) + '&_photo=' + id; - - this.set_photo_actions(id); - $(this.gui_objects.contactphoto).children('img').attr('src', img_src); - }; - - this.photo_upload_end = function() - { - this.set_busy(false, null, this.file_upload_id); - delete this.file_upload_id; - }; - - this.set_photo_actions = function(id) - { - var n, buttons = this.buttons['upload-photo']; - for (n=0; buttons && n < buttons.length; n++) - $('a#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto')); - - $('#ff_photo').val(id); - this.enable_command('upload-photo', this.env.coltypes.photo ? true : false); - this.enable_command('delete-photo', this.env.coltypes.photo && id != '-del-'); - }; - - // load advanced search page - this.advanced_search = function() - { - var win, url = {_form: 1, _action: 'search'}, target = window; - - if (win = this.get_frame_window(this.env.contentframe)) { - url._framed = 1; - target = win; - this.contact_list.clear_selection(); - } - - this.location_href(url, target, true); - - return true; - }; - - // unselect directory/group - this.unselect_directory = function() - { - this.select_folder(''); - this.enable_command('search-delete', false); - }; - - // callback for creating a new saved search record - this.insert_saved_search = function(name, id) - { - this.reset_add_input(); - - var key = 'S'+id, - link = $('<a>').attr('href', '#') - .attr('rel', id) - .click(function() { return rcmail.command('listsearch', id, this); }) - .html(name), - prop = { name:name, id:id }; - - this.treelist.insert({ id:key, html:link, classes:['contactsearch'] }, null, 'contactsearch'); - this.select_folder(key,'',true); - this.enable_command('search-delete', true); - this.env.search_id = id; - - this.triggerEvent('abook_search_insert', prop); - }; - - // creates an input for saved search name - this.search_create = function() - { - this.add_input_row('contactsearch'); - }; - - this.search_delete = function() - { - if (this.env.search_request) { - var lock = this.set_busy(true, 'savedsearchdeleting'); - this.http_post('search-delete', {_sid: this.env.search_id}, lock); - } - }; - - // callback from server upon search-delete command - this.remove_search_item = function(id) - { - var li, key = 'S'+id; - if (this.treelist.remove(key)) { - this.triggerEvent('search_delete', { id:id, li:li }); - } - - this.env.search_id = null; - this.env.search_request = null; - this.list_contacts_clear(); - this.reset_qsearch(); - this.enable_command('search-delete', 'search-create', false); - }; - - this.listsearch = function(id) - { - var folder, lock = this.set_busy(true, 'searching'); - - if (this.contact_list) { - this.list_contacts_clear(); - } - - this.reset_qsearch(); - this.select_folder('S'+id, '', true); - - // reset vars - this.env.current_page = 1; - this.http_request('search', {_sid: id}, lock); - }; - - - /*********************************************************/ - /********* user settings methods *********/ - /*********************************************************/ - - // preferences section select and load options frame - this.section_select = function(list) - { - var win, id = list.get_single_selection(), target = window, - url = {_action: 'edit-prefs', _section: id}; - - if (id) { - if (win = this.get_frame_window(this.env.contentframe)) { - url._framed = 1; - target = win; - } - this.location_href(url, target, true); - } - - return true; - }; - - this.identity_select = function(list) - { - var id; - if (id = list.get_single_selection()) { - this.enable_command('delete', list.rowcount > 1 && this.env.identities_level < 2); - this.load_identity(id, 'edit-identity'); - } - }; - - // load identity record - this.load_identity = function(id, action) - { - if (action == 'edit-identity' && (!id || id == this.env.iid)) - return false; - - var win, target = window, - url = {_action: action, _iid: id}; - - if (win = this.get_frame_window(this.env.contentframe)) { - url._framed = 1; - target = win; - } - - if (action && (id || action == 'add-identity')) { - this.set_busy(true); - this.location_href(url, target); - } - - return true; - }; - - this.delete_identity = function(id) - { - // exit if no identity is specified or if selection is empty - var selection = this.identity_list.get_selection(); - if (!(selection.length || this.env.iid)) - return; - - if (!id) - id = this.env.iid ? this.env.iid : selection[0]; - - // submit request with appended token - if (confirm(this.get_label('deleteidentityconfirm'))) - this.goto_url('delete-identity', { _iid: id, _token: this.env.request_token }, true); - - return true; - }; - - this.update_identity_row = function(id, name, add) - { - var list = this.identity_list, - rid = this.html_identifier(id); - - if (add) { - list.insert_row({ id:'rcmrow'+rid, cols:[ { className:'mail', innerHTML:name } ] }); - list.select(rid); - } - else { - list.update_row(rid, [ name ]); - } - }; - - - /*********************************************************/ - /********* folder manager methods *********/ - /*********************************************************/ - - this.init_subscription_list = function() - { - var p = this; - this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, - {multiselect:false, draggable:true, keyboard:false, toggleselect:true}); - this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); }); - this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); - this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); }); - this.subscription_list.row_init = function (row) { - row.obj.onmouseover = function() { p.focus_subscription(row.id); }; - row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; - }; - this.subscription_list.init(); - $('#mailboxroot') - .mouseover(function(){ p.focus_subscription(this.id); }) - .mouseout(function(){ p.unfocus_subscription(this.id); }) - }; - - this.focus_subscription = function(id) - { - var row, folder, - delim = RegExp.escape(this.env.delimiter), - reg = RegExp('['+delim+']?[^'+delim+']+$'); - - if (this.drag_active && this.env.mailbox && (row = document.getElementById(id))) - if (this.env.subscriptionrows[id] && - (folder = this.env.subscriptionrows[id][0]) !== null - ) { - if (this.check_droptarget(folder) && - !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] && - (folder != this.env.mailbox.replace(reg, '')) && - (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter)))) - ) { - this.env.dstfolder = folder; - $(row).addClass('droptarget'); - } - } - }; - - this.unfocus_subscription = function(id) - { - var row = $('#'+id); - - this.env.dstfolder = null; - if (this.env.subscriptionrows[id] && row[0]) - row.removeClass('droptarget'); - else - $(this.subscription_list.frame).removeClass('droptarget'); - }; - - this.subscription_select = function(list) - { - var id, folder; - - if (list && (id = list.get_single_selection()) && - (folder = this.env.subscriptionrows['rcmrow'+id]) - ) { - this.env.mailbox = folder[0]; - this.show_folder(folder[0]); - this.enable_command('delete-folder', !folder[2]); - } - else { - this.env.mailbox = null; - this.show_contentframe(false); - this.enable_command('delete-folder', 'purge', false); - } - }; - - this.subscription_move_folder = function(list) - { - var delim = RegExp.escape(this.env.delimiter), - reg = RegExp('['+delim+']?[^'+delim+']+$'); - - if (this.env.mailbox && this.env.dstfolder !== null && (this.env.dstfolder != this.env.mailbox) && - (this.env.dstfolder != this.env.mailbox.replace(reg, '')) - ) { - reg = new RegExp('[^'+delim+']*['+delim+']', 'g'); - var basename = this.env.mailbox.replace(reg, ''), - newname = this.env.dstfolder === '' ? basename : this.env.dstfolder+this.env.delimiter+basename; - - if (newname != this.env.mailbox) { - this.http_post('rename-folder', {_folder_oldname: this.env.mailbox, _folder_newname: newname}, this.set_busy(true, 'foldermoving')); - this.subscription_list.draglayer.hide(); - } - } - this.drag_active = false; - this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder)); - }; - - // tell server to create and subscribe a new mailbox - this.create_folder = function() - { - this.show_folder('', this.env.mailbox); - }; - - // delete a specific mailbox with all its messages - this.delete_folder = function(name) - { - var id = this.get_folder_row_id(name ? name : this.env.mailbox), - folder = this.env.subscriptionrows[id][0]; - - if (folder && confirm(this.get_label('deletefolderconfirm'))) { - var lock = this.set_busy(true, 'folderdeleting'); - this.http_post('delete-folder', {_mbox: folder}, lock); - } - }; - - // Add folder row to the table and initialize it - this.add_folder_row = function (name, display_name, is_protected, subscribed, skip_init, class_name) - { - if (!this.gui_objects.subscriptionlist) - return false; - - var row, n, i, tmp, tmp_name, folders, rowid, list = [], slist = [], - tbody = this.gui_objects.subscriptionlist.tBodies[0], - refrow = $('tr', tbody).get(1), - id = 'rcmrow'+((new Date).getTime()); - - if (!refrow) { - // Refresh page if we don't have a table row to clone - this.goto_url('folders'); - return false; - } - - // clone a table row if there are existing rows - row = $(refrow).clone(true); - - // set ID, reset css class - row.attr('id', id); - row.attr('class', class_name); - - // set folder name - row.find('td:first').html(display_name); - - // update subscription checkbox - $('input[name="_subscribed[]"]', row).val(name) - .prop({checked: subscribed ? true : false, disabled: is_protected ? true : false}); - - // add to folder/row-ID map - this.env.subscriptionrows[id] = [name, display_name, 0]; - - // sort folders, to find a place where to insert the row - folders = []; - $.each(this.env.subscriptionrows, function(k,v){ folders.push(v) }); - folders.sort(function(a,b){ return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0) }); - - for (n in folders) { - // protected folder - if (folders[n][2]) { - tmp_name = folders[n][0] + this.env.delimiter; - // prefix namespace cannot have subfolders (#1488349) - if (tmp_name == this.env.prefix_ns) - continue; - slist.push(folders[n][0]); - tmp = tmp_name; - } - // protected folder's child - else if (tmp && folders[n][0].indexOf(tmp) == 0) - slist.push(folders[n][0]); - // other - else { - list.push(folders[n][0]); - tmp = null; - } - } - - // check if subfolder of a protected folder - for (n=0; n<slist.length; n++) { - if (name.indexOf(slist[n]+this.env.delimiter) == 0) - rowid = this.get_folder_row_id(slist[n]); - } - - // find folder position after sorting - for (n=0; !rowid && n<list.length; n++) { - if (n && list[n] == name) - rowid = this.get_folder_row_id(list[n-1]); - } - - // add row to the table - if (rowid) - $('#'+rowid).after(row); - else - row.appendTo(tbody); - - // update list widget - this.subscription_list.clear_selection(); - if (!skip_init) - this.init_subscription_list(); - - row = row.get(0); - if (row.scrollIntoView) - row.scrollIntoView(); - - return row; - }; - - // replace an existing table row with a new folder line (with subfolders) - this.replace_folder_row = function(oldfolder, newfolder, display_name, is_protected, class_name) - { - if (!this.gui_objects.subscriptionlist) - return false; - - var i, n, len, name, dispname, oldrow, tmprow, row, level, - tbody = this.gui_objects.subscriptionlist.tBodies[0], - folders = this.env.subscriptionrows, - id = this.get_folder_row_id(oldfolder), - regex = new RegExp('^'+RegExp.escape(oldfolder)), - subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'), - // find subfolders of renamed folder - list = this.get_subfolders(oldfolder); - - // replace an existing table row - this._remove_folder_row(id); - row = $(this.add_folder_row(newfolder, display_name, is_protected, subscribed, true, class_name)); - - // detect tree depth change - if (len = list.length) { - level = (oldfolder.split(this.env.delimiter)).length - (newfolder.split(this.env.delimiter)).length; - } - - // move subfolders to the new branch - for (n=0; n<len; n++) { - id = list[n]; - name = this.env.subscriptionrows[id][0]; - dispname = this.env.subscriptionrows[id][1]; - oldrow = $('#'+id); - tmprow = oldrow.clone(true); - oldrow.remove(); - row.after(tmprow); - row = tmprow; - // update folder index - name = name.replace(regex, newfolder); - $('input[name="_subscribed[]"]', row).val(name); - this.env.subscriptionrows[id][0] = name; - // update the name if level is changed - if (level != 0) { - if (level > 0) { - for (i=level; i>0; i--) - dispname = dispname.replace(/^ /, ''); - } - else { - for (i=level; i<0; i++) - dispname = ' ' + dispname; - } - row.find('td:first').html(dispname); - this.env.subscriptionrows[id][1] = dispname; - } - } - - // update list widget - this.init_subscription_list(); - }; - - // remove the table row of a specific mailbox from the table - this.remove_folder_row = function(folder, subs) - { - var n, len, list = [], id = this.get_folder_row_id(folder); - - // get subfolders if any - if (subs) - list = this.get_subfolders(folder); - - // remove old row - this._remove_folder_row(id); - - // remove subfolders - for (n=0, len=list.length; n<len; n++) - this._remove_folder_row(list[n]); - }; - - this._remove_folder_row = function(id) - { - this.subscription_list.remove_row(id.replace(/^rcmrow/, '')); - $('#'+id).remove(); - delete this.env.subscriptionrows[id]; - } - - this.get_subfolders = function(folder) - { - var name, list = [], - regex = new RegExp('^'+RegExp.escape(folder)+RegExp.escape(this.env.delimiter)), - row = $('#'+this.get_folder_row_id(folder)).get(0); - - while (row = row.nextSibling) { - if (row.id) { - name = this.env.subscriptionrows[row.id][0]; - if (regex.test(name)) { - list.push(row.id); - } - else - break; - } - } - - return list; - } - - this.subscribe = function(folder) - { - if (folder) { - var lock = this.display_message(this.get_label('foldersubscribing'), 'loading'); - this.http_post('subscribe', {_mbox: folder}, lock); - } - }; - - this.unsubscribe = function(folder) - { - if (folder) { - var lock = this.display_message(this.get_label('folderunsubscribing'), 'loading'); - this.http_post('unsubscribe', {_mbox: folder}, lock); - } - }; - - // helper method to find a specific mailbox row ID - this.get_folder_row_id = function(folder) - { - var id, folders = this.env.subscriptionrows; - for (id in folders) - if (folders[id] && folders[id][0] == folder) - break; - - return id; - }; - - // when user select a folder in manager - this.show_folder = function(folder, path, force) - { - var win, target = window, - url = '&_action=edit-folder&_mbox='+urlencode(folder); - - if (path) - url += '&_path='+urlencode(path); - - if (win = this.get_frame_window(this.env.contentframe)) { - target = win; - url += '&_framed=1'; - } - - if (String(target.location.href).indexOf(url) >= 0 && !force) - this.show_contentframe(true); - else - this.location_href(this.env.comm_path+url, target, true); - }; - - // disables subscription checkbox (for protected folder) - this.disable_subscription = function(folder) - { - var id = this.get_folder_row_id(folder); - if (id) - $('input[name="_subscribed[]"]', $('#'+id)).prop('disabled', true); - }; - - this.folder_size = function(folder) - { - var lock = this.set_busy(true, 'loading'); - this.http_post('folder-size', {_mbox: folder}, lock); - }; - - this.folder_size_update = function(size) - { - $('#folder-size').replaceWith(size); - }; - - - /*********************************************************/ - /********* GUI functionality *********/ - /*********************************************************/ - - var init_button = function(cmd, prop) - { - var elm = document.getElementById(prop.id); - if (!elm) - return; - - var preload = false; - if (prop.type == 'image') { - elm = elm.parentNode; - preload = true; - } - - elm._command = cmd; - elm._id = prop.id; - if (prop.sel) { - elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); }; - elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); }; - if (preload) - new Image().src = prop.sel; - } - if (prop.over) { - elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); }; - elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); }; - if (preload) - new Image().src = prop.over; - } - }; - - // set event handlers on registered buttons - this.init_buttons = function() - { - for (var cmd in this.buttons) { - if (typeof cmd !== 'string') - continue; - - for (var i=0; i<this.buttons[cmd].length; i++) { - init_button(cmd, this.buttons[cmd][i]); - } - } - - // set active task button - this.set_button(this.task, 'sel'); - }; - - // set button to a specific state - this.set_button = function(command, state) - { - var n, button, obj, a_buttons = this.buttons[command], - len = a_buttons ? a_buttons.length : 0; - - for (n=0; n<len; n++) { - button = a_buttons[n]; - obj = document.getElementById(button.id); - - if (!obj) - continue; - - // get default/passive setting of the button - if (button.type == 'image' && !button.status) { - button.pas = obj._original_src ? obj._original_src : obj.src; - // respect PNG fix on IE browsers - if (obj.runtimeStyle && obj.runtimeStyle.filter && obj.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/)) - button.pas = RegExp.$1; - } - else if (!button.status) - button.pas = String(obj.className); - - // set image according to button state - if (button.type == 'image' && button[state]) { - button.status = state; - obj.src = button[state]; - } - // set class name according to button state - else if (button[state] !== undefined) { - button.status = state; - obj.className = button[state]; - } - // disable/enable input buttons - if (button.type == 'input') { - button.status = state; - obj.disabled = !state; - } - } - }; - - // display a specific alttext - this.set_alttext = function(command, label) - { - var n, button, obj, link, a_buttons = this.buttons[command], - len = a_buttons ? a_buttons.length : 0; - - for (n=0; n<len; n++) { - button = a_buttons[n]; - obj = document.getElementById(button.id); - - if (button.type == 'image' && obj) { - obj.setAttribute('alt', this.get_label(label)); - if ((link = obj.parentNode) && link.tagName.toLowerCase() == 'a') - link.setAttribute('title', this.get_label(label)); - } - else if (obj) - obj.setAttribute('title', this.get_label(label)); - } - }; - - // mouse over button - this.button_over = function(command, id) - { - var n, button, obj, a_buttons = this.buttons[command], - len = a_buttons ? a_buttons.length : 0; - - for (n=0; n<len; n++) { - button = a_buttons[n]; - if (button.id == id && button.status == 'act') { - obj = document.getElementById(button.id); - if (obj && button.over) { - if (button.type == 'image') - obj.src = button.over; - else - obj.className = button.over; - } - } - } - }; - - // mouse down on button - this.button_sel = function(command, id) - { - var n, button, obj, a_buttons = this.buttons[command], - len = a_buttons ? a_buttons.length : 0; - - for (n=0; n<len; n++) { - button = a_buttons[n]; - if (button.id == id && button.status == 'act') { - obj = document.getElementById(button.id); - if (obj && button.sel) { - if (button.type == 'image') - obj.src = button.sel; - else - obj.className = button.sel; - } - this.buttons_sel[id] = command; - } - } - }; - - // mouse out of button - this.button_out = function(command, id) - { - var n, button, obj, a_buttons = this.buttons[command], - len = a_buttons ? a_buttons.length : 0; - - for (n=0; n<len; n++) { - button = a_buttons[n]; - if (button.id == id && button.status == 'act') { - obj = document.getElementById(button.id); - if (obj && button.act) { - if (button.type == 'image') - obj.src = button.act; - else - obj.className = button.act; - } - } - } - }; - - // write to the document/window title - this.set_pagetitle = function(title) - { - if (title && document.title) - document.title = title; - }; - - // display a system message, list of types in common.css (below #message definition) - this.display_message = function(msg, type, timeout) - { - // pass command to parent window - if (this.is_framed()) - return parent.rcmail.display_message(msg, type, timeout); - - if (!this.gui_objects.message) { - // save message in order to display after page loaded - if (type != 'loading') - this.pending_message = [msg, type, timeout]; - return 1; - } - - type = type ? type : 'notice'; - - var ref = this, - key = this.html_identifier(msg), - date = new Date(), - id = type + date.getTime(); - - if (!timeout) - timeout = this.message_time * (type == 'error' || type == 'warning' ? 2 : 1); - - if (type == 'loading') { - key = 'loading'; - timeout = this.env.request_timeout * 1000; - if (!msg) - msg = this.get_label('loading'); - } - - // The same message is already displayed - if (this.messages[key]) { - // replace label - if (this.messages[key].obj) - this.messages[key].obj.html(msg); - // store label in stack - if (type == 'loading') { - this.messages[key].labels.push({'id': id, 'msg': msg}); - } - // add element and set timeout - this.messages[key].elements.push(id); - setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout); - return id; - } - - // create DOM object and display it - var obj = $('<div>').addClass(type).html(msg).data('key', key), - cont = $(this.gui_objects.message).append(obj).show(); - - this.messages[key] = {'obj': obj, 'elements': [id]}; - - if (type == 'loading') { - this.messages[key].labels = [{'id': id, 'msg': msg}]; - } - else { - obj.click(function() { return ref.hide_message(obj); }); - } - - this.triggerEvent('message', { message:msg, type:type, timeout:timeout, object:obj }); - - if (timeout > 0) - setTimeout(function() { ref.hide_message(id, type == 'loading'); }, timeout); - return id; - }; - - // make a message to disapear - this.hide_message = function(obj, fade) - { - // pass command to parent window - if (this.is_framed()) - return parent.rcmail.hide_message(obj, fade); - - if (!this.gui_objects.message) - return; - - var k, n, i, o, m = this.messages; - - // Hide message by object, don't use for 'loading'! - if (typeof obj === 'object') { - o = $(obj); - k = o.data('key'); - this.hide_message_object(o, fade); - if (m[k]) - delete m[k]; - } - // Hide message by id - else { - for (k in m) { - for (n in m[k].elements) { - if (m[k] && m[k].elements[n] == obj) { - m[k].elements.splice(n, 1); - // hide DOM element if last instance is removed - if (!m[k].elements.length) { - this.hide_message_object(m[k].obj, fade); - delete m[k]; - } - // set pending action label for 'loading' message - else if (k == 'loading') { - for (i in m[k].labels) { - if (m[k].labels[i].id == obj) { - delete m[k].labels[i]; - } - else { - o = m[k].labels[i].msg; - m[k].obj.html(o); - } - } - } - } - } - } - } - }; - - // hide message object and remove from the DOM - this.hide_message_object = function(o, fade) - { - if (fade) - o.fadeOut(600, function() {$(this).remove(); }); - else - o.hide().remove(); - }; - - // remove all messages immediately - this.clear_messages = function() - { - // pass command to parent window - if (this.is_framed()) - return parent.rcmail.clear_messages(); - - var k, n, m = this.messages; - - for (k in m) - for (n in m[k].elements) - if (m[k].obj) - this.hide_message_object(m[k].obj); - - this.messages = {}; - }; - - // open a jquery UI dialog with the given content - this.show_popup_dialog = function(html, title, buttons) - { - // forward call to parent window - if (this.is_framed()) { - parent.rcmail.show_popup_dialog(html, title, buttons); - return; - } - - var popup = $('<div class="popup">') - .html(html) - .dialog({ - title: title, - buttons: buttons, - modal: true, - resizable: true, - width: 500, - close: function(event, ui) { $(this).remove() } - }); - - // resize and center popup - var win = $(window), w = win.width(), h = win.height(), - width = popup.width(), height = popup.height(); - - popup.dialog('option', { - height: Math.min(h - 40, height + 75 + (buttons ? 50 : 0)), - width: Math.min(w - 20, width + 20) - }); - }; - - // enable/disable buttons for page shifting - this.set_page_buttons = function() - { - this.enable_command('nextpage', 'lastpage', (this.env.pagecount > this.env.current_page)); - this.enable_command('previouspage', 'firstpage', (this.env.current_page > 1)); - }; - - // mark a mailbox as selected and set environment variable - this.select_folder = function(name, prefix, encode) - { - if (this.treelist) { - this.treelist.select(name); - } - else if (this.gui_objects.folderlist) { - var current_li, target_li; - - if ((current_li = $('li.selected', this.gui_objects.folderlist))) { - current_li.removeClass('selected').addClass('unfocused'); - } - if ((target_li = this.get_folder_li(name, prefix, encode))) { - $(target_li).removeClass('unfocused').addClass('selected'); - } - - // trigger event hook - this.triggerEvent('selectfolder', { folder:name, prefix:prefix }); - } - }; - - // adds a class to selected folder - this.mark_folder = function(name, class_name, prefix, encode) - { - $(this.get_folder_li(name, prefix, encode)).addClass(class_name); - }; - - // adds a class to selected folder - this.unmark_folder = function(name, class_name, prefix, encode) - { - $(this.get_folder_li(name, prefix, encode)).removeClass(class_name); - }; - - // helper method to find a folder list item - this.get_folder_li = function(name, prefix, encode) - { - if (!prefix) - prefix = 'rcmli'; - - if (this.gui_objects.folderlist) { - name = this.html_identifier(name, encode); - return document.getElementById(prefix+name); - } - - return null; - }; - - // for reordering column array (Konqueror workaround) - // and for setting some message list global variables - this.set_message_coltypes = function(coltypes, repl, smart_col) - { - var list = this.message_list, - thead = list ? list.thead : null, - cell, col, n, len, th, tr; - - this.env.coltypes = coltypes; - - // replace old column headers - if (thead) { - if (repl) { - th = document.createElement('thead'); - tr = document.createElement('tr'); - - for (c=0, len=repl.length; c < len; c++) { - cell = document.createElement('td'); - cell.innerHTML = repl[c].html || ''; - if (repl[c].id) cell.id = repl[c].id; - if (repl[c].className) cell.className = repl[c].className; - tr.appendChild(cell); - } - th.appendChild(tr); - thead.parentNode.replaceChild(th, thead); - list.thead = thead = th; - } - - for (n=0, len=this.env.coltypes.length; n<len; n++) { - col = this.env.coltypes[n]; - if ((cell = thead.rows[0].cells[n]) && (col == 'from' || col == 'to' || col == 'fromto')) { - cell.id = 'rcm'+col; - $('span,a', cell).text(this.get_label(col == 'fromto' ? smart_col : col)); - // if we have links for sorting, it's a bit more complicated... - $('a', cell).click(function(){ - return rcmail.command('sort', this.id.replace(/^rcm/, ''), this); - }); - } - } - } - - this.env.subject_col = null; - this.env.flagged_col = null; - this.env.status_col = null; - - if ((n = $.inArray('subject', this.env.coltypes)) >= 0) { - this.env.subject_col = n; - if (list) - list.subject_col = n; - } - if ((n = $.inArray('flag', this.env.coltypes)) >= 0) - this.env.flagged_col = n; - if ((n = $.inArray('status', this.env.coltypes)) >= 0) - this.env.status_col = n; - - if (list) - list.init_header(); - }; - - // replace content of row count display - this.set_rowcount = function(text, mbox) - { - // #1487752 - if (mbox && mbox != this.env.mailbox) - return false; - - $(this.gui_objects.countdisplay).html(text); - - // update page navigation buttons - this.set_page_buttons(); - }; - - // replace content of mailboxname display - this.set_mailboxname = function(content) - { - if (this.gui_objects.mailboxname && content) - this.gui_objects.mailboxname.innerHTML = content; - }; - - // replace content of quota display - this.set_quota = function(content) - { - if (this.gui_objects.quotadisplay && content && content.type == 'text') - $(this.gui_objects.quotadisplay).html(content.percent+'%').attr('title', content.title); - - this.triggerEvent('setquota', content); - this.env.quota_content = content; - }; - - // update the mailboxlist - this.set_unread_count = function(mbox, count, set_title, mark) - { - if (!this.gui_objects.mailboxlist) - return false; - - this.env.unread_counts[mbox] = count; - this.set_unread_count_display(mbox, set_title); - - if (mark) - this.mark_folder(mbox, mark, '', true); - else if (!count) - this.unmark_folder(mbox, 'recent', '', true); - }; - - // update the mailbox count display - this.set_unread_count_display = function(mbox, set_title) - { - var reg, link, text_obj, item, mycount, childcount, div; - - if (item = this.get_folder_li(mbox, '', true)) { - mycount = this.env.unread_counts[mbox] ? this.env.unread_counts[mbox] : 0; - link = $(item).children('a').eq(0); - text_obj = link.children('span.unreadcount'); - if (!text_obj.length && mycount) - text_obj = $('<span>').addClass('unreadcount').appendTo(link); - reg = /\s+\([0-9]+\)$/i; - - childcount = 0; - if ((div = item.getElementsByTagName('div')[0]) && - div.className.match(/collapsed/)) { - // add children's counters - for (var k in this.env.unread_counts) - if (k.indexOf(mbox + this.env.delimiter) == 0) - childcount += this.env.unread_counts[k]; - } - - if (mycount && text_obj.length) - text_obj.html(this.env.unreadwrap.replace(/%[sd]/, mycount)); - else if (text_obj.length) - text_obj.remove(); - - // set parent's display - reg = new RegExp(RegExp.escape(this.env.delimiter) + '[^' + RegExp.escape(this.env.delimiter) + ']+$'); - if (mbox.match(reg)) - this.set_unread_count_display(mbox.replace(reg, ''), false); - - // set the right classes - if ((mycount+childcount)>0) - $(item).addClass('unread'); - else - $(item).removeClass('unread'); - } - - // set unread count to window title - reg = /^\([0-9]+\)\s+/i; - if (set_title && document.title) { - var new_title = '', - doc_title = String(document.title); - - if (mycount && doc_title.match(reg)) - new_title = doc_title.replace(reg, '('+mycount+') '); - else if (mycount) - new_title = '('+mycount+') '+doc_title; - else - new_title = doc_title.replace(reg, ''); - - this.set_pagetitle(new_title); - } - }; - - // display fetched raw headers - this.set_headers = function(content) - { - if (this.gui_objects.all_headers_row && this.gui_objects.all_headers_box && content) - $(this.gui_objects.all_headers_box).html(content).show(); - }; - - // display all-headers row and fetch raw message headers - this.show_headers = function(props, elem) - { - if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box || !this.env.uid) - return; - - $(elem).removeClass('show-headers').addClass('hide-headers'); - $(this.gui_objects.all_headers_row).show(); - elem.onclick = function() { rcmail.command('hide-headers', '', elem); }; - - // fetch headers only once - if (!this.gui_objects.all_headers_box.innerHTML) { - var lock = this.display_message(this.get_label('loading'), 'loading'); - this.http_post('headers', {_uid: this.env.uid}, lock); - } - }; - - // hide all-headers row - this.hide_headers = function(props, elem) - { - if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box) - return; - - $(elem).removeClass('hide-headers').addClass('show-headers'); - $(this.gui_objects.all_headers_row).hide(); - elem.onclick = function() { rcmail.command('show-headers', '', elem); }; - }; - - - /********************************************************/ - /********* html to text conversion functions *********/ - /********************************************************/ - - this.html2plain = function(htmlText, id) - { - var rcmail = this, - url = '?_task=utils&_action=html2text', - lock = this.set_busy(true, 'converting'); - - this.log('HTTP POST: ' + url); - - $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream', - error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }, - success: function(data) { rcmail.set_busy(false, null, lock); $('#'+id).val(data); rcmail.log(data); } - }); - }; - - this.plain2html = function(plain, id) - { - var lock = this.set_busy(true, 'converting'); - - plain = plain.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); - $('#'+id).val(plain ? '<pre>'+plain+'</pre>' : ''); - - this.set_busy(false, null, lock); - }; - - - /********************************************************/ - /********* remote request methods *********/ - /********************************************************/ - - // compose a valid url with the given parameters - this.url = function(action, query) - { - var querystring = typeof query === 'string' ? '&' + query : ''; - - if (typeof action !== 'string') - query = action; - else if (!query || typeof query !== 'object') - query = {}; - - if (action) - query._action = action; - else - query._action = this.env.action; - - var base = this.env.comm_path, k, param = {}; - - // overwrite task name - if (query._action.match(/([a-z0-9_-]+)\/([a-z0-9-_.]+)/)) { - query._action = RegExp.$2; - base = base.replace(/\_task=[a-z0-9_-]+/, '_task='+RegExp.$1); - } - - // remove undefined values - for (k in query) { - if (query[k] !== undefined && query[k] !== null) - param[k] = query[k]; - } - - return base + '&' + $.param(param) + querystring; - }; - - this.redirect = function(url, lock) - { - if (lock || lock === null) - this.set_busy(true); - - if (this.is_framed()) { - parent.rcmail.redirect(url, lock); - } - else { - if (this.env.extwin) { - if (typeof url == 'string') - url += (url.indexOf('?') < 0 ? '?' : '&') + '_extwin=1'; - else - url._extwin = 1; - } - this.location_href(url, window); - } - }; - - this.goto_url = function(action, query, lock) - { - this.redirect(this.url(action, query)); - }; - - this.location_href = function(url, target, frame) - { - if (frame) - this.lock_frame(); - - if (typeof url == 'object') - url = this.env.comm_path + '&' + $.param(url); - - // simulate real link click to force IE to send referer header - if (bw.ie && target == window) - $('<a>').attr('href', url).appendTo(document.body).get(0).click(); - else - target.location.href = url; - - // reset keep-alive interval - this.start_keepalive(); - }; - - // send a http request to the server - this.http_request = function(action, query, lock) - { - var url = this.url(action, query); - - // trigger plugin hook - var result = this.triggerEvent('request'+action, query); - - if (result !== undefined) { - // abort if one the handlers returned false - if (result === false) - return false; - else - query = result; - } - - url += '&_remote=1'; - - // send request - this.log('HTTP GET: ' + url); - - // reset keep-alive interval - this.start_keepalive(); - - return $.ajax({ - type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', - success: function(data){ ref.http_response(data); }, - error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } - }); - }; - - // send a http POST request to the server - this.http_post = function(action, postdata, lock) - { - var url = this.url(action); - - if (postdata && typeof postdata === 'object') { - postdata._remote = 1; - postdata._unlock = (lock ? lock : 0); - } - else - postdata += (postdata ? '&' : '') + '_remote=1' + (lock ? '&_unlock='+lock : ''); - - // trigger plugin hook - var result = this.triggerEvent('request'+action, postdata); - if (result !== undefined) { - // abort if one of the handlers returned false - if (result === false) - return false; - else - postdata = result; - } - - // send request - this.log('HTTP POST: ' + url); - - // reset keep-alive interval - this.start_keepalive(); - - return $.ajax({ - type: 'POST', url: url, data: postdata, dataType: 'json', - success: function(data){ ref.http_response(data); }, - error: function(o, status, err) { ref.http_error(o, status, err, lock, action); } - }); - }; - - // aborts ajax request - this.abort_request = function(r) - { - if (r.request) - r.request.abort(); - if (r.lock) - this.set_busy(false, null, r.lock); - }; - - // handle HTTP response - this.http_response = function(response) - { - if (!response) - return; - - if (response.unlock) - this.set_busy(false); - - this.triggerEvent('responsebefore', {response: response}); - this.triggerEvent('responsebefore'+response.action, {response: response}); - - // set env vars - if (response.env) - this.set_env(response.env); - - // we have labels to add - if (typeof response.texts === 'object') { - for (var name in response.texts) - if (typeof response.texts[name] === 'string') - this.add_label(name, response.texts[name]); - } - - // if we get javascript code from server -> execute it - if (response.exec) { - this.log(response.exec); - eval(response.exec); - } - - // execute callback functions of plugins - if (response.callbacks && response.callbacks.length) { - for (var i=0; i < response.callbacks.length; i++) - this.triggerEvent(response.callbacks[i][0], response.callbacks[i][1]); - } - - // process the response data according to the sent action - switch (response.action) { - case 'delete': - if (this.task == 'addressbook') { - var sid, uid = this.contact_list.get_selection(), writable = false; - - if (uid && this.contact_list.rows[uid]) { - // search results, get source ID from record ID - if (this.env.source == '') { - sid = String(uid).replace(/^[^-]+-/, ''); - writable = sid && this.env.address_sources[sid] && !this.env.address_sources[sid].readonly; - } - else { - writable = !this.env.address_sources[this.env.source].readonly; - } - } - this.enable_command('compose', (uid && this.contact_list.rows[uid])); - this.enable_command('delete', 'edit', writable); - this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); - this.enable_command('export-selected', false); - } - - case 'move': - if (this.env.action == 'show') { - // re-enable commands on move/delete error - this.enable_command(this.env.message_commands, true); - if (!this.env.list_post) - this.enable_command('reply-list', false); - } - else if (this.task == 'addressbook') { - this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); - } - - case 'purge': - case 'expunge': - if (this.task == 'mail') { - if (!this.env.exists) { - // clear preview pane content - if (this.env.contentframe) - this.show_contentframe(false); - // disable commands useless when mailbox is empty - this.enable_command(this.env.message_commands, 'purge', 'expunge', - 'select-all', 'select-none', 'expand-all', 'expand-unread', 'collapse-all', false); - } - if (this.message_list) - this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); - } - break; - - case 'refresh': - case 'check-recent': - case 'getunread': - case 'search': - this.env.qsearch = null; - case 'list': - if (this.task == 'mail') { - this.enable_command('show', 'select-all', 'select-none', this.env.messagecount > 0); - this.enable_command('expunge', this.env.exists); - this.enable_command('purge', this.purge_mailbox_test()); - this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount); - - if ((response.action == 'list' || response.action == 'search') && this.message_list) { - this.msglist_select(this.message_list); - this.message_list.resize(); - this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); - } - } - else if (this.task == 'addressbook') { - this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); - - if (response.action == 'list' || response.action == 'search') { - this.enable_command('search-create', this.env.source == ''); - this.enable_command('search-delete', this.env.search_id); - this.update_group_commands(); - this.contact_list.resize(); - this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount }); - } - } - break; - } - - if (response.unlock) - this.hide_message(response.unlock); - - this.triggerEvent('responseafter', {response: response}); - this.triggerEvent('responseafter'+response.action, {response: response}); - - // reset keep-alive interval - this.start_keepalive(); - }; - - // handle HTTP request errors - this.http_error = function(request, status, err, lock, action) - { - var errmsg = request.statusText; - - this.set_busy(false, null, lock); - request.abort(); - - // don't display error message on page unload (#1488547) - if (this.unload) - return; - - if (request.status && errmsg) - this.display_message(this.get_label('servererror') + ' (' + errmsg + ')', 'error'); - else if (status == 'timeout') - this.display_message(this.get_label('requesttimedout'), 'error'); - else if (request.status == 0 && status != 'abort') - this.display_message(this.get_label('servererror') + ' (No connection)', 'error'); - - // redirect to url specified in location header if not empty - var location_url = request.getResponseHeader("Location"); - if (location_url && this.env.action != 'compose') // don't redirect on compose screen, contents might get lost (#1488926) - this.redirect(location_url); - - // 403 Forbidden response (CSRF prevention) - reload the page. - // In case there's a new valid session it will be used, otherwise - // login form will be presented (#1488960). - if (request.status == 403) { - (this.is_framed() ? parent : window).location.reload(); - return; - } - - // re-send keep-alive requests after 30 seconds - if (action == 'keep-alive') - setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000); - }; - - // callback when an iframe finished loading - this.iframe_loaded = function(unlock) - { - this.set_busy(false, null, unlock); - - if (this.submit_timer) - clearTimeout(this.submit_timer); - }; - - // post the given form to a hidden iframe - this.async_upload_form = function(form, action, onload) - { - var ts = new Date().getTime(), - frame_name = 'rcmupload'+ts; - - // upload progress support - if (this.env.upload_progress_name) { - var fname = this.env.upload_progress_name, - field = $('input[name='+fname+']', form); - - if (!field.length) { - field = $('<input>').attr({type: 'hidden', name: fname}); - field.prependTo(form); - } - - field.val(ts); - } - - // have to do it this way for IE - // otherwise the form will be posted to a new window - if (document.all) { - var html = '<iframe name="'+frame_name+'" src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'; - document.body.insertAdjacentHTML('BeforeEnd', html); - } - else { // for standards-compilant browsers - var frame = document.createElement('iframe'); - frame.name = frame_name; - frame.style.border = 'none'; - frame.style.width = 0; - frame.style.height = 0; - frame.style.visibility = 'hidden'; - document.body.appendChild(frame); - } - - // handle upload errors, parsing iframe content in onload - $(frame_name).bind('load', {ts:ts}, onload); - - $(form).attr({ - target: frame_name, - action: this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }), - method: 'POST'}) - .attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data') - .submit(); - - return frame_name; - }; - - // html5 file-drop API - this.document_drag_hover = function(e, over) - { - e.preventDefault(); - $(ref.gui_objects.filedrop)[(over?'addClass':'removeClass')]('active'); - }; - - this.file_drag_hover = function(e, over) - { - e.preventDefault(); - e.stopPropagation(); - $(ref.gui_objects.filedrop)[(over?'addClass':'removeClass')]('hover'); - }; - - // handler when files are dropped to a designated area. - // compose a multipart form data and submit it to the server - this.file_dropped = function(e) - { - // abort event and reset UI - this.file_drag_hover(e, false); - - // prepare multipart form data composition - var files = e.target.files || e.dataTransfer.files, - formdata = window.FormData ? new FormData() : null, - fieldname = (this.env.filedrop.fieldname || '_file') + (this.env.filedrop.single ? '' : '[]'), - boundary = '------multipartformboundary' + (new Date).getTime(), - dashdash = '--', crlf = '\r\n', - multipart = dashdash + boundary + crlf; - - if (!files || !files.length) - return; - - // inline function to submit the files to the server - var submit_data = function() { - var multiple = files.length > 1, - ts = new Date().getTime(), - content = '<span>' + (multiple ? ref.get_label('uploadingmany') : files[0].name) + '</span>'; - - // add to attachments list - if (!ref.add2attachment_list(ts, { name:'', html:content, classname:'uploading', complete:false })) - ref.file_upload_id = ref.set_busy(true, 'uploading'); - - // complete multipart content and post request - multipart += dashdash + boundary + dashdash + crlf; - - $.ajax({ - type: 'POST', - dataType: 'json', - url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||ref.env.cid||'', _uploadid:ts, _remote:1 }), - contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary, - processData: false, - timeout: 0, // disable default timeout set in ajaxSetup() - data: formdata || multipart, - headers: {'X-Roundcube-Request': ref.env.request_token}, - xhr: function() { var xhr = jQuery.ajaxSettings.xhr(); if (!formdata && xhr.sendAsBinary) xhr.send = xhr.sendAsBinary; return xhr; }, - success: function(data){ ref.http_response(data); }, - error: function(o, status, err) { ref.http_error(o, status, err, null, 'attachment'); } - }); - }; - - // get contents of all dropped files - var last = this.env.filedrop.single ? 0 : files.length - 1; - for (var j=0, i=0, f; j <= last && (f = files[i]); i++) { - if (!f.name) f.name = f.fileName; - if (!f.size) f.size = f.fileSize; - if (!f.type) f.type = 'application/octet-stream'; - - // file name contains non-ASCII characters, do UTF8-binary string conversion. - if (!formdata && /[^\x20-\x7E]/.test(f.name)) - f.name_bin = unescape(encodeURIComponent(f.name)); - - // filter by file type if requested - if (this.env.filedrop.filter && !f.type.match(new RegExp(this.env.filedrop.filter))) { - // TODO: show message to user - continue; - } - - // do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+) - if (formdata) { - formdata.append(fieldname, f); - if (j == last) - return submit_data(); - } - // use FileReader supporetd by Firefox 3.6 - else if (window.FileReader) { - var reader = new FileReader(); - - // closure to pass file properties to async callback function - reader.onload = (function(file, j) { - return function(e) { - multipart += 'Content-Disposition: form-data; name="' + fieldname + '"'; - multipart += '; filename="' + (f.name_bin || file.name) + '"' + crlf; - multipart += 'Content-Length: ' + file.size + crlf; - multipart += 'Content-Type: ' + file.type + crlf + crlf; - multipart += reader.result + crlf; - multipart += dashdash + boundary + crlf; - - if (j == last) // we're done, submit the data - return submit_data(); - } - })(f,j); - reader.readAsBinaryString(f); - } - // Firefox 3 - else if (f.getAsBinary) { - multipart += 'Content-Disposition: form-data; name="' + fieldname + '"'; - multipart += '; filename="' + (f.name_bin || f.name) + '"' + crlf; - multipart += 'Content-Length: ' + f.size + crlf; - multipart += 'Content-Type: ' + f.type + crlf + crlf; - multipart += f.getAsBinary() + crlf; - multipart += dashdash + boundary +crlf; - - if (j == last) - return submit_data(); - } - - j++; - } - }; - - // starts interval for keep-alive signal - this.start_keepalive = function() - { - if (!this.env.session_lifetime || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') - return; - - if (this._keepalive) - clearInterval(this._keepalive); - - this._keepalive = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000); - }; - - // starts interval for refresh signal - this.start_refresh = function() - { - if (!this.env.refresh_interval || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print') - return; - - if (this._refresh) - clearInterval(this._refresh); - - this._refresh = setInterval(function(){ ref.refresh(); }, this.env.refresh_interval * 1000); - }; - - // sends keep-alive signal - this.keep_alive = function() - { - if (!this.busy) - this.http_request('keep-alive'); - }; - - // sends refresh signal - this.refresh = function() - { - if (this.busy) { - // try again after 10 seconds - setTimeout(function(){ ref.refresh(); ref.start_refresh(); }, 10000); - return; - } - - var params = {}, lock = this.set_busy(true, 'refreshing'); - - if (this.task == 'mail' && this.gui_objects.mailboxlist) - params = this.check_recent_params(); - - // plugins should bind to 'requestrefresh' event to add own params - this.http_request('refresh', params, lock); - }; - - // returns check-recent request parameters - this.check_recent_params = function() - { - var params = {_mbox: this.env.mailbox}; - - if (this.gui_objects.mailboxlist) - params._folderlist = 1; - if (this.gui_objects.messagelist) - params._list = 1; - if (this.gui_objects.quotadisplay) - params._quota = 1; - if (this.env.search_request) - params._search = this.env.search_request; - - return params; - }; - - - /********************************************************/ - /********* helper methods *********/ - /********************************************************/ - - // get window.opener.rcmail if available - this.opener = function() - { - // catch Error: Permission denied to access property rcmail - try { - if (window.opener && !opener.closed && opener.rcmail) - return opener.rcmail; - } - catch (e) {} - }; - - // check if we're in show mode or if we have a unique selection - // and return the message uid - this.get_single_uid = function() - { - return this.env.uid ? this.env.uid : (this.message_list ? this.message_list.get_single_selection() : null); - }; - - // same as above but for contacts - this.get_single_cid = function() - { - return this.env.cid ? this.env.cid : (this.contact_list ? this.contact_list.get_single_selection() : null); - }; - - // gets cursor position - this.get_caret_pos = function(obj) - { - if (obj.selectionEnd !== undefined) - return obj.selectionEnd; - - if (document.selection && document.selection.createRange) { - var range = document.selection.createRange(); - if (range.parentElement() != obj) - return 0; - - var gm = range.duplicate(); - if (obj.tagName == 'TEXTAREA') - gm.moveToElementText(obj); - else - gm.expand('textedit'); - - gm.setEndPoint('EndToStart', range); - var p = gm.text.length; - - return p <= obj.value.length ? p : -1; - } - - return obj.value.length; - }; - - // moves cursor to specified position - this.set_caret_pos = function(obj, pos) - { - if (obj.setSelectionRange) - obj.setSelectionRange(pos, pos); - else if (obj.createTextRange) { - var range = obj.createTextRange(); - range.collapse(true); - range.moveEnd('character', pos); - range.moveStart('character', pos); - range.select(); - } - }; - - // disable/enable all fields of a form - this.lock_form = function(form, lock) - { - if (!form || !form.elements) - return; - - var n, len, elm; - - if (lock) - this.disabled_form_elements = []; - - for (n=0, len=form.elements.length; n<len; n++) { - elm = form.elements[n]; - - if (elm.type == 'hidden') - continue; - // remember which elem was disabled before lock - if (lock && elm.disabled) - this.disabled_form_elements.push(elm); - // check this.disabled_form_elements before inArray() as a workaround for FF5 bug - // http://bugs.jquery.com/ticket/9873 - else if (lock || (this.disabled_form_elements && $.inArray(elm, this.disabled_form_elements)<0)) - elm.disabled = lock; - } - }; - - this.mailto_handler_uri = function() - { - return location.href.split('?')[0] + '?_task=mail&_action=compose&_to=%s'; - }; - - this.register_protocol_handler = function(name) - { - try { - window.navigator.registerProtocolHandler('mailto', this.mailto_handler_uri(), name); - } - catch(e) {}; - }; - - this.check_protocol_handler = function(name, elem) - { - var nav = window.navigator; - if (!nav - || (typeof nav.registerProtocolHandler != 'function') - || ((typeof nav.isProtocolHandlerRegistered == 'function') - && nav.isProtocolHandlerRegistered('mailto', this.mailto_handler_uri()) == 'registered') - ) - $(elem).addClass('disabled'); - else - $(elem).click(function() { rcmail.register_protocol_handler(name); return false; }); - }; - - // Checks browser capabilities eg. PDF support, TIF support - this.browser_capabilities_check = function() - { - if (!this.env.browser_capabilities) - this.env.browser_capabilities = {}; - - if (this.env.browser_capabilities.pdf === undefined) - this.env.browser_capabilities.pdf = this.pdf_support_check(); - - if (this.env.browser_capabilities.flash === undefined) - this.env.browser_capabilities.flash = this.flash_support_check(); - - if (this.env.browser_capabilities.tif === undefined) - this.tif_support_check(); - }; - - // Returns browser capabilities string - this.browser_capabilities = function() - { - if (!this.env.browser_capabilities) - return ''; - - var n, ret = []; - - for (n in this.env.browser_capabilities) - ret.push(n + '=' + this.env.browser_capabilities[n]); - - return ret.join(); - }; - - this.tif_support_check = function() - { - var img = new Image(); - - img.onload = function() { rcmail.env.browser_capabilities.tif = 1; }; - img.onerror = function() { rcmail.env.browser_capabilities.tif = 0; }; - img.src = 'program/resources/blank.tif'; - }; - - this.pdf_support_check = function() - { - var plugin = navigator.mimeTypes ? navigator.mimeTypes["application/pdf"] : {}, - plugins = navigator.plugins, - len = plugins.length, - regex = /Adobe Reader|PDF|Acrobat/i; - - if (plugin && plugin.enabledPlugin) - return 1; - - if (window.ActiveXObject) { - try { - if (axObj = new ActiveXObject("AcroPDF.PDF")) - return 1; - } - catch (e) {} - try { - if (axObj = new ActiveXObject("PDF.PdfCtrl")) - return 1; - } - catch (e) {} - } - - for (i=0; i<len; i++) { - plugin = plugins[i]; - if (typeof plugin === 'String') { - if (regex.test(plugin)) - return 1; - } - else if (plugin.name && regex.test(plugin.name)) - return 1; - } - - return 0; - }; - - this.flash_support_check = function() - { - var plugin = navigator.mimeTypes ? navigator.mimeTypes["application/x-shockwave-flash"] : {}; - - if (plugin && plugin.enabledPlugin) - return 1; - - if (window.ActiveXObject) { - try { - if (axObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) - return 1; - } - catch (e) {} - } - - return 0; - }; - - // Cookie setter - this.set_cookie = function(name, value, expires) - { - setCookie(name, value, expires, this.env.cookie_path, this.env.cookie_domain, this.env.cookie_secure); - } - -} // end object rcube_webmail - - -// some static methods -rcube_webmail.long_subject_title = function(elem, indent) -{ - if (!elem.title) { - var $elem = $(elem); - if ($elem.width() + indent * 15 > $elem.parent().width()) - elem.title = $elem.html(); - } -}; - -rcube_webmail.long_subject_title_ie = function(elem, indent) -{ - if (!elem.title) { - var $elem = $(elem), - txt = $.trim($elem.text()), - tmp = $('<span>').text(txt) - .css({'position': 'absolute', 'float': 'left', 'visibility': 'hidden', - 'font-size': $elem.css('font-size'), 'font-weight': $elem.css('font-weight')}) - .appendTo($('body')), - w = tmp.width(); - - tmp.remove(); - if (w + indent * 15 > $elem.width()) - elem.title = txt; - } -}; - -rcube_webmail.prototype.get_cookie = getCookie; - -// copy event engine prototype -rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener; -rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener; -rcube_webmail.prototype.triggerEvent = rcube_event_engine.prototype.triggerEvent; +function rcube_webmail(){this.labels={};this.buttons={};this.buttons_sel={};this.gui_objects={};this.gui_containers={};this.commands={};this.command_handlers={};this.onloads=[];this.messages={};this.group2expand={};this.dblclick_time=500;this.message_time=4000;this.identifier_expr=new RegExp("[^0-9a-z-_]","gi");this.env={request_timeout:180,draft_autosave:0,comm_path:"./",blankpage:"program/resources/blank.gif",recipients_separator:",",recipients_delimiter:", "};this.ref="rcmail";var ref=this;$.ajaxSetup({cache:false,timeout:this.env.request_timeout*1000,error:function(request,status,err){ref.http_error(request,status,err)},beforeSend:function(xmlhttp){xmlhttp.setRequestHeader("X-Roundcube-Request",ref.env.request_token)}});$(window).bind("beforeunload",function(){rcmail.unload=true});this.set_env=function(p,value){if(p!=null&&typeof p==="object"&&!value){for(var n in p){this.env[n]=p[n]}}else{this.env[p]=value}};this.add_label=function(p,value){if(typeof p=="string"){this.labels[p]=value}else{if(typeof p=="object"){$.extend(this.labels,p)}}};this.register_button=function(command,id,type,act,sel,over){var button_prop={id:id,type:type};if(act){button_prop.act=act}if(sel){button_prop.sel=sel}if(over){button_prop.over=over}if(!this.buttons[command]){this.buttons[command]=[]}this.buttons[command].push(button_prop);if(this.loaded){init_button(command,button_prop)}};this.gui_object=function(name,id){this.gui_objects[name]=this.loaded?rcube_find_object(id):id};this.gui_container=function(name,id){this.gui_containers[name]=id};this.add_element=function(elm,container){if(this.gui_containers[container]&&this.gui_containers[container].jquery){this.gui_containers[container].append(elm)}};this.register_command=function(command,callback,enable){this.command_handlers[command]=callback;if(enable){this.enable_command(command,true)}};this.add_onload=function(f){this.onloads.push(f)};this.init=function(){var n,p=this;this.task=this.env.task;if(!bw.dom||!bw.xmlhttp_test()||(bw.mz&&bw.vendver<1.9)){this.goto_url("error","_code=0x199");return}for(n in this.gui_containers){this.gui_containers[n]=$("#"+this.gui_containers[n])}for(n in this.gui_objects){this.gui_objects[n]=rcube_find_object(this.gui_objects[n])}if(this.env.x_frame_options){try{if(this.env.x_frame_options=="deny"&&top.location.href!=self.location.href){top.location.href=self.location.href}else{if(top.location.hostname!=self.location.hostname){throw 1}}}catch(e){$("form").each(function(){ref.lock_form(this,true)});this.display_message("Blocked: possible clickjacking attack!","error");return}}this.init_buttons();if(this.is_framed()){parent.rcmail.set_busy(false,null,parent.rcmail.env.frame_lock);parent.rcmail.env.frame_lock=null}this.enable_command("close","logout","mail","addressbook","settings","save-pref","compose","undo","about","switch-task",true);if(this.env.permaurl){this.enable_command("permaurl","extwin",true)}switch(this.task){case"mail":this.enable_command("list","checkmail","add-contact","search","reset-search","collapse-folder",true);if(this.gui_objects.messagelist){this.message_list=new rcube_list_widget(this.gui_objects.messagelist,{multiselect:true,multiexpand:true,draggable:true,keyboard:true,column_movable:this.env.col_movable,dblclick_time:this.dblclick_time});this.message_list.row_init=function(o){p.init_message_row(o)};this.message_list.addEventListener("dblclick",function(o){p.msglist_dbl_click(o)});this.message_list.addEventListener("click",function(o){p.msglist_click(o)});this.message_list.addEventListener("keypress",function(o){p.msglist_keypress(o)});this.message_list.addEventListener("select",function(o){p.msglist_select(o)});this.message_list.addEventListener("dragstart",function(o){p.drag_start(o)});this.message_list.addEventListener("dragmove",function(e){p.drag_move(e)});this.message_list.addEventListener("dragend",function(e){p.drag_end(e)});this.message_list.addEventListener("expandcollapse",function(e){p.msglist_expand(e)});this.message_list.addEventListener("column_replace",function(e){p.msglist_set_coltypes(e)});document.onmouseup=function(e){return p.doc_mouse_up(e)};this.gui_objects.messagelist.parentNode.onmousedown=function(e){return p.click_on_list(e)};this.message_list.init();this.enable_command("toggle_status","toggle_flag","menu-open","menu-save","sort",true);this.command("list")}if(this.gui_objects.qsearchbox){if(this.env.search_text!=null){this.gui_objects.qsearchbox.value=this.env.search_text}$(this.gui_objects.qsearchbox).focusin(function(){rcmail.message_list&&rcmail.message_list.blur()})}this.set_button_titles();this.env.message_commands=["show","reply","reply-all","reply-list","moveto","copy","delete","open","mark","edit","viewsource","print","load-attachment","show-headers","hide-headers","download","forward","forward-inline","forward-attachment"];if(this.env.action=="show"||this.env.action=="preview"){this.enable_command(this.env.message_commands,this.env.uid);this.enable_command("reply-list",this.env.list_post);if(this.env.action=="show"){this.http_request("pagenav",{_uid:this.env.uid,_mbox:this.env.mailbox,_search:this.env.search_request},this.display_message("","loading"))}if(this.env.blockedobjects){if(this.gui_objects.remoteobjectsmsg){this.gui_objects.remoteobjectsmsg.style.display="block"}this.enable_command("load-images","always-load",true)}if(this.env.action=="preview"&&this.is_framed()){this.enable_command("compose","add-contact",false);parent.rcmail.show_contentframe(true)}}else{if(this.env.action=="compose"){this.env.compose_commands=["send-attachment","remove-attachment","send","cancel","toggle-editor","list-adresses","search","reset-search","extwin"];if(this.env.drafts_mailbox){this.env.compose_commands.push("savedraft")}this.enable_command(this.env.compose_commands,"identities",true);$.merge(this.env.compose_commands,["add-recipient","firstpage","previouspage","nextpage","lastpage"]);if(this.env.spellcheck){this.env.spellcheck.spelling_state_observer=function(s){ref.spellcheck_state()};this.env.compose_commands.push("spellcheck");this.enable_command("spellcheck",true)}document.onmouseup=function(e){return p.doc_mouse_up(e)};this.init_messageform()}else{if(this.env.action=="print"&&this.env.uid){if(bw.safari){setTimeout("window.print()",10)}else{window.print()}}}}if(this.gui_objects.mailboxlist){this.env.unread_counts={};this.gui_objects.folderlist=this.gui_objects.mailboxlist;this.http_request("getunread")}if(this.gui_objects.contactslist){this.contact_list=new rcube_list_widget(this.gui_objects.contactslist,{multiselect:true,draggable:false,keyboard:false});this.contact_list.addEventListener("select",function(o){ref.compose_recipient_select(o)});this.contact_list.addEventListener("dblclick",function(o){ref.compose_add_recipient("to")});this.contact_list.init()}if(this.gui_objects.addressbookslist){this.gui_objects.folderlist=this.gui_objects.addressbookslist;this.enable_command("list-adresses",true)}if(this.env.mdn_request&&this.env.uid){var postact="sendmdn",postdata={_uid:this.env.uid,_mbox:this.env.mailbox};if(!confirm(this.get_label("mdnrequest"))){postdata._flag="mdnsent";postact="mark"}this.http_post(postact,postdata)}if(!this.is_framed()&&!this.env.extwin){this.browser_capabilities_check()}break;case"addressbook":if(this.gui_objects.folderlist){this.env.contactfolders=$.extend($.extend({},this.env.address_sources),this.env.contactgroups)}this.enable_command("add","import",this.env.writable_source);this.enable_command("list","listgroup","listsearch","advanced-search",true);if(this.gui_objects.contactslist){this.contact_list=new rcube_list_widget(this.gui_objects.contactslist,{multiselect:true,draggable:this.gui_objects.folderlist?true:false,keyboard:true});this.contact_list.row_init=function(row){p.triggerEvent("insertrow",{cid:row.uid,row:row})};this.contact_list.addEventListener("keypress",function(o){p.contactlist_keypress(o)});this.contact_list.addEventListener("select",function(o){p.contactlist_select(o)});this.contact_list.addEventListener("dragstart",function(o){p.drag_start(o)});this.contact_list.addEventListener("dragmove",function(e){p.drag_move(e)});this.contact_list.addEventListener("dragend",function(e){p.drag_end(e)});this.contact_list.init();if(this.env.cid){this.contact_list.highlight_row(this.env.cid)}this.gui_objects.contactslist.parentNode.onmousedown=function(e){return p.click_on_list(e)};document.onmouseup=function(e){return p.doc_mouse_up(e)};if(this.gui_objects.qsearchbox){$(this.gui_objects.qsearchbox).focusin(function(){rcmail.contact_list.blur()})}this.update_group_commands();this.command("list")}this.set_page_buttons();if(this.env.cid){this.enable_command("show","edit",true);if(this.gui_objects.editform){$("input.groupmember").change(function(){ref.group_member_change(this.checked?"add":"del",ref.env.cid,ref.env.source,this.value)})}}if(this.gui_objects.editform){this.enable_command("save",true);if(this.env.action=="add"||this.env.action=="edit"||this.env.action=="search"){this.init_contact_form()}}if(this.gui_objects.qsearchbox){this.enable_command("search","reset-search","moveto",true)}break;case"settings":this.enable_command("preferences","identities","save","folders",true);if(this.env.action=="identities"){this.enable_command("add",this.env.identities_level<2)}else{if(this.env.action=="edit-identity"||this.env.action=="add-identity"){this.enable_command("save","edit","toggle-editor",true);this.enable_command("delete",this.env.identities_level<2);if(this.env.action=="add-identity"){$("input[type='text']").first().select()}}else{if(this.env.action=="folders"){this.enable_command("subscribe","unsubscribe","create-folder","rename-folder",true)}else{if(this.env.action=="edit-folder"&&this.gui_objects.editform){this.enable_command("save","folder-size",true);parent.rcmail.env.exists=this.env.messagecount;parent.rcmail.enable_command("purge",this.env.messagecount);$("input[type='text']").first().select()}}}}if(this.gui_objects.identitieslist){this.identity_list=new rcube_list_widget(this.gui_objects.identitieslist,{multiselect:false,draggable:false,keyboard:false});this.identity_list.addEventListener("select",function(o){p.identity_select(o)});this.identity_list.init();this.identity_list.focus();if(this.env.iid){this.identity_list.highlight_row(this.env.iid)}}else{if(this.gui_objects.sectionslist){this.sections_list=new rcube_list_widget(this.gui_objects.sectionslist,{multiselect:false,draggable:false,keyboard:false});this.sections_list.addEventListener("select",function(o){p.section_select(o)});this.sections_list.init();this.sections_list.focus()}else{if(this.gui_objects.subscriptionlist){this.init_subscription_list()}}}break;case"login":var input_user=$("#rcmloginuser");input_user.bind("keyup",function(e){return rcmail.login_user_keyup(e)});if(input_user.val()==""){input_user.focus()}else{$("#rcmloginpwd").focus()}if(window.jstz&&!bw.ie6){var timezone=jstz.determine();if(timezone.name()){$("#rcmlogintz").val(timezone.name())}}else{$("#rcmlogintz").val(new Date().getStdTimezoneOffset()/-60)}$("form").submit(function(){$("input[type=submit]",this).prop("disabled",true);rcmail.clear_messages();rcmail.display_message("","loading")});this.enable_command("login",true);break}if(this.env.contentframe&&!$("#"+this.env.contentframe).is(":visible")){this.env.contentframe=null}if(bw.ie){$("input[type=file]").keydown(function(e){if(e.keyCode=="13"){e.preventDefault()}})}this.loaded=true;if(this.pending_message){this.display_message(this.pending_message[0],this.pending_message[1],this.pending_message[2])}if(this.gui_objects.folderlist){this.gui_containers.foldertray=$(this.gui_objects.folderlist)}if(this.gui_objects.filedrop&&this.env.filedrop&&((window.XMLHttpRequest&&XMLHttpRequest.prototype&&XMLHttpRequest.prototype.sendAsBinary)||window.FormData)){$(document.body).bind("dragover dragleave drop",function(e){return ref.document_drag_hover(e,e.type=="dragover")});$(this.gui_objects.filedrop).addClass("droptarget").bind("dragover dragleave",function(e){return ref.file_drag_hover(e,e.type=="dragover")}).get(0).addEventListener("drop",function(e){return ref.file_dropped(e)},false)}this.triggerEvent("init",{task:this.task,action:this.env.action});for(var i in this.onloads){if(typeof this.onloads[i]==="string"){eval(this.onloads[i])}else{if(typeof this.onloads[i]==="function"){this.onloads[i]()}}}this.start_refresh();this.start_keepalive()};this.log=function(msg){if(window.console&&console.log){console.log(msg)}};this.command=function(command,props,obj,event){var ret,uid,cid,url,flag;if(obj&&obj.blur){obj.blur()}if(this.busy){return false}if((obj&&obj.href&&String(obj.href).indexOf("#")<0)&&rcube_event.get_modifier(event)){return true}if(!this.commands[command]){if(this.is_framed()){parent.rcmail.command(command,props)}return false}if(this.task=="mail"&&this.env.action=="compose"&&$.inArray(command,this.env.compose_commands)<0){if(this.cmp_hash!=this.compose_field_hash()&&!confirm(this.get_label("notsentwarning"))){return false}}if(typeof this.command_handlers[command]==="function"){ret=this.command_handlers[command](props,obj);return ret!==undefined?ret:(obj?false:true)}else{if(typeof this.command_handlers[command]==="string"){ret=window[this.command_handlers[command]](props,obj);return ret!==undefined?ret:(obj?false:true)}}this.triggerEvent("actionbefore",{props:props,action:command});ret=this.triggerEvent("before"+command,props);if(ret!==undefined){if(ret===false){return false}else{props=ret}}ret=undefined;switch(command){case"login":if(this.gui_objects.loginform){this.gui_objects.loginform.submit()}break;case"mail":case"addressbook":case"settings":case"logout":this.switch_task(command);break;case"about":this.redirect("?_task=settings&_action=about",false);break;case"permaurl":if(obj&&obj.href&&obj.target){return true}else{if(this.env.permaurl){parent.location.href=this.env.permaurl}}break;case"extwin":if(this.env.action=="compose"){var prevstate=this.env.compose_extwin;$("input[name='_action']",this.gui_objects.messageform).val("compose");this.gui_objects.messageform.action=this.url("mail/compose",{_id:this.env.compose_id,_extwin:1});this.gui_objects.messageform.target=this.open_window("",1100);this.gui_objects.messageform.submit()}else{this.open_window(this.env.permaurl,900)}break;case"menu-open":case"menu-save":this.triggerEvent(command,{props:props});return false;case"open":if(uid=this.get_single_uid()){obj.href=this.url("show",{_mbox:this.env.mailbox,_uid:uid});return true}break;case"close":if(this.env.extwin){window.close()}break;case"list":if(props&&props!=""){this.reset_qsearch()}if(this.env.action=="compose"&&this.env.extwin){window.close()}else{if(this.task=="mail"){this.list_mailbox(props);this.set_button_titles()}else{if(this.task=="addressbook"){this.list_contacts(props)}}}break;case"sort":var sort_order=this.env.sort_order,sort_col=!this.env.disabled_sort_col?props:this.env.sort_col;if(!this.env.disabled_sort_order){sort_order=this.env.sort_col==sort_col&&sort_order=="ASC"?"DESC":"ASC"}this.set_list_sorting(sort_col,sort_order);this.list_mailbox("","",sort_col+"_"+sort_order);break;case"nextpage":this.list_page("next");break;case"lastpage":this.list_page("last");break;case"previouspage":this.list_page("prev");break;case"firstpage":this.list_page("first");break;case"expunge":if(this.env.exists){this.expunge_mailbox(this.env.mailbox)}break;case"purge":case"empty-mailbox":if(this.env.exists){this.purge_mailbox(this.env.mailbox)}break;case"show":if(this.task=="mail"){uid=this.get_single_uid();if(uid&&(!this.env.uid||uid!=this.env.uid)){if(this.env.mailbox==this.env.drafts_mailbox){this.open_compose_step({_draft_uid:uid,_mbox:this.env.mailbox})}else{this.show_message(uid)}}}else{if(this.task=="addressbook"){cid=props?props:this.get_single_cid();if(cid&&!(this.env.action=="show"&&cid==this.env.cid)){this.load_contact(cid,"show")}}}break;case"add":if(this.task=="addressbook"){this.load_contact(0,"add")}else{if(this.task=="settings"){this.identity_list.clear_selection();this.load_identity(0,"add-identity")}}break;case"edit":if(this.task=="addressbook"&&(cid=this.get_single_cid())){this.load_contact(cid,"edit")}else{if(this.task=="settings"&&props){this.load_identity(props,"edit-identity")}else{if(this.task=="mail"&&(cid=this.get_single_uid())){url={_mbox:this.env.mailbox};url[this.env.mailbox==this.env.drafts_mailbox&&props!="new"?"_draft_uid":"_uid"]=cid;this.open_compose_step(url)}}}break;case"save":var input,form=this.gui_objects.editform;if(form){if(this.env.action=="search"){}else{if((input=$("input[name='_pagesize']",form))&&input.length&&isNaN(parseInt(input.val()))){alert(this.get_label("nopagesizewarning"));input.focus();break}else{if(props=="reload"){form.action+="?_reload=1"}else{if(this.task=="settings"&&(this.env.identities_level%2)==0&&(input=$("input[name='_email']",form))&&input.length&&!rcube_check_email(input.val())){alert(this.get_label("noemailwarning"));input.focus();break}}$("input.placeholder").each(function(){if(this.value==this._placeholder){this.value=""}})}}if(parent.rcmail&&parent.rcmail.env.source){form.action=this.add_url(form.action,"_orig_source",parent.rcmail.env.source)}form.submit()}break;case"delete":if(this.task=="mail"){this.delete_messages(event)}else{if(this.task=="addressbook"){this.delete_contacts()}else{if(this.task=="settings"){this.delete_identity()}}}break;case"move":case"moveto":if(this.task=="mail"){this.move_messages(props)}else{if(this.task=="addressbook"&&this.drag_active){this.copy_contact(null,props)}}break;case"copy":if(this.task=="mail"){this.copy_messages(props)}break;case"mark":if(props){this.mark_message(props)}break;case"toggle_status":if(props&&!props._row){break}flag="read";if(props._row.uid){uid=props._row.uid;if(this.message_list.rows[uid].deleted){flag="undelete"}else{if(!this.message_list.rows[uid].unread){flag="unread"}}}this.mark_message(flag,uid);break;case"toggle_flag":if(props&&!props._row){break}flag="flagged";if(props._row.uid){uid=props._row.uid;if(this.message_list.rows[uid].flagged){flag="unflagged"}}this.mark_message(flag,uid);break;case"always-load":if(this.env.uid&&this.env.sender){this.add_contact(this.env.sender);setTimeout(function(){ref.command("load-images")},300);break}case"load-images":if(this.env.uid){this.show_message(this.env.uid,true,this.env.action=="preview")}break;case"load-attachment":var qstring="_mbox="+urlencode(this.env.mailbox)+"&_uid="+this.env.uid+"&_part="+props.part;if(this.env.uid&&props.mimetype&&this.env.mimetypes&&$.inArray(props.mimetype,this.env.mimetypes)>=0){var attachment_win=window.open(this.env.comm_path+"&_action=get&"+qstring+"&_frame=1",this.html_identifier("rcubemailattachment"+this.env.uid+props.part));if(attachment_win){setTimeout(function(){attachment_win.focus()},10);break}}this.goto_url("get",qstring+"&_download=1",false);break;case"select-all":this.select_all_mode=props?false:true;this.dummy_select=true;if(props=="invert"){this.message_list.invert_selection()}else{this.message_list.select_all(props=="page"?"":props)}this.dummy_select=null;break;case"select-none":this.select_all_mode=false;this.message_list.clear_selection();break;case"expand-all":this.env.autoexpand_threads=1;this.message_list.expand_all();break;case"expand-unread":this.env.autoexpand_threads=2;this.message_list.collapse_all();this.expand_unread();break;case"collapse-all":this.env.autoexpand_threads=0;this.message_list.collapse_all();break;case"nextmessage":if(this.env.next_uid){this.show_message(this.env.next_uid,false,this.env.action=="preview")}break;case"lastmessage":if(this.env.last_uid){this.show_message(this.env.last_uid)}break;case"previousmessage":if(this.env.prev_uid){this.show_message(this.env.prev_uid,false,this.env.action=="preview")}break;case"firstmessage":if(this.env.first_uid){this.show_message(this.env.first_uid)}break;case"compose":url={};if(this.task=="mail"){url._mbox=this.env.mailbox;if(props){url._to=props}if(this.env.search_request){url._search=this.env.search_request}}else{if(this.task=="addressbook"){if(props&&props.indexOf("@")>0){url._to=props}else{var n,len,a_cids=[];if(props){a_cids.push(props)}else{if(this.contact_list){var selection=this.contact_list.get_selection();for(n=0,len=selection.length;n<len;n++){a_cids.push(selection[n])}}}if(a_cids.length){this.http_post("mailto",{_cid:a_cids.join(","),_source:this.env.source},true)}else{if(this.env.group){this.http_post("mailto",{_gid:this.env.group,_source:this.env.source},true)}}break}}else{if(props){url._to=props}}}this.open_compose_step(url);break;case"spellcheck":if(this.spellcheck_state()){this.stop_spellchecking()}else{if(window.tinyMCE&&tinyMCE.get(this.env.composebody)){tinyMCE.execCommand("mceSpellCheck",true)}else{if(this.env.spellcheck&&this.env.spellcheck.spellCheck){this.env.spellcheck.spellCheck()}}}this.spellcheck_state();break;case"savedraft":clearTimeout(this.save_timer);if(this.env.draft_id&&this.cmp_hash==this.compose_field_hash()){this.auto_save_start();break}this.submit_messageform(true);break;case"send":if(!props.nocheck&&!this.check_compose_input(command)){break}clearTimeout(this.save_timer);this.submit_messageform();break;case"send-attachment":clearTimeout(this.save_timer);this.upload_file(props||this.gui_objects.uploadform);break;case"insert-sig":this.change_identity($("[name='_from']")[0],true);break;case"list-adresses":this.list_contacts(props);this.enable_command("add-recipient",false);break;case"add-recipient":this.compose_add_recipient(props);break;case"reply-all":case"reply-list":case"reply":if(uid=this.get_single_uid()){url={_reply_uid:uid,_mbox:this.env.mailbox};if(command=="reply-all"){url._all=(!props&&this.commands["reply-list"]?"list":"all")}else{if(command=="reply-list"){url._all="list"}}this.open_compose_step(url)}break;case"forward-attachment":case"forward-inline":case"forward":var uids=this.env.uid?[this.env.uid]:(this.message_list?this.message_list.get_selection():[]);if(uids.length){url={_forward_uid:this.uids_to_list(uids),_mbox:this.env.mailbox};if(command=="forward-attachment"||(!props&&this.env.forward_attachment)||uids.length>1){url._attachment=1}this.open_compose_step(url)}break;case"print":if(uid=this.get_single_uid()){ref.printwin=window.open(this.env.comm_path+"&_action=print&_uid="+uid+"&_mbox="+urlencode(this.env.mailbox)+(this.env.safemode?"&_safe=1":""));if(this.printwin){setTimeout(function(){ref.printwin.focus()},20);if(this.env.action!="show"){this.mark_message("read",uid)}}}break;case"viewsource":if(uid=this.get_single_uid()){ref.sourcewin=window.open(this.env.comm_path+"&_action=viewsource&_uid="+uid+"&_mbox="+urlencode(this.env.mailbox));if(this.sourcewin){setTimeout(function(){ref.sourcewin.focus()},20)}}break;case"download":if(uid=this.get_single_uid()){this.goto_url("viewsource",{_uid:uid,_mbox:this.env.mailbox,_save:1})}break;case"search":if(!props&&this.gui_objects.qsearchbox){props=this.gui_objects.qsearchbox.value}if(props){this.qsearch(props);break}case"reset-search":var n,s=this.env.search_request||this.env.qsearch;this.reset_qsearch();this.select_all_mode=false;if(s&&this.env.action=="compose"){if(this.contact_list){this.list_contacts_clear()}}else{if(s&&this.env.mailbox){this.list_mailbox(this.env.mailbox,1)}else{if(s&&this.task=="addressbook"){if(this.env.source==""){for(n in this.env.address_sources){break}this.env.source=n;this.env.group=""}this.list_contacts(this.env.source,this.env.group,1)}}}break;case"listgroup":this.reset_qsearch();this.list_contacts(props.source,props.id);break;case"import":if(this.env.action=="import"&&this.gui_objects.importform){var file=document.getElementById("rcmimportfile");if(file&&!file.value){alert(this.get_label("selectimportfile"));break}this.gui_objects.importform.submit();this.set_busy(true,"importwait");this.lock_form(this.gui_objects.importform,true)}else{this.goto_url("import",(this.env.source?"_target="+urlencode(this.env.source)+"&":""))}break;case"export":if(this.contact_list.rowcount>0){this.goto_url("export",{_source:this.env.source,_gid:this.env.group,_search:this.env.search_request})}break;case"upload-photo":this.upload_contact_photo(props||this.gui_objects.uploadform);break;case"delete-photo":this.replace_contact_photo("-del-");break;case"preferences":case"identities":case"folders":this.goto_url("settings/"+command);break;case"undo":this.http_request("undo","",this.display_message("","loading"));break;default:var func=command.replace(/-/g,"_");if(this[func]&&typeof this[func]==="function"){ret=this[func](props,obj)}break}if(this.triggerEvent("after"+command,props)===false){ret=false}this.triggerEvent("actionafter",{props:props,action:command});return ret===false?false:obj?false:true};this.enable_command=function(){var i,n,args=Array.prototype.slice.call(arguments),enable=args.pop(),cmd;for(n=0;n<args.length;n++){cmd=args[n];if(typeof cmd==="string"){this.commands[cmd]=enable;this.set_button(cmd,(enable?"act":"pas"))}else{for(i in cmd){args.push(cmd[i])}}}};this.set_busy=function(a,message,id){if(a&&message){var msg=this.get_label(message);if(msg==message){msg="Loading..."}id=this.display_message(msg,"loading")}else{if(!a&&id){this.hide_message(id)}}this.busy=a;if(this.gui_objects.editform){this.lock_form(this.gui_objects.editform,a)}return id};this.get_label=function(name,domain){if(domain&&this.labels[domain+"."+name]){return this.labels[domain+"."+name]}else{if(this.labels[name]){return this.labels[name]}else{return name}}};this.gettext=this.get_label;this.switch_task=function(task){if(this.task===task&&task!="mail"){return}var url=this.get_task_url(task);if(task=="mail"){url+="&_mbox=INBOX"}this.redirect(url)};this.get_task_url=function(task,url){if(!url){url=this.env.comm_path}return url.replace(/_task=[a-z]+/,"_task="+task)};this.reload=function(delay){if(this.is_framed()){parent.rcmail.reload(delay)}else{if(delay){setTimeout(function(){rcmail.reload()},delay)}else{if(window.location){location.href=this.env.comm_path+(this.env.action?"&_action="+this.env.action:"")}}}};this.add_url=function(url,name,value){value=urlencode(value);if(/(\?.*)$/.test(url)){var urldata=RegExp.$1,datax=RegExp("((\\?|&)"+RegExp.escape(name)+"=[^&]*)");if(datax.test(urldata)){urldata=urldata.replace(datax,RegExp.$2+name+"="+value)}else{urldata+="&"+name+"="+value}return url.replace(/(\?.*)$/,urldata)}return url+"?"+name+"="+value};this.is_framed=function(){return(this.env.framed&&parent.rcmail&&parent.rcmail!=this&&parent.rcmail.command)};this.save_pref=function(prop){var request={_name:prop.name,_value:prop.value};if(prop.session){request._session=prop.session}if(prop.env){this.env[prop.env]=prop.value}this.http_post("save-pref",request)};this.html_identifier=function(str,encode){str=String(str);if(encode){return Base64.encode(str).replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_")}else{return str.replace(this.identifier_expr,"_")}};this.html_identifier_decode=function(str){str=String(str).replace(/-/g,"+").replace(/_/g,"/");while(str.length%4){str+="="}return Base64.decode(str)};this.drag_menu=function(e,target){var modkey=rcube_event.get_modifier(e),menu=this.gui_objects.message_dragmenu;if(menu&&modkey==SHIFT_KEY&&this.commands.copy){var pos=rcube_event.get_mouse_pos(e);this.env.drag_target=target;$(menu).css({top:(pos.y-10)+"px",left:(pos.x-10)+"px"}).show();return true}return false};this.drag_menu_action=function(action){var menu=this.gui_objects.message_dragmenu;if(menu){$(menu).hide()}this.command(action,this.env.drag_target);this.env.drag_target=null};this.drag_start=function(list){var model=this.task=="mail"?this.env.mailboxes:this.env.contactfolders;this.drag_active=true;if(this.preview_timer){clearTimeout(this.preview_timer)}if(this.preview_read_timer){clearTimeout(this.preview_read_timer)}if(this.gui_objects.folderlist&&model){this.initialBodyScrollTop=bw.ie?0:window.pageYOffset;this.initialListScrollTop=this.gui_objects.folderlist.parentNode.scrollTop;var k,li,height,list=$(this.gui_objects.folderlist);pos=list.offset();this.env.folderlist_coords={x1:pos.left,y1:pos.top,x2:pos.left+list.width(),y2:pos.top+list.height()};this.env.folder_coords=[];for(k in model){if(li=this.get_folder_li(k)){if(height=li.firstChild.offsetHeight){pos=$(li.firstChild).offset();this.env.folder_coords[k]={x1:pos.left,y1:pos.top,x2:pos.left+li.firstChild.offsetWidth,y2:pos.top+height,on:0}}}}}};this.drag_end=function(e){this.drag_active=false;this.env.last_folder_target=null;if(this.folder_auto_timer){clearTimeout(this.folder_auto_timer);this.folder_auto_timer=null;this.folder_auto_expand=null}if(this.gui_objects.folderlist&&this.env.folder_coords){for(var k in this.env.folder_coords){if(this.env.folder_coords[k].on){$(this.get_folder_li(k)).removeClass("droptarget")}}}};this.drag_move=function(e){if(this.gui_objects.folderlist&&this.env.folder_coords){var k,li,div,check,oldclass,layerclass="draglayernormal",mouse=rcube_event.get_mouse_pos(e),pos=this.env.folderlist_coords,boffset=bw.ie?-document.documentElement.scrollTop:this.initialBodyScrollTop,moffset=this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop;if(this.contact_list&&this.contact_list.draglayer){oldclass=this.contact_list.draglayer.attr("class")}mouse.y+=-moffset-boffset;if(mouse.x<pos.x1||mouse.x>=pos.x2||mouse.y<pos.y1||mouse.y>=pos.y2){if(this.env.last_folder_target){$(this.get_folder_li(this.env.last_folder_target)).removeClass("droptarget");this.env.folder_coords[this.env.last_folder_target].on=0;this.env.last_folder_target=null}if(layerclass!=oldclass&&this.contact_list&&this.contact_list.draglayer){this.contact_list.draglayer.attr("class",layerclass)}return}for(k in this.env.folder_coords){pos=this.env.folder_coords[k];if(mouse.x>=pos.x1&&mouse.x<pos.x2&&mouse.y>=pos.y1&&mouse.y<pos.y2){if(check=this.check_droptarget(k)){li=this.get_folder_li(k);div=$(li.getElementsByTagName("div")[0]);if(div.hasClass("collapsed")){if(this.folder_auto_timer){clearTimeout(this.folder_auto_timer)}this.folder_auto_expand=this.env.mailboxes[k].id;this.folder_auto_timer=setTimeout(function(){rcmail.command("collapse-folder",rcmail.folder_auto_expand);rcmail.drag_start(null)},1000)}else{if(this.folder_auto_timer){clearTimeout(this.folder_auto_timer);this.folder_auto_timer=null;this.folder_auto_expand=null}}$(li).addClass("droptarget");this.env.folder_coords[k].on=1;this.env.last_folder_target=k;layerclass="draglayer"+(check>1?"copy":"normal")}else{this.env.last_folder_target=null}}else{if(pos.on){$(this.get_folder_li(k)).removeClass("droptarget");this.env.folder_coords[k].on=0}}}if(layerclass!=oldclass&&this.contact_list&&this.contact_list.draglayer){this.contact_list.draglayer.attr("class",layerclass)}}};this.collapse_folder=function(name){var li=this.get_folder_li(name,"",true),div=$("div:first",li),ul=$("ul:first",li);if(div.hasClass("collapsed")){ul.show();div.removeClass("collapsed").addClass("expanded");var reg=new RegExp("&"+urlencode(name)+"&");this.env.collapsed_folders=this.env.collapsed_folders.replace(reg,"")}else{if(div.hasClass("expanded")){ul.hide();div.removeClass("expanded").addClass("collapsed");this.env.collapsed_folders=this.env.collapsed_folders+"&"+urlencode(name)+"&";if(this.env.mailbox.indexOf(name+this.env.delimiter)==0&&!$(li).hasClass("virtual")){this.command("list",name)}}else{return}}if(bw.ie6||bw.ie7){var siblings=li.nextSibling?li.nextSibling.getElementsByTagName("ul"):null;if(siblings&&siblings.length&&(li=siblings[0])&&li.style&&li.style.display!="none"){li.style.display="none";li.style.display=""}}this.command("save-pref",{name:"collapsed_folders",value:this.env.collapsed_folders});this.set_unread_count_display(name,false)};this.doc_mouse_up=function(e){var model,list,id;if($(rcube_event.get_target(e)).closest(".ui-dialog, .ui-widget-overlay").length){return}if(list=this.message_list){model=this.env.mailboxes}else{if(list=this.contact_list){model=this.env.contactfolders}else{if(this.ksearch_value){this.ksearch_blur()}}}if(list&&!rcube_mouse_is_over(e,list.list.parentNode)){list.blur()}if(this.drag_active&&model&&this.env.last_folder_target){var target=model[this.env.last_folder_target];$(this.get_folder_li(this.env.last_folder_target)).removeClass("droptarget");this.env.last_folder_target=null;list.draglayer.hide();if(!this.drag_menu(e,target)){this.command("moveto",target)}}if(this.buttons_sel){for(id in this.buttons_sel){if(typeof id!=="function"){this.button_out(this.buttons_sel[id],id)}}this.buttons_sel={}}};this.click_on_list=function(e){if(this.gui_objects.qsearchbox){this.gui_objects.qsearchbox.blur()}if(this.message_list){this.message_list.focus()}else{if(this.contact_list){this.contact_list.focus()}}return true};this.msglist_select=function(list){if(this.preview_timer){clearTimeout(this.preview_timer)}if(this.preview_read_timer){clearTimeout(this.preview_read_timer)}var selected=list.get_single_selection();this.enable_command(this.env.message_commands,selected!=null);if(selected){if(this.env.mailbox==this.env.drafts_mailbox){this.enable_command("reply","reply-all","reply-list","forward","forward-attachment","forward-inline",false)}else{var msg=this.env.messages[selected];if(!msg.ml){this.enable_command("reply-list",false)}}}this.enable_command("delete","moveto","copy","mark","forward","forward-attachment",list.selection.length>0);if(selected||(list.selection.length&&list.selection.length!=list.rowcount)){this.select_all_mode=false}if(selected&&this.env.contentframe&&!list.multi_selecting&&!this.dummy_select){this.preview_timer=setTimeout(function(){ref.msglist_get_preview()},this.dblclick_time)}else{if(this.env.contentframe){this.show_contentframe(false)}}};this.msglist_click=function(list){if(list.multi_selecting||!this.env.contentframe){return}if(list.get_single_selection()){return}var win=this.get_frame_window(this.env.contentframe);if(win&&win.location.href.indexOf(this.env.blankpage)>=0){if(this.preview_timer){clearTimeout(this.preview_timer)}if(this.preview_read_timer){clearTimeout(this.preview_read_timer)}this.preview_timer=setTimeout(function(){ref.msglist_get_preview()},this.dblclick_time)}};this.msglist_dbl_click=function(list){if(this.preview_timer){clearTimeout(this.preview_timer)}if(this.preview_read_timer){clearTimeout(this.preview_read_timer)}var uid=list.get_single_selection();if(uid&&this.env.mailbox==this.env.drafts_mailbox){this.open_compose_step({_draft_uid:uid,_mbox:this.env.mailbox})}else{if(uid){this.show_message(uid,false,false)}}};this.msglist_keypress=function(list){if(list.modkey==CONTROL_KEY){return}if(list.key_pressed==list.ENTER_KEY){this.command("show")}else{if(list.key_pressed==list.DELETE_KEY||list.key_pressed==list.BACKSPACE_KEY){this.command("delete")}else{if(list.key_pressed==33){this.command("previouspage")}else{if(list.key_pressed==34){this.command("nextpage")}}}}};this.msglist_get_preview=function(){var uid=this.get_single_uid();if(uid&&this.env.contentframe&&!this.drag_active){this.show_message(uid,false,true)}else{if(this.env.contentframe){this.show_contentframe(false)}}};this.msglist_expand=function(row){if(this.env.messages[row.uid]){this.env.messages[row.uid].expanded=row.expanded}$(row.obj)[row.expanded?"addClass":"removeClass"]("expanded")};this.msglist_set_coltypes=function(list){var i,found,name,cols=list.list.tHead.rows[0].cells;this.env.coltypes=[];for(i=0;i<cols.length;i++){if(cols[i].id&&cols[i].id.match(/^rcm/)){name=cols[i].id.replace(/^rcm/,"");this.env.coltypes.push(name)}}if((found=$.inArray("flag",this.env.coltypes))>=0){this.env.flagged_col=found}if((found=$.inArray("subject",this.env.coltypes))>=0){this.env.subject_col=found}this.command("save-pref",{name:"list_cols",value:this.env.coltypes,session:"list_attrib/columns"})};this.check_droptarget=function(id){if(this.task=="mail"){return(this.env.mailboxes[id]&&this.env.mailboxes[id].id!=this.env.mailbox&&!this.env.mailboxes[id].virtual)?1:0}if(this.task=="settings"){return id!=this.env.mailbox?1:0}if(this.task=="addressbook"){if(id!=this.env.source&&this.env.contactfolders[id]){if(this.env.contactfolders[id].type=="group"){var target_abook=this.env.contactfolders[id].source;if(this.env.contactfolders[id].id!=this.env.group&&!this.env.contactfolders[target_abook].readonly){return(this.env.selection_sources.length>1||$.inArray(target_abook,this.env.selection_sources)==-1)?2:1}}else{if(!this.env.contactfolders[id].readonly){return(this.env.selection_sources.length>1||$.inArray(id,this.env.selection_sources)==-1)?2:0}}}}return 0};this.open_window=function(url,width){var win=this.is_framed()?parent.window:window,page=$(win),page_width=page.width(),page_height=bw.mz?$("body",win).height():page.height(),w=Math.min(width,page_width),h=page_height,l=(win.screenLeft||win.screenX)+20,t=(win.screenTop||win.screenY)+20,wname="rcmextwin"+new Date().getTime(),extwin=window.open(url+(url.match(/\?/)?"&":"?")+"_extwin=1",wname,"width="+w+",height="+h+",top="+t+",left="+l+",resizable=yes,toolbar=no,status=no,location=no");if(!url&&extwin.document){extwin.document.write("<html><body>"+this.get_label("loading")+"</body></html>")}window.setTimeout(function(){extwin.focus()},10);return wname};this.init_message_row=function(row){var expando,self=this,uid=row.uid,status_icon=(this.env.status_col!=null?"status":"msg")+"icn"+row.uid;if(uid&&this.env.messages[uid]){$.extend(row,this.env.messages[uid])}if(row.icon=document.getElementById(status_icon)){row.icon._row=row.obj;row.icon.onmousedown=function(e){self.command("toggle_status",this);rcube_event.cancel(e)}}if(this.env.status_col!=null){row.msgicon=document.getElementById("msgicn"+row.uid)}else{row.msgicon=row.icon}if(this.env.flagged_col!=null&&(row.flagicon=document.getElementById("flagicn"+row.uid))){row.flagicon._row=row.obj;row.flagicon.onmousedown=function(e){self.command("toggle_flag",this);rcube_event.cancel(e)}}if(!row.depth&&row.has_children&&(expando=document.getElementById("rcmexpando"+row.uid))){row.expando=expando;expando.onmousedown=function(e){return self.expand_message_row(e,uid)};if(bw.touch){expando.addEventListener("touchend",function(e){if(e.changedTouches.length==1){self.expand_message_row(e,uid);return rcube_event.cancel(e)}},false)}}this.triggerEvent("insertrow",{uid:uid,row:row})};this.add_message_row=function(uid,cols,flags,attop){if(!this.gui_objects.messagelist||!this.message_list){return false}if(flags.mbox!=this.env.mailbox&&!flags.skip_mbox_check){return false}if(!this.env.messages[uid]){this.env.messages[uid]={}}$.extend(this.env.messages[uid],{deleted:flags.deleted?1:0,replied:flags.answered?1:0,unread:!flags.seen?1:0,forwarded:flags.forwarded?1:0,flagged:flags.flagged?1:0,has_children:flags.has_children?1:0,depth:flags.depth?flags.depth:0,unread_children:flags.unread_children?flags.unread_children:0,parent_uid:flags.parent_uid?flags.parent_uid:0,selected:this.select_all_mode||this.message_list.in_selection(uid),ml:flags.ml?1:0,ctype:flags.ctype,flags:flags.extra_flags});var c,n,col,html,css_class,tree="",expando="",list=this.message_list,rows=list.rows,message=this.env.messages[uid],row_class="message"+(!flags.seen?" unread":"")+(flags.deleted?" deleted":"")+(flags.flagged?" flagged":"")+(message.selected?" selected":""),row=document.createElement("tr");row.id="rcmrow"+uid;css_class="msgicon";if(this.env.status_col===null){css_class+=" status";if(flags.deleted){css_class+=" deleted"}else{if(!flags.seen){css_class+=" unread"}else{if(flags.unread_children>0){css_class+=" unreadchildren"}}}}if(flags.answered){css_class+=" replied"}if(flags.forwarded){css_class+=" forwarded"}if(message.selected&&!list.in_selection(uid)){list.selection.push(uid)}if(this.env.threading){if(message.depth){tree+='<span id="rcmtab'+uid+'" class="branch" style="width:'+(message.depth*15)+'px;"> </span>';if((rows[message.parent_uid]&&rows[message.parent_uid].expanded===false)||((this.env.autoexpand_threads==0||this.env.autoexpand_threads==2)&&(!rows[message.parent_uid]||!rows[message.parent_uid].expanded))){row.style.display="none";message.expanded=false}else{message.expanded=true}row_class+=" thread expanded"}else{if(message.has_children){if(message.expanded===undefined&&(this.env.autoexpand_threads==1||(this.env.autoexpand_threads==2&&message.unread_children))){message.expanded=true}expando='<div id="rcmexpando'+uid+'" class="'+(message.expanded?"expanded":"collapsed")+'"> </div>';row_class+=" thread"+(message.expanded?" expanded":"")}}if(flags.unread_children&&flags.seen&&!message.expanded){row_class+=" unroot"}}tree+='<span id="msgicn'+uid+'" class="'+css_class+'"> </span>';row.className=row_class;if(!bw.ie&&cols.subject){var action=flags.mbox==this.env.drafts_mailbox?"compose":"show";var uid_param=flags.mbox==this.env.drafts_mailbox?"_draft_uid":"_uid";cols.subject='<a href="./?_task=mail&_action='+action+"&_mbox="+urlencode(flags.mbox)+"&"+uid_param+"="+uid+'" onclick="return rcube_event.cancel(event)" onmouseover="rcube_webmail.long_subject_title(this,'+(message.depth+1)+')">'+cols.subject+"</a>"}for(n in this.env.coltypes){c=this.env.coltypes[n];col=document.createElement("td");col.className=String(c).toLowerCase();if(c=="flag"){css_class=(flags.flagged?"flagged":"unflagged");html='<span id="flagicn'+uid+'" class="'+css_class+'"> </span>'}else{if(c=="attachment"){if(/application\/|multipart\/(m|signed)/.test(flags.ctype)){html='<span class="attachment"> </span>'}else{if(/multipart\/report/.test(flags.ctype)){html='<span class="report"> </span>'}else{html=" "}}}else{if(c=="status"){if(flags.deleted){css_class="deleted"}else{if(!flags.seen){css_class="unread"}else{if(flags.unread_children>0){css_class="unreadchildren"}else{css_class="msgicon"}}}html='<span id="statusicn'+uid+'" class="'+css_class+'"> </span>'}else{if(c=="threads"){html=expando}else{if(c=="subject"){if(bw.ie){col.onmouseover=function(){rcube_webmail.long_subject_title_ex(this,message.depth+1)};if(bw.ie8){tree="<span></span>"+tree}}html=tree+cols[c]}else{if(c=="priority"){if(flags.prio>0&&flags.prio<6){html='<span class="prio'+flags.prio+'"> </span>'}else{html=" "}}else{html=cols[c]}}}}}}if(html){col.innerHTML=html}row.appendChild(col)}list.insert_row(row,attop);if(attop&&this.env.pagesize&&list.rowcount>this.env.pagesize){var uid=list.get_last_row();list.remove_row(uid);list.clear_selection(uid)}};this.set_list_sorting=function(sort_col,sort_order){$("#rcm"+this.env.sort_col).removeClass("sorted"+(this.env.sort_order.toUpperCase()));if(sort_col){$("#rcm"+sort_col).addClass("sorted"+sort_order)}this.env.sort_col=sort_col;this.env.sort_order=sort_order};this.set_list_options=function(cols,sort_col,sort_order,threads){var update,post_data={};if(sort_col===undefined){sort_col=this.env.sort_col}if(!sort_order){sort_order=this.env.sort_order}if(this.env.sort_col!=sort_col||this.env.sort_order!=sort_order){update=1;this.set_list_sorting(sort_col,sort_order)}if(this.env.threading!=threads){update=1;post_data._threads=threads}if(cols&&cols.length){var i,idx,name,newcols=[],oldcols=this.env.coltypes;for(i=0;i<oldcols.length;i++){name=oldcols[i];idx=$.inArray(name,cols);if(idx!=-1){newcols.push(name);delete cols[idx]}}for(i=0;i<cols.length;i++){if(cols[i]){newcols.push(cols[i])}}if(newcols.join()!=oldcols.join()){update=1;post_data._cols=newcols.join(",")}}if(update){this.list_mailbox("","",sort_col+"_"+sort_order,post_data)}};this.show_message=function(id,safe,preview){if(!id){return}var win,target=window,action=preview?"preview":"show",url="&_action="+action+"&_uid="+id+"&_mbox="+urlencode(this.env.mailbox);if(preview&&(win=this.get_frame_window(this.env.contentframe))){target=win;url+="&_framed=1"}if(safe){url+="&_safe=1"}if(this.env.search_request){url+="&_search="+this.env.search_request}url+="&_caps="+urlencode(this.browser_capabilities());if(this.env.extwin){url+="&_extwin=1"}if(preview&&String(target.location.href).indexOf(url)>=0){this.show_contentframe(true)}else{if(!preview&&this.env.message_extwin&&!this.env.extwin){this.open_window(this.env.comm_path+url,1000)}else{this.location_href(this.env.comm_path+url,target,true)}if(preview&&this.message_list&&this.message_list.rows[id]&&this.message_list.rows[id].unread&&this.env.preview_pane_mark_read>=0){this.preview_read_timer=setTimeout(function(){ref.set_message(id,"unread",false);ref.update_thread_root(id,"read");if(ref.env.unread_counts[ref.env.mailbox]){ref.env.unread_counts[ref.env.mailbox]-=1;ref.set_unread_count(ref.env.mailbox,ref.env.unread_counts[ref.env.mailbox],ref.env.mailbox=="INBOX")}if(ref.env.preview_pane_mark_read>0){ref.http_post("mark",{_uid:id,_flag:"read",_quiet:1})}},this.env.preview_pane_mark_read*1000)}}};this.show_contentframe=function(show){var frame,win,name=this.env.contentframe;if(name&&(frame=this.get_frame_element(name))){if(!show&&(win=this.get_frame_window(name))){if(win.location&&win.location.href.indexOf(this.env.blankpage)<0){win.location.href=this.env.blankpage}}else{if(!bw.safari&&!bw.konq){$(frame)[show?"show":"hide"]()}}}if(!show&&this.busy){this.set_busy(false,null,this.env.frame_lock)}};this.get_frame_element=function(id){var frame;if(id&&(frame=document.getElementById(id))){return frame}};this.get_frame_window=function(id){var frame=this.get_frame_element(id);if(frame&&frame.name&&window.frames){return window.frames[frame.name]}};this.lock_frame=function(){if(!this.env.frame_lock){(this.is_framed()?parent.rcmail:this).env.frame_lock=this.set_busy(true,"loading")}};this.list_page=function(page){if(page=="next"){page=this.env.current_page+1}else{if(page=="last"){page=this.env.pagecount}else{if(page=="prev"&&this.env.current_page>1){page=this.env.current_page-1}else{if(page=="first"&&this.env.current_page>1){page=1}}}}if(page>0&&page<=this.env.pagecount){this.env.current_page=page;if(this.task=="addressbook"||this.contact_list){this.list_contacts(this.env.source,this.env.group,page)}else{if(this.task=="mail"){this.list_mailbox(this.env.mailbox,page)}}}};this.checkmail=function(){var lock=this.set_busy(true,"checkingmail"),params=this.check_recent_params();this.http_request("check-recent",params,lock)};this.filter_mailbox=function(filter){var lock=this.set_busy(true,"searching");this.clear_message_list();this.env.current_page=1;this.http_request("search",this.search_params(false,filter),lock)};this.list_mailbox=function(mbox,page,sort,url){var win,target=window;if(typeof url!="object"){url={}}if(!mbox){mbox=this.env.mailbox?this.env.mailbox:"INBOX"}if(sort){url._sort=sort}if(this.env.search_request){url._search=this.env.search_request}if(this.env.mailbox!=mbox){page=1;this.env.current_page=page;this.select_all_mode=false}this.clear_message_list();if(mbox!=this.env.mailbox||(mbox==this.env.mailbox&&!page&&!sort)){url._refresh=1}this.select_folder(mbox,"",true);this.unmark_folder(mbox,"recent","",true);this.env.mailbox=mbox;if(this.gui_objects.messagelist){this.list_mailbox_remote(mbox,page,url);return}if(win=this.get_frame_window(this.env.contentframe)){target=win;url._framed=1}if(mbox){this.set_busy(true,"loading");url._mbox=mbox;if(page){url._page=page}this.location_href(url,target)}};this.clear_message_list=function(){this.env.messages={};this.last_selected=0;this.show_contentframe(false);if(this.message_list){this.message_list.clear(true)}};this.list_mailbox_remote=function(mbox,page,post_data){this.message_list.clear();var lock=this.set_busy(true,"loading");if(typeof post_data!="object"){post_data={}}post_data._mbox=mbox;if(page){post_data._page=page}this.http_request("list",post_data,lock)};this.update_selection=function(){var selected=this.message_list.selection,rows=this.message_list.rows,i,selection=[];for(i in selected){if(rows[selected[i]]){selection.push(selected[i])}}this.message_list.selection=selection};this.expand_unread=function(){var r,tbody=this.gui_objects.messagelist.tBodies[0],new_row=tbody.firstChild;while(new_row){if(new_row.nodeType==1&&(r=this.message_list.rows[new_row.uid])&&r.unread_children){this.message_list.expand_all(r);this.set_unread_children(r.uid)}new_row=new_row.nextSibling}return false};this.expand_message_row=function(e,uid){var row=this.message_list.rows[uid];row.expanded=!row.expanded;this.set_unread_children(uid);row.expanded=!row.expanded;this.message_list.expand_row(e,uid)};this.expand_threads=function(){if(!this.env.threading||!this.env.autoexpand_threads||!this.message_list){return}switch(this.env.autoexpand_threads){case 2:this.expand_unread();break;case 1:this.message_list.expand_all();break}};this.init_threads=function(roots,mbox){if(mbox&&mbox!=this.env.mailbox){return false}for(var n=0,len=roots.length;n<len;n++){this.add_tree_icons(roots[n])}this.expand_threads()};this.add_tree_icons=function(root){var i,l,r,n,len,pos,tmp=[],uid=[],row,rows=this.message_list.rows;if(root){row=rows[root]?rows[root].obj:null}else{row=this.message_list.list.tBodies[0].firstChild}while(row){if(row.nodeType==1&&(r=rows[row.uid])){if(r.depth){for(i=tmp.length-1;i>=0;i--){len=tmp[i].length;if(len>r.depth){pos=len-r.depth;if(!(tmp[i][pos]&2)){tmp[i][pos]=tmp[i][pos]?tmp[i][pos]+2:2}}else{if(len==r.depth){if(!(tmp[i][0]&2)){tmp[i][0]+=2}}}if(r.depth>len){break}}tmp.push(new Array(r.depth));tmp[tmp.length-1][0]=1;uid.push(r.uid)}else{if(tmp.length){for(i in tmp){this.set_tree_icons(uid[i],tmp[i])}tmp=[];uid=[]}if(root&&row!=rows[root].obj){break}}}row=row.nextSibling}if(tmp.length){for(i in tmp){this.set_tree_icons(uid[i],tmp[i])}}};this.set_tree_icons=function(uid,tree){var i,divs=[],html="",len=tree.length;for(i=0;i<len;i++){if(tree[i]>2){divs.push({"class":"l3",width:15})}else{if(tree[i]>1){divs.push({"class":"l2",width:15})}else{if(tree[i]>0){divs.push({"class":"l1",width:15})}else{if(divs.length&&!divs[divs.length-1]["class"]){divs[divs.length-1].width+=15}else{divs.push({"class":null,width:15})}}}}}for(i=divs.length-1;i>=0;i--){if(divs[i]["class"]){html+='<div class="tree '+divs[i]["class"]+'" />'}else{html+='<div style="width:'+divs[i].width+'px" />'}}if(html){$("#rcmtab"+uid).html(html)}};this.update_thread_root=function(uid,flag){if(!this.env.threading){return}var root=this.message_list.find_root(uid);if(uid==root){return}var p=this.message_list.rows[root];if(flag=="read"&&p.unread_children){p.unread_children--}else{if(flag=="unread"&&p.has_children){p.unread_children=p.unread_children?p.unread_children+1:1}else{return}}this.set_message_icon(root);this.set_unread_children(root)};this.update_thread=function(uid){if(!this.env.threading){return 0}var r,parent,count=0,rows=this.message_list.rows,row=rows[uid],depth=rows[uid].depth,roots=[];if(!row.depth){count--}else{if(row.unread){parent=this.message_list.find_root(uid);rows[parent].unread_children--;this.set_unread_children(parent)}}parent=row.parent_uid;row=row.obj.nextSibling;while(row){if(row.nodeType==1&&(r=rows[row.uid])){if(!r.depth||r.depth<=depth){break}r.depth--;$("#rcmtab"+r.uid).width(r.depth*15).html("");if(!r.depth){count++;r.parent_uid=0;if(r.has_children){$("#rcmrow"+r.uid+" .leaf:first").attr("id","rcmexpando"+r.uid).attr("class",(r.obj.style.display!="none"?"expanded":"collapsed")).bind("mousedown",{uid:r.uid,p:this},function(e){return e.data.p.expand_message_row(e,e.data.uid)});r.unread_children=0;roots.push(r)}if(r.obj.style.display=="none"){$(r.obj).show()}}else{if(r.depth==depth){r.parent_uid=parent}if(r.unread&&roots.length){roots[roots.length-1].unread_children++}}}row=row.nextSibling}for(var i=0;i<roots.length;i++){this.set_unread_children(roots[i].uid)}return count};this.delete_excessive_thread_rows=function(){var rows=this.message_list.rows,tbody=this.message_list.list.tBodies[0],row=tbody.firstChild,cnt=this.env.pagesize+1;while(row){if(row.nodeType==1&&(r=rows[row.uid])){if(!r.depth&&cnt){cnt--}if(!cnt){this.message_list.remove_row(row.uid)}}row=row.nextSibling}};this.set_message_icon=function(uid){var css_class,row=this.message_list.rows[uid];if(!row){return false}if(row.icon){css_class="msgicon";if(row.deleted){css_class+=" deleted"}else{if(row.unread){css_class+=" unread"}else{if(row.unread_children){css_class+=" unreadchildren"}}}if(row.msgicon==row.icon){if(row.replied){css_class+=" replied"}if(row.forwarded){css_class+=" forwarded"}css_class+=" status"}row.icon.className=css_class}if(row.msgicon&&row.msgicon!=row.icon){css_class="msgicon";if(!row.unread&&row.unread_children){css_class+=" unreadchildren"}if(row.replied){css_class+=" replied"}if(row.forwarded){css_class+=" forwarded"}row.msgicon.className=css_class}if(row.flagicon){css_class=(row.flagged?"flagged":"unflagged");row.flagicon.className=css_class}};this.set_message_status=function(uid,flag,status){var row=this.message_list.rows[uid];if(!row){return false}if(flag=="unread"){row.unread=status}else{if(flag=="deleted"){row.deleted=status}else{if(flag=="replied"){row.replied=status}else{if(flag=="forwarded"){row.forwarded=status}else{if(flag=="flagged"){row.flagged=status}}}}}};this.set_message=function(uid,flag,status){var row=this.message_list&&this.message_list.rows[uid];if(!row){return false}if(flag){this.set_message_status(uid,flag,status)}var rowobj=$(row.obj);if(row.unread&&!rowobj.hasClass("unread")){rowobj.addClass("unread")}else{if(!row.unread&&rowobj.hasClass("unread")){rowobj.removeClass("unread")}}if(row.deleted&&!rowobj.hasClass("deleted")){rowobj.addClass("deleted")}else{if(!row.deleted&&rowobj.hasClass("deleted")){rowobj.removeClass("deleted")}}if(row.flagged&&!rowobj.hasClass("flagged")){rowobj.addClass("flagged")}else{if(!row.flagged&&rowobj.hasClass("flagged")){rowobj.removeClass("flagged")}}this.set_unread_children(uid);this.set_message_icon(uid)};this.set_unread_children=function(uid){var row=this.message_list.rows[uid];if(row.parent_uid){return}if(!row.unread&&row.unread_children&&!row.expanded){$(row.obj).addClass("unroot")}else{$(row.obj).removeClass("unroot")}};this.copy_messages=function(mbox){if(mbox&&typeof mbox==="object"){mbox=mbox.id}if(!mbox||mbox==this.env.mailbox){return}var post_data=this.selection_post_data({_target_mbox:mbox});if(!post_data._uid){return}this.http_post("copy",post_data,this.display_message(this.get_label("copyingmessage"),"loading"))};this.move_messages=function(mbox){if(mbox&&typeof mbox==="object"){mbox=mbox.id}if(!mbox||mbox==this.env.mailbox){return}var lock=false,post_data=this.selection_post_data({_target_mbox:mbox});if(!post_data._uid){return}if(this.env.action=="show"){lock=this.set_busy(true,"movingmessage")}else{this.show_contentframe(false)}this.enable_command(this.env.message_commands,false);this._with_selected_messages("moveto",post_data,lock)};this.delete_messages=function(event){var uid,i,len,trash=this.env.trash_mailbox,list=this.message_list,selection=list?list.get_selection():[];if(!this.env.uid&&!selection.length){return}for(i=0,len=selection.length;i<len;i++){uid=selection[i];if(list.rows[uid].has_children&&!list.rows[uid].expanded){list.select_children(uid)}}if(this.env.flag_for_deletion){this.mark_message("delete");return false}else{if(!trash||this.env.mailbox==trash){this.permanently_remove_messages()}else{if(this.env.delete_junk&&this.env.junk_mailbox&&this.env.mailbox==this.env.junk_mailbox){this.permanently_remove_messages()}else{if((list&&list.modkey==SHIFT_KEY)||(event&&rcube_event.get_modifier(event)==SHIFT_KEY)){if(confirm(this.get_label("deletemessagesconfirm"))){this.permanently_remove_messages()}}else{this.move_messages(trash)}}}}return true};this.permanently_remove_messages=function(){var post_data=this.selection_post_data();if(!post_data._uid){return}this.show_contentframe(false);this._with_selected_messages("delete",post_data)};this._with_selected_messages=function(action,post_data,lock){var count=0,msg;if(this.message_list){var n,id,root,roots=[],selection=this.message_list.get_selection();for(n=0,len=selection.length;n<len;n++){id=selection[n];if(this.env.threading){count+=this.update_thread(id);root=this.message_list.find_root(id);if(root!=id&&$.inArray(root,roots)<0){roots.push(root)}}this.message_list.remove_row(id,(this.env.display_next&&n==selection.length-1))}if(!this.env.display_next){this.message_list.clear_selection()}for(n=0,len=roots.length;n<len;n++){this.add_tree_icons(roots[n])}}if(this.env.display_next&&this.env.next_uid){post_data._next_uid=this.env.next_uid}if(count<0){post_data._count=(count*-1)}else{if(count>0){this.delete_excessive_thread_rows()}}if(!lock){msg=action=="moveto"?"movingmessage":"deletingmessage";lock=this.display_message(this.get_label(msg),"loading")}this.http_post(action,post_data,lock)};this.selection_post_data=function(data){if(typeof(data)!="object"){data={}}data._mbox=this.env.mailbox;if(!data._uid){var uids=this.env.uid?[this.env.uid]:this.message_list.get_selection();data._uid=this.uids_to_list(uids)}if(this.env.action){data._from=this.env.action}if(this.env.search_request){data._search=this.env.search_request}return data};this.mark_message=function(flag,uid){var a_uids=[],r_uids=[],len,n,id,list=this.message_list;if(uid){a_uids[0]=uid}else{if(this.env.uid){a_uids[0]=this.env.uid}else{if(list){a_uids=list.get_selection()}}}if(!list){r_uids=a_uids}else{list.focus();for(n=0,len=a_uids.length;n<len;n++){id=a_uids[n];if((flag=="read"&&list.rows[id].unread)||(flag=="unread"&&!list.rows[id].unread)||(flag=="delete"&&!list.rows[id].deleted)||(flag=="undelete"&&list.rows[id].deleted)||(flag=="flagged"&&!list.rows[id].flagged)||(flag=="unflagged"&&list.rows[id].flagged)){r_uids.push(id)}}}if(!r_uids.length&&!this.select_all_mode){return}switch(flag){case"read":case"unread":this.toggle_read_status(flag,r_uids);break;case"delete":case"undelete":this.toggle_delete_status(r_uids);break;case"flagged":case"unflagged":this.toggle_flagged_status(flag,a_uids);break}};this.toggle_read_status=function(flag,a_uids){var i,len=a_uids.length,post_data=this.selection_post_data({_uid:this.uids_to_list(a_uids),_flag:flag}),lock=this.display_message(this.get_label("markingmessage"),"loading");for(i=0;i<len;i++){this.set_message(a_uids[i],"unread",(flag=="unread"?true:false))}this.http_post("mark",post_data,lock);for(i=0;i<len;i++){this.update_thread_root(a_uids[i],flag)}};this.toggle_flagged_status=function(flag,a_uids){var i,len=a_uids.length,post_data=this.selection_post_data({_uid:this.uids_to_list(a_uids),_flag:flag}),lock=this.display_message(this.get_label("markingmessage"),"loading");for(i=0;i<len;i++){this.set_message(a_uids[i],"flagged",(flag=="flagged"?true:false))}this.http_post("mark",post_data,lock)};this.toggle_delete_status=function(a_uids){var len=a_uids.length,i,uid,all_deleted=true,rows=this.message_list?this.message_list.rows:[];if(len==1){if(!rows.length||(rows[a_uids[0]]&&!rows[a_uids[0]].deleted)){this.flag_as_deleted(a_uids)}else{this.flag_as_undeleted(a_uids)}return true}for(i=0;i<len;i++){uid=a_uids[i];if(rows[uid]&&!rows[uid].deleted){all_deleted=false;break}}if(all_deleted){this.flag_as_undeleted(a_uids)}else{this.flag_as_deleted(a_uids)}return true};this.flag_as_undeleted=function(a_uids){var i,len=a_uids.length,post_data=this.selection_post_data({_uid:this.uids_to_list(a_uids),_flag:"undelete"}),lock=this.display_message(this.get_label("markingmessage"),"loading");for(i=0;i<len;i++){this.set_message(a_uids[i],"deleted",false)}this.http_post("mark",post_data,lock)};this.flag_as_deleted=function(a_uids){var r_uids=[],post_data=this.selection_post_data({_uid:this.uids_to_list(a_uids),_flag:"delete"}),lock=this.display_message(this.get_label("markingmessage"),"loading"),rows=this.message_list?this.message_list.rows:[],count=0;for(var i=0,len=a_uids.length;i<len;i++){uid=a_uids[i];if(rows[uid]){if(rows[uid].unread){r_uids[r_uids.length]=uid}if(this.env.skip_deleted){count+=this.update_thread(uid);this.message_list.remove_row(uid,(this.env.display_next&&i==this.message_list.selection.length-1))}else{this.set_message(uid,"deleted",true)}}}if(this.env.skip_deleted&&this.message_list){if(!this.env.display_next){this.message_list.clear_selection()}if(count<0){post_data._count=(count*-1)}else{if(count>0){this.delete_excessive_thread_rows()}}}if(r_uids.length){post_data._ruid=this.uids_to_list(r_uids)}if(this.env.skip_deleted&&this.env.display_next&&this.env.next_uid){post_data._next_uid=this.env.next_uid}this.http_post("mark",post_data,lock)};this.flag_deleted_as_read=function(uids){var icn_src,uid,i,len,rows=this.message_list?this.message_list.rows:[];uids=String(uids).split(",");for(i=0,len=uids.length;i<len;i++){uid=uids[i];if(rows[uid]){this.set_message(uid,"unread",false)}}};this.uids_to_list=function(uids){return this.select_all_mode?"*":uids.join(",")};this.set_button_titles=function(){var label="deletemessage";if(!this.env.flag_for_deletion&&this.env.trash_mailbox&&this.env.mailbox!=this.env.trash_mailbox&&(!this.env.delete_junk||!this.env.junk_mailbox||this.env.mailbox!=this.env.junk_mailbox)){label="movemessagetotrash"}this.set_alttext("delete",label)};this.expunge_mailbox=function(mbox){var lock,post_data={_mbox:mbox};if(mbox==this.env.mailbox){lock=this.set_busy(true,"loading");post_data._reload=1;if(this.env.search_request){post_data._search=this.env.search_request}}this.http_post("expunge",post_data,lock)};this.purge_mailbox=function(mbox){var lock,post_data={_mbox:mbox};if(!confirm(this.get_label("purgefolderconfirm"))){return false}if(mbox==this.env.mailbox){lock=this.set_busy(true,"loading");post_data._reload=1}this.http_post("purge",post_data,lock)};this.purge_mailbox_test=function(){return(this.env.exists&&(this.env.mailbox==this.env.trash_mailbox||this.env.mailbox==this.env.junk_mailbox||this.env.mailbox.match("^"+RegExp.escape(this.env.trash_mailbox)+RegExp.escape(this.env.delimiter))||this.env.mailbox.match("^"+RegExp.escape(this.env.junk_mailbox)+RegExp.escape(this.env.delimiter))))};this.login_user_keyup=function(e){var key=rcube_event.get_keycode(e);var passwd=$("#rcmloginpwd");if(key==13&&passwd.length&&!passwd.val()){passwd.focus();return rcube_event.cancel(e)}return true};this.open_compose_step=function(p){var url=this.url("mail/compose",p);if(this.env.compose_extwin&&!this.env.extwin){this.open_window(url,1150)}else{this.redirect(url);if(this.env.extwin){window.resizeTo(Math.max(1150,$(window).width()),$(window).height()+24)}}};this.init_messageform=function(){if(!this.gui_objects.messageform){return false}var input_from=$("[name='_from']"),input_to=$("[name='_to']"),input_subject=$("input[name='_subject']"),input_message=$("[name='_message']").get(0),html_mode=$("input[name='_is_html']").val()=="1",ac_fields=["cc","bcc","replyto","followupto"],ac_props,opener_rc=this.opener();if(opener_rc&&opener_rc.env.action=="compose"){setTimeout(function(){opener.history.back()},100);this.env.opened_extwin=true}if(this.env.autocomplete_threads>0){ac_props={threads:this.env.autocomplete_threads,sources:this.env.autocomplete_sources}}this.init_address_input_events(input_to,ac_props);for(var i in ac_fields){this.init_address_input_events($("[name='_"+ac_fields[i]+"']"),ac_props)}if(!html_mode){this.set_caret_pos(input_message,this.env.top_posting?0:$(input_message).val().length);if(input_from.prop("type")=="select-one"){this.change_identity(input_from[0])}}if(input_to.val()==""){input_to.focus()}else{if(input_subject.val()==""){input_subject.focus()}else{if(input_message){input_message.focus()}}}this.env.compose_focus_elem=document.activeElement;this.compose_field_hash(true);this.auto_save_start()};this.init_address_input_events=function(obj,props){this.env.recipients_delimiter=this.env.recipients_separator+" ";obj[bw.ie||bw.safari||bw.chrome?"keydown":"keypress"](function(e){return ref.ksearch_keydown(e,this,props)}).attr("autocomplete","off")};this.submit_messageform=function(draft){var form=this.gui_objects.messageform;if(!form){return}var msgid=this.set_busy(true,draft?"savingmessage":"sendingmessage"),lang=this.spellcheck_lang(),files=[];$("li",this.gui_objects.attachmentlist).each(function(){files.push(this.id.replace(/^rcmfile/,""))});$('input[name="_attachments"]',form).val(files.join());form.target="savetarget";form._draft.value=draft?"1":"";form.action=this.add_url(form.action,"_unlock",msgid);form.action=this.add_url(form.action,"_lang",lang);this.submit_timer=setTimeout(function(){ref.set_busy(false,null,msgid);ref.display_message(ref.get_label("requesttimedout"),"error")},this.env.request_timeout*1000);form.submit()};this.compose_recipient_select=function(list){this.enable_command("add-recipient",list.selection.length>0)};this.compose_add_recipient=function(field){var recipients=[],input=$("#_"+field),delim=this.env.recipients_delimiter;if(this.contact_list&&this.contact_list.selection.length){for(var id,n=0;n<this.contact_list.selection.length;n++){id=this.contact_list.selection[n];if(id&&this.env.contactdata[id]){recipients.push(this.env.contactdata[id]);if(id.charAt(0)=="E"&&this.env.contactdata[id].indexOf("@")<0&&input.length){var gid=id.substr(1);this.group2expand[gid]={name:this.env.contactdata[id],input:input.get(0)};this.http_request("group-expand",{_source:this.env.source,_gid:gid},false)}}}}if(recipients.length&&input.length){var oldval=input.val(),rx=new RegExp(RegExp.escape(delim)+"\\s*$");if(oldval&&!rx.test(oldval)){oldval+=delim+" "}input.val(oldval+recipients.join(delim+" ")+delim+" ");this.triggerEvent("add-recipient",{field:field,recipients:recipients})}};this.check_compose_input=function(cmd){var ed,input_to=$("[name='_to']"),input_cc=$("[name='_cc']"),input_bcc=$("[name='_bcc']"),input_from=$("[name='_from']"),input_subject=$("[name='_subject']"),input_message=$("[name='_message']");if(input_from.prop("type")=="text"&&!rcube_check_email(input_from.val(),true)){alert(this.get_label("nosenderwarning"));input_from.focus();return false}var recipients=input_to.val()?input_to.val():(input_cc.val()?input_cc.val():input_bcc.val());if(!rcube_check_email(recipients.replace(/^\s+/,"").replace(/[\s,;]+$/,""),true)){alert(this.get_label("norecipientwarning"));input_to.focus();return false}for(var key in this.env.attachments){if(typeof this.env.attachments[key]==="object"&&!this.env.attachments[key].complete){alert(this.get_label("notuploadedwarning"));return false}}if(input_subject.val()==""){var myprompt=$('<div class="prompt">').html('<div class="message">'+this.get_label("nosubjectwarning")+"</div>").appendTo(document.body);var prompt_value=$("<input>").attr("type","text").attr("size",30).appendTo(myprompt).val(this.get_label("nosubject"));var buttons={};buttons[this.get_label("cancel")]=function(){input_subject.focus();$(this).dialog("close")};buttons[this.get_label("sendmessage")]=function(){input_subject.val(prompt_value.val());$(this).dialog("close");ref.command(cmd,{nocheck:true})};myprompt.dialog({modal:true,resizable:false,buttons:buttons,close:function(event,ui){$(this).remove()}});prompt_value.select();return false}this.stop_spellchecking();if(window.tinyMCE){ed=tinyMCE.get(this.env.composebody)}if(!ed&&input_message.val()==""&&!confirm(this.get_label("nobodywarning"))){input_message.focus();return false}else{if(ed){if(!ed.getContent()&&!confirm(this.get_label("nobodywarning"))){ed.focus();return false}tinyMCE.triggerSave()}}return true};this.toggle_editor=function(props){this.stop_spellchecking();if(props.mode=="html"){this.plain2html($("#"+props.id).val(),props.id);tinyMCE.execCommand("mceAddControl",false,props.id);if(this.env.default_font){setTimeout(function(){$(tinyMCE.get(props.id).getBody()).css("font-family",rcmail.env.default_font)},500)}}else{var thisMCE=tinyMCE.get(props.id),existingHtml;if(existingHtml=thisMCE.getContent()){if(!confirm(this.get_label("editorwarning"))){return false}this.html2plain(existingHtml,props.id)}tinyMCE.execCommand("mceRemoveControl",false,props.id)}return true};this.stop_spellchecking=function(){var ed;if(window.tinyMCE&&(ed=tinyMCE.get(this.env.composebody))){if(ed.plugins&&ed.plugins.spellchecker&&ed.plugins.spellchecker.active){ed.execCommand("mceSpellCheck")}}else{if(ed=this.env.spellcheck){if(ed.state&&ed.state!="ready"&&ed.state!="no_error_found"){$(ed.spell_span).trigger("click")}}}this.spellcheck_state()};this.spellcheck_state=function(){var ed,active;if(window.tinyMCE&&(ed=tinyMCE.get(this.env.composebody))&&ed.plugins&&ed.plugins.spellchecker){active=ed.plugins.spellchecker.active}else{if((ed=this.env.spellcheck)&&ed.state){active=ed.state!="ready"&&ed.state!="no_error_found"}}if(rcmail.buttons.spellcheck){$("#"+rcmail.buttons.spellcheck[0].id)[active?"addClass":"removeClass"]("selected")}return active};this.spellcheck_lang=function(){var ed;if(window.tinyMCE&&(ed=tinyMCE.get(this.env.composebody))&&ed.plugins&&ed.plugins.spellchecker){return ed.plugins.spellchecker.selectedLang}else{if(this.env.spellcheck){return GOOGIE_CUR_LANG}}};this.spellcheck_lang_set=function(lang){var ed;if(window.tinyMCE&&(ed=tinyMCE.get(this.env.composebody))&&ed.plugins){ed.plugins.spellchecker.selectedLang=lang}else{if(this.env.spellcheck){this.env.spellcheck.setCurrentLanguage(lang)}}};this.spellcheck_resume=function(ishtml,data){if(ishtml){var ed=tinyMCE.get(this.env.composebody);sp=ed.plugins.spellchecker;sp.active=1;sp._markWords(data);ed.nodeChanged()}else{var sp=this.env.spellcheck;sp.prepare(false,true);sp.processData(data)}this.spellcheck_state()};this.set_draft_id=function(id){var rc;if(!this.env.draft_id&&id&&(rc=this.opener())){if(rc.env.task=="mail"&&rc.env.action==""&&rc.env.mailbox==this.env.drafts_mailbox){rc.command("checkmail")}}this.env.draft_id=id;$("input[name='_draft_saveid']").val(id)};this.auto_save_start=function(){if(this.env.draft_autosave){this.save_timer=setTimeout(function(){ref.command("savedraft")},this.env.draft_autosave*1000)}this.busy=false};this.compose_field_hash=function(save){var ed,i,val,str="",hash_fields=["to","cc","bcc","subject"];for(i=0;i<hash_fields.length;i++){if(val=$('[name="_'+hash_fields[i]+'"]').val()){str+=val+":"}}if(window.tinyMCE&&(ed=tinyMCE.get(this.env.composebody))){str+=ed.getContent()}else{str+=$("[name='_message']").val()}if(this.env.attachments){for(var upload_id in this.env.attachments){str+=upload_id}}if(save){this.cmp_hash=str}return str};this.change_identity=function(obj,show_sig){if(!obj||!obj.options){return false}if(!show_sig){show_sig=this.env.show_sig}if(!this.env.identities_initialized){this.env.identities_initialized=true;if(this.env.show_sig_later){this.env.show_sig=true}if(this.env.opened_extwin){return}}var cursor_pos,p=-1,id=obj.options[obj.selectedIndex].value,input_message=$("[name='_message']"),message=input_message.val(),is_html=($("input[name='_is_html']").val()=="1"),sig=this.env.identity;if(this.env.signatures&&this.env.signatures[id]){this.enable_command("insert-sig",true);this.env.compose_commands.push("insert-sig")}else{this.enable_command("insert-sig",false)}if(!is_html){if(show_sig&&sig&&this.env.signatures&&this.env.signatures[sig]){sig=this.env.signatures[sig].text;sig=sig.replace(/\r\n/g,"\n");p=this.env.top_posting?message.indexOf(sig):message.lastIndexOf(sig);if(p>=0){message=message.substring(0,p)+message.substring(p+sig.length,message.length)}}if(show_sig&&this.env.signatures&&this.env.signatures[id]){sig=this.env.signatures[id].text;sig=sig.replace(/\r\n/g,"\n");if(this.env.top_posting){if(p>=0){message=message.substring(0,p)+sig+message.substring(p,message.length);cursor_pos=p-1}else{if(!message){cursor_pos=0;message="\n\n"+sig}else{if(pos=this.get_caret_pos(input_message.get(0))){message=message.substring(0,pos)+"\n"+sig+"\n\n"+message.substring(pos,message.length);cursor_pos=pos}else{cursor_pos=0;message="\n\n"+sig+"\n\n"+message.replace(/^[\r\n]+/,"")}}}}else{message=message.replace(/[\r\n]+$/,"");cursor_pos=!this.env.top_posting&&message.length?message.length+1:0;message+="\n\n"+sig}}else{cursor_pos=this.env.top_posting?0:message.length}input_message.val(message);this.set_caret_pos(input_message.get(0),cursor_pos)}else{if(show_sig&&this.env.signatures){var editor=tinyMCE.get(this.env.composebody),sigElem=editor.dom.get("_rc_sig");if(!sigElem){var body=editor.getBody(),doc=editor.getDoc();sigElem=doc.createElement("div");sigElem.setAttribute("id","_rc_sig");if(this.env.top_posting){editor.getWin().focus();var node=editor.selection.getNode();if(node.nodeName=="BODY"){body.insertBefore(sigElem,body.firstChild);body.insertBefore(doc.createElement("br"),body.firstChild)}else{body.insertBefore(sigElem,node.nextSibling);body.insertBefore(doc.createElement("br"),node.nextSibling)}}else{if(bw.ie){body.appendChild(doc.createElement("br"))}body.appendChild(sigElem)}}if(this.env.signatures[id]){sigElem.innerHTML=this.env.signatures[id].html}}}this.env.identity=id;return true};this.upload_file=function(form){if(!form){return false}var size=0,numfiles=0;$("input[type=file]",form).each(function(i,field){var files=field.files?field.files.length:(field.value?1:0);if(field.files){for(var i=0;i<files;i++){size+=field.files[i].size}}numfiles+=files});if(numfiles){if(this.env.max_filesize&&this.env.filesizeerror&&size>this.env.max_filesize){this.display_message(this.env.filesizeerror,"error");return}var frame_name=this.async_upload_form(form,"upload",function(e){var d,content="";try{if(this.contentDocument){d=this.contentDocument}else{if(this.contentWindow){d=this.contentWindow.document}}content=d.childNodes[0].innerHTML}catch(err){}if(!content.match(/add2attachment/)&&(!bw.opera||(rcmail.env.uploadframe&&rcmail.env.uploadframe==e.data.ts))){if(!content.match(/display_message/)){rcmail.display_message(rcmail.get_label("fileuploaderror"),"error")}rcmail.remove_from_attachment_list(e.data.ts)}if(bw.opera){rcmail.env.uploadframe=e.data.ts}});var content="<span>"+this.get_label("uploading"+(numfiles>1?"many":""))+"</span>",ts=frame_name.replace(/^rcmupload/,"");this.add2attachment_list(ts,{name:"",html:content,classname:"uploading",frame:frame_name,complete:false});if(this.env.upload_progress_time){this.upload_progress_start("upload",ts)}}this.gui_objects.attachmentform=form;return true};this.add2attachment_list=function(name,att,upload_id){if(!this.gui_objects.attachmentlist){return false}if(!att.complete&&ref.env.loadingicon){att.html='<img src="'+ref.env.loadingicon+'" alt="" class="uploading" />'+att.html}if(!att.complete&&att.frame){att.html='<a title="'+this.get_label("cancel")+'" onclick="return rcmail.cancel_attachment_upload(\''+name+"', '"+att.frame+'\');" href="#cancelupload" class="cancelupload">'+(this.env.cancelicon?'<img src="'+this.env.cancelicon+'" alt="" />':this.get_label("cancel"))+"</a>"+att.html}var indicator,li=$("<li>");li.attr("id",name).addClass(att.classname).html(att.html).on("mouseover",function(){rcube_webmail.long_subject_title_ex(this,0)});if(upload_id&&(indicator=document.getElementById(upload_id))){li.replaceAll(indicator)}else{li.appendTo(this.gui_objects.attachmentlist)}if(upload_id&&this.env.attachments[upload_id]){delete this.env.attachments[upload_id]}this.env.attachments[name]=att;return true};this.remove_from_attachment_list=function(name){delete this.env.attachments[name];$("#"+name).remove()};this.remove_attachment=function(name){if(name&&this.env.attachments[name]){this.http_post("remove-attachment",{_id:this.env.compose_id,_file:name})}return true};this.cancel_attachment_upload=function(name,frame_name){if(!name||!frame_name){return false}this.remove_from_attachment_list(name);$("iframe[name='"+frame_name+"']").remove();return false};this.upload_progress_start=function(action,name){setTimeout(function(){rcmail.http_request(action,{_progress:name})},this.env.upload_progress_time*1000)};this.upload_progress_update=function(param){var elem=$("#"+param.name+"> span");if(!elem.length||!param.text){return}elem.text(param.text);if(!param.done){this.upload_progress_start(param.action,param.name)}};this.add_contact=function(value){if(value){this.http_post("addcontact",{_address:value})}return true};this.qsearch=function(value){if(value!=""){var r,lock=this.set_busy(true,"searching"),url=this.search_params(value);if(this.message_list){this.clear_message_list()}else{if(this.contact_list){this.list_contacts_clear()}}if(this.env.source){url._source=this.env.source}if(this.env.group){url._gid=this.env.group}this.env.current_page=1;var action=this.env.action=="compose"&&this.contact_list?"search-contacts":"search";r=this.http_request(action,url,lock);this.env.qsearch={lock:lock,request:r}}};this.search_params=function(search,filter){var n,url={},mods_arr=[],mods=this.env.search_mods,mbox=this.env.mailbox;if(!filter&&this.gui_objects.search_filter){filter=this.gui_objects.search_filter.value}if(!search&&this.gui_objects.qsearchbox){search=this.gui_objects.qsearchbox.value}if(filter){url._filter=filter}if(search){url._q=search;if(mods&&this.message_list){mods=mods[mbox]?mods[mbox]:mods["*"]}if(mods){for(n in mods){mods_arr.push(n)}url._headers=mods_arr.join(",")}}if(mbox){url._mbox=mbox}return url};this.reset_qsearch=function(){if(this.gui_objects.qsearchbox){this.gui_objects.qsearchbox.value=""}if(this.env.qsearch){this.abort_request(this.env.qsearch)}this.env.qsearch=null;this.env.search_request=null;this.env.search_id=null};this.sent_successfully=function(type,msg,target){this.display_message(msg,type);if(this.env.extwin){var rc=this.opener();this.lock_form(this.gui_objects.messageform);if(rc){rc.display_message(msg,type);if(target&&rc.env.task=="mail"&&rc.env.action==""&&rc.env.mailbox==target){rc.command("checkmail")}}setTimeout(function(){window.close()},1000)}else{setTimeout(function(){ref.list_mailbox()},500)}};this.ksearch_keydown=function(e,obj,props){if(this.ksearch_timer){clearTimeout(this.ksearch_timer)}var highlight,key=rcube_event.get_keycode(e),mod=rcube_event.get_modifier(e);switch(key){case 38:case 40:if(!this.ksearch_visible()){break}var dir=key==38?1:0;highlight=document.getElementById("rcmksearchSelected");if(!highlight){highlight=this.ksearch_pane.__ul.firstChild}if(highlight){this.ksearch_select(dir?highlight.previousSibling:highlight.nextSibling)}return rcube_event.cancel(e);case 9:if(mod==SHIFT_KEY||!this.ksearch_visible()){this.ksearch_hide();return}case 13:if(!this.ksearch_visible()){return false}this.insert_recipient(this.ksearch_selected);this.ksearch_hide();return rcube_event.cancel(e);case 27:this.ksearch_hide();return;case 37:case 39:if(mod!=SHIFT_KEY){return}}this.ksearch_timer=setTimeout(function(){ref.ksearch_get_results(props)},200);this.ksearch_input=obj;return true};this.ksearch_visible=function(){return(this.ksearch_selected!==null&&this.ksearch_selected!==undefined&&this.ksearch_value)};this.ksearch_select=function(node){var current=$("#rcmksearchSelected");if(current[0]&&node){current.removeAttr("id").removeClass("selected")}if(node){$(node).attr("id","rcmksearchSelected").addClass("selected");this.ksearch_selected=node._rcm_id}};this.insert_recipient=function(id){if(id===null||!this.env.contacts[id]||!this.ksearch_input){return}var inp_value=this.ksearch_input.value,cpos=this.get_caret_pos(this.ksearch_input),p=inp_value.lastIndexOf(this.ksearch_value,cpos),trigger=false,insert="",pre=inp_value.substring(0,p),end=inp_value.substring(p+this.ksearch_value.length,inp_value.length);this.ksearch_destroy();if(typeof this.env.contacts[id]==="object"&&this.env.contacts[id].id){insert+=this.env.contacts[id].name+this.env.recipients_delimiter;this.group2expand[this.env.contacts[id].id]=$.extend({input:this.ksearch_input},this.env.contacts[id]);this.http_request("mail/group-expand",{_source:this.env.contacts[id].source,_gid:this.env.contacts[id].id},false)}else{if(typeof this.env.contacts[id]==="string"){insert=this.env.contacts[id]+this.env.recipients_delimiter;trigger=true}}this.ksearch_input.value=pre+insert+end;cpos=p+insert.length;if(this.ksearch_input.setSelectionRange){this.ksearch_input.setSelectionRange(cpos,cpos)}if(trigger){this.triggerEvent("autocomplete_insert",{field:this.ksearch_input,insert:insert})}};this.replace_group_recipients=function(id,recipients){if(this.group2expand[id]){this.group2expand[id].input.value=this.group2expand[id].input.value.replace(this.group2expand[id].name,recipients);this.triggerEvent("autocomplete_insert",{field:this.group2expand[id].input,insert:recipients});this.group2expand[id]=null}};this.ksearch_get_results=function(props){var inp_value=this.ksearch_input?this.ksearch_input.value:null;if(inp_value===null){return}if(this.ksearch_pane&&this.ksearch_pane.is(":visible")){this.ksearch_pane.hide()}var cpos=this.get_caret_pos(this.ksearch_input),p=inp_value.lastIndexOf(this.env.recipients_separator,cpos-1),q=inp_value.substring(p+1,cpos),min=this.env.autocomplete_min_length,ac=this.ksearch_data;q=$.trim(q);if(q==this.ksearch_value){return}this.ksearch_destroy();if(q.length&&q.length<min){if(!this.ksearch_info){this.ksearch_info=this.display_message(this.get_label("autocompletechars").replace("$min",min))}return}var old_value=this.ksearch_value;this.ksearch_value=q;if(!q.length){return}if(old_value&&old_value.length&&q.indexOf(old_value)==0&&(!ac||ac.num<=0)&&this.env.contacts&&!this.env.contacts.length){return}var i,lock,source,xhr,reqid=new Date().getTime(),post_data={_search:q,_id:reqid},threads=props&&props.threads?props.threads:1,sources=props&&props.sources?props.sources:[],action=props&&props.action?props.action:"mail/autocomplete";this.ksearch_data={id:reqid,sources:sources.slice(),action:action,locks:[],requests:[],num:sources.length};for(i=0;i<threads;i++){source=this.ksearch_data.sources.shift();if(threads>1&&source===undefined){break}post_data._source=source?source:"";lock=this.display_message(this.get_label("searching"),"loading");xhr=this.http_post(action,post_data,lock);this.ksearch_data.locks.push(lock);this.ksearch_data.requests.push(xhr)}};this.ksearch_query_results=function(results,search,reqid){if(!this.ksearch_value){return}if(this.ksearch_input&&search!=this.ksearch_value){return}var i,len,ul,li,text,init,value=this.ksearch_value,data=this.ksearch_data,maxlen=this.env.autocomplete_max?this.env.autocomplete_max:15;if(!this.ksearch_pane){ul=$("<ul>");this.ksearch_pane=$("<div>").attr("id","rcmKSearchpane").css({position:"absolute","z-index":30000}).append(ul).appendTo(document.body);this.ksearch_pane.__ul=ul[0]}ul=this.ksearch_pane.__ul;if(reqid&&this.ksearch_pane.data("reqid")==reqid){maxlen-=ul.childNodes.length}else{this.ksearch_pane.data("reqid",reqid);init=1;ul.innerHTML="";this.env.contacts=[];var pos=$(this.ksearch_input).offset();this.ksearch_pane.css({left:pos.left+"px",top:(pos.top+this.ksearch_input.offsetHeight)+"px",display:"none"})}if(results&&(len=results.length)){for(i=0;i<len&&maxlen>0;i++){text=typeof results[i]==="object"?results[i].name:results[i];li=document.createElement("LI");li.innerHTML=text.replace(new RegExp("("+RegExp.escape(value)+")","ig"),"##$1%%").replace(/</g,"<").replace(/>/g,">").replace(/##([^%]+)%%/g,"<b>$1</b>");li.onmouseover=function(){ref.ksearch_select(this)};li.onmouseup=function(){ref.ksearch_click(this)};li._rcm_id=this.env.contacts.length+i;ul.appendChild(li);maxlen-=1}}if(ul.childNodes.length){this.ksearch_pane.show();if(!this.env.contacts.length){$("li:first",ul).attr("id","rcmksearchSelected").addClass("selected");this.ksearch_selected=0}}if(len){this.env.contacts=this.env.contacts.concat(results)}if(data.id==reqid){data.num--;if(maxlen>0&&data.sources.length){var lock,xhr,source=data.sources.shift(),post_data;if(source){post_data={_search:value,_id:reqid,_source:source};lock=this.display_message(this.get_label("searching"),"loading");xhr=this.http_post(data.action,post_data,lock);this.ksearch_data.locks.push(lock);this.ksearch_data.requests.push(xhr)}}else{if(!maxlen){if(!this.ksearch_msg){this.ksearch_msg=this.display_message(this.get_label("autocompletemore"))}this.ksearch_abort()}}}};this.ksearch_click=function(node){if(this.ksearch_input){this.ksearch_input.focus()}this.insert_recipient(node._rcm_id);this.ksearch_hide()};this.ksearch_blur=function(){if(this.ksearch_timer){clearTimeout(this.ksearch_timer)}this.ksearch_input=null;this.ksearch_hide()};this.ksearch_hide=function(){this.ksearch_selected=null;this.ksearch_value="";if(this.ksearch_pane){this.ksearch_pane.hide()}this.ksearch_destroy()};this.ksearch_destroy=function(){this.ksearch_abort();if(this.ksearch_info){this.hide_message(this.ksearch_info)}if(this.ksearch_msg){this.hide_message(this.ksearch_msg)}this.ksearch_data=null;this.ksearch_info=null;this.ksearch_msg=null};this.ksearch_abort=function(){var i,len,ac=this.ksearch_data;if(!ac){return}for(i=0,len=ac.locks.length;i<len;i++){this.abort_request({request:ac.requests[i],lock:ac.locks[i]})}};this.contactlist_keypress=function(list){if(list.key_pressed==list.DELETE_KEY){this.command("delete")}};this.contactlist_select=function(list){if(this.preview_timer){clearTimeout(this.preview_timer)}var n,id,sid,ref=this,writable=false,source=this.env.source?this.env.address_sources[this.env.source]:null;if(id=list.get_single_selection()){this.preview_timer=setTimeout(function(){ref.load_contact(id,"show")},200)}else{if(this.env.contentframe){this.show_contentframe(false)}}if(list.selection.length){this.env.selection_sources=[];if(!source){for(n in list.selection){sid=String(list.selection[n]).replace(/^[^-]+-/,"");if(sid&&this.env.address_sources[sid]){writable=writable||!this.env.address_sources[sid].readonly;this.env.selection_sources.push(sid)}}this.env.selection_sources=$.unique(this.env.selection_sources)}else{this.env.selection_sources.push(this.env.source);writable=!source.readonly}}this.enable_command("group-remove-selected",this.env.group&&list.selection.length>0);this.enable_command("compose",this.env.group||list.selection.length>0);this.enable_command("edit",id&&writable);this.enable_command("delete",list.selection.length&&writable);return false};this.list_contacts=function(src,group,page){var win,folder,url={},target=window;if(!src){src=this.env.source}if(page&&this.current_page==page&&src==this.env.source&&group==this.env.group){return false}if(src!=this.env.source){page=this.env.current_page=1;this.reset_qsearch()}else{if(group!=this.env.group){page=this.env.current_page=1}}if(this.env.search_id){folder="S"+this.env.search_id}else{if(!this.env.search_request){folder=group?"G"+src+group:src}}this.select_folder(folder);this.env.source=src;this.env.group=group;if(this.gui_objects.contactslist){this.list_contacts_remote(src,group,page);return}if(win=this.get_frame_window(this.env.contentframe)){target=win;url._framed=1}if(group){url._gid=group}if(page){url._page=page}if(src){url._source=src}if(this.env.search_request){url._search=this.env.search_request}this.set_busy(true,"loading");this.location_href(url,target)};this.list_contacts_remote=function(src,group,page){this.list_contacts_clear();var url={},lock=this.set_busy(true,"loading");if(src){url._source=src}if(page){url._page=page}if(group){url._gid=group}this.env.source=src;this.env.group=group;if(this.env.search_request){url._search=this.env.search_request}this.http_request(this.env.task=="mail"?"list-contacts":"list",url,lock)};this.list_contacts_clear=function(){this.contact_list.clear(true);this.show_contentframe(false);this.enable_command("delete",false);this.enable_command("compose",this.env.group?true:false)};this.load_contact=function(cid,action,framed){var win,url={},target=window;if(win=this.get_frame_window(this.env.contentframe)){url._framed=1;target=win;this.show_contentframe(true);if(!cid){this.contact_list.clear_selection();this.enable_command("delete","compose",false)}}else{if(framed){return false}}if(action&&(cid||action=="add")&&!this.drag_active){if(this.env.group){url._gid=this.env.group}url._action=action;url._source=this.env.source;url._cid=cid;this.location_href(url,target,true)}return true};this.group_member_change=function(what,cid,source,gid){what=what=="add"?"add":"del";var label=this.get_label(what=="add"?"addingmember":"removingmember"),lock=this.display_message(label,"loading"),post_data={_cid:cid,_source:source,_gid:gid};this.http_post("group-"+what+"members",post_data,lock)};this.copy_contact=function(cid,to){var n,dest=to.type=="group"?to.source:to.id,source=this.env.source,group=this.env.group?this.env.group:"";if(!cid){cid=this.contact_list.get_selection().join(",")}if(!cid||!this.env.address_sources[dest]||this.env.address_sources[dest].readonly){return}if(source==""&&this.env.selection_sources.length==1){source=this.env.selection_sources[0]}if(to.type=="group"){if(dest==source){this.group_member_change("add",cid,dest,to.id)}else{var lock=this.display_message(this.get_label("copyingcontact"),"loading"),post_data={_cid:cid,_source:this.env.source,_to:dest,_togid:to.id,_gid:group};this.http_post("copy",post_data,lock)}}else{if(to.id!=source){var lock=this.display_message(this.get_label("copyingcontact"),"loading"),post_data={_cid:cid,_source:this.env.source,_to:to.id,_gid:group};this.http_post("copy",post_data,lock)}}};this.delete_contacts=function(){var selection=this.contact_list.get_selection(),undelete=this.env.source&&this.env.address_sources[this.env.source].undelete;if(!(selection.length||this.env.cid)||(!undelete&&!confirm(this.get_label("deletecontactconfirm")))){return}var id,n,a_cids=[],post_data={_source:this.env.source,_from:(this.env.action?this.env.action:"")},lock=this.display_message(this.get_label("contactdeleting"),"loading");if(this.env.cid){a_cids.push(this.env.cid)}else{for(n=0;n<selection.length;n++){id=selection[n];a_cids.push(id);this.contact_list.remove_row(id,(n==selection.length-1))}if(selection.length==1){this.show_contentframe(false)}}post_data._cid=a_cids.join(",");if(this.env.group){post_data._gid=this.env.group}if(this.env.search_request){post_data._search=this.env.search_request}this.http_post("delete",post_data,lock);return true};this.update_contact_row=function(cid,cols_arr,newcid,source){var c,row,list=this.contact_list;cid=this.html_identifier(cid);if(!list.rows[cid]){cid=cid+"-"+source;if(newcid){newcid=newcid+"-"+source}}if(list.rows[cid]&&(row=list.rows[cid].obj)){for(c=0;c<cols_arr.length;c++){if(row.cells[c]){$(row.cells[c]).html(cols_arr[c])}}if(newcid){newcid=this.html_identifier(newcid);row.id="rcmrow"+newcid;list.remove_row(cid);list.init_row(row);list.selection[0]=newcid;row.style.display=""}}};this.add_contact_row=function(cid,cols,classes){if(!this.gui_objects.contactslist){return false}var c,col,list=this.contact_list,row=document.createElement("tr");row.id="rcmrow"+this.html_identifier(cid);row.className="contact "+(classes||"");if(list.in_selection(cid)){row.className+=" selected"}for(c in cols){col=document.createElement("td");col.className=String(c).toLowerCase();if(cols[c]){col.innerHTML=cols[c]}row.appendChild(col)}list.insert_row(row);this.enable_command("export",list.rowcount>0)};this.init_contact_form=function(){var ref=this,col;if(this.env.coltypes){this.set_photo_actions($("#ff_photo").val());for(col in this.env.coltypes){this.init_edit_field(col,null)}}$(".contactfieldgroup .row a.deletebutton").click(function(){ref.delete_edit_field(this);return false});$("select.addfieldmenu").change(function(e){ref.insert_edit_field($(this).val(),$(this).attr("rel"),this);this.selectedIndex=0});if($.datepicker&&this.env.date_format){$.datepicker.setDefaults({dateFormat:this.env.date_format,changeMonth:true,changeYear:true,yearRange:"-100:+10",showOtherMonths:true,selectOtherMonths:true,onSelect:function(dateText){$(this).focus().val(dateText)}});$("input.datepicker").datepicker()}$("input[type='text']:visible").first().focus();if(this.env.action=="search"){$(this.gui_objects.editform).append($('<input type="submit">').hide()).submit(function(){$("input.mainaction").click();return false})}};this.group_create=function(){this.add_input_row("contactgroup")};this.group_rename=function(){if(!this.env.group||!this.gui_objects.folderlist){return}if(!this.name_input){this.enable_command("list","listgroup",false);this.name_input=$("<input>").attr("type","text").val(this.env.contactgroups["G"+this.env.source+this.env.group].name);this.name_input.bind("keydown",function(e){return rcmail.add_input_keydown(e)});this.env.group_renaming=true;var link,li=this.get_folder_li(this.env.source+this.env.group,"rcmliG");if(li&&(link=li.firstChild)){$(link).hide().before(this.name_input)}}this.name_input.select().focus()};this.group_delete=function(){if(this.env.group&&confirm(this.get_label("deletegroupconfirm"))){var lock=this.set_busy(true,"groupdeleting");this.http_post("group-delete",{_source:this.env.source,_gid:this.env.group},lock)}};this.remove_group_item=function(prop){var li,key="G"+prop.source+prop.id;if((li=this.get_folder_li(key))){this.triggerEvent("group_delete",{source:prop.source,id:prop.id,li:li});li.parentNode.removeChild(li);delete this.env.contactfolders[key];delete this.env.contactgroups[key]}this.list_contacts(prop.source,0)};this.add_input_row=function(type){if(!this.gui_objects.folderlist){return}if(!this.name_input){this.name_input=$("<input>").attr("type","text").data("tt",type);this.name_input.bind("keydown",function(e){return rcmail.add_input_keydown(e)});this.name_input_li=$("<li>").addClass(type).append(this.name_input);var li=type=="contactsearch"?$("li:last",this.gui_objects.folderlist):this.get_folder_li(this.env.source);this.name_input_li.insertAfter(li)}this.name_input.select().focus()};this.group_remove_selected=function(){ref.http_post("group-delmembers",{_cid:this.contact_list.selection,_source:this.env.source,_gid:this.env.group})};this.remove_group_contacts=function(props){if("undefined"!=typeof this.env.group&&(this.env.group===props.gid)){var n,selection=this.contact_list.get_selection();for(n=0;n<selection.length;n++){id=selection[n];this.contact_list.remove_row(id,(n==selection.length-1))}}};this.add_input_keydown=function(e){var key=rcube_event.get_keycode(e),input=$(e.target),itype=input.data("tt");if(key==13){var newname=input.val();if(newname){var lock=this.set_busy(true,"loading");if(itype=="contactsearch"){this.http_post("search-create",{_search:this.env.search_request,_name:newname},lock)}else{if(this.env.group_renaming){this.http_post("group-rename",{_source:this.env.source,_gid:this.env.group,_name:newname},lock)}else{this.http_post("group-create",{_source:this.env.source,_name:newname},lock)}}}return false}else{if(key==27){this.reset_add_input()}}return true};this.reset_add_input=function(){if(this.name_input){if(this.env.group_renaming){var li=this.name_input.parent();li.children().last().show();this.env.group_renaming=false}this.name_input.remove();if(this.name_input_li){this.name_input_li.remove()}this.name_input=this.name_input_li=null}this.enable_command("list","listgroup",true)};this.insert_contact_group=function(prop){this.reset_add_input();prop.type="group";var key="G"+prop.source+prop.id,link=$("<a>").attr("href","#").attr("rel",prop.source+":"+prop.id).click(function(){return rcmail.command("listgroup",prop,this)}).html(prop.name),li=$("<li>").attr({id:"rcmli"+this.html_identifier(key),"class":"contactgroup"}).append(link);this.env.contactfolders[key]=this.env.contactgroups[key]=prop;this.add_contact_group_row(prop,li);this.triggerEvent("group_insert",{id:prop.id,source:prop.source,name:prop.name,li:li[0]})};this.update_contact_group=function(prop){this.reset_add_input();var key="G"+prop.source+prop.id,li=this.get_folder_li(key),link;if(li&&prop.newid){var newkey="G"+prop.source+prop.newid,newprop=$.extend({},prop);li.id="rcmli"+this.html_identifier(newkey);this.env.contactfolders[newkey]=this.env.contactfolders[key];this.env.contactfolders[newkey].id=prop.newid;this.env.group=prop.newid;delete this.env.contactfolders[key];delete this.env.contactgroups[key];newprop.id=prop.newid;newprop.type="group";link=$("<a>").attr("href","#").attr("rel",prop.source+":"+prop.newid).click(function(){return rcmail.command("listgroup",newprop,this)}).html(prop.name);$(li).children().replaceWith(link)}else{if(li&&(link=li.firstChild)&&link.tagName.toLowerCase()=="a"){link.innerHTML=prop.name}}this.env.contactfolders[key].name=this.env.contactgroups[key].name=prop.name;this.add_contact_group_row(prop,$(li),true);this.triggerEvent("group_update",{id:prop.id,source:prop.source,name:prop.name,li:li[0],newid:prop.newid})};this.add_contact_group_row=function(prop,li,reloc){var row,name=prop.name.toUpperCase(),sibling=this.get_folder_li(prop.source),prefix="rcmliG"+this.html_identifier(prop.source);if(reloc){row=li.clone(true);li.remove()}else{row=li}$('li[id^="'+prefix+'"]',this.gui_objects.folderlist).each(function(i,elem){if(name>=$(this).text().toUpperCase()){sibling=elem}else{return false}});row.insertAfter(sibling)};this.update_group_commands=function(){var source=this.env.source!=""?this.env.address_sources[this.env.source]:null;this.enable_command("group-create",(source&&source.groups&&!source.readonly));this.enable_command("group-rename","group-delete",(source&&source.groups&&this.env.group&&!source.readonly))};this.init_edit_field=function(col,elem){var label=this.env.coltypes[col].label;if(!elem){elem=$(".ff_"+col)}if(label){elem.placeholder(label)}};this.insert_edit_field=function(col,section,menu){var elem=$("#ff_"+col);if(elem.length){elem.show().focus();$(menu).children('option[value="'+col+'"]').prop("disabled",true)}else{var lastelem=$(".ff_"+col),appendcontainer=$("#contactsection"+section+" .contactcontroller"+col);if(!appendcontainer.length){var sect=$("#contactsection"+section),lastgroup=$(".contactfieldgroup",sect).last();appendcontainer=$("<fieldset>").addClass("contactfieldgroup contactcontroller"+col);if(lastgroup.length){appendcontainer.insertAfter(lastgroup)}else{sect.prepend(appendcontainer)}}if(appendcontainer.length&&appendcontainer.get(0).nodeName=="FIELDSET"){var input,colprop=this.env.coltypes[col],row=$("<div>").addClass("row"),cell=$("<div>").addClass("contactfieldcontent data"),label=$("<div>").addClass("contactfieldlabel label");if(colprop.subtypes_select){label.html(colprop.subtypes_select)}else{label.html(colprop.label)}var name_suffix=colprop.limit!=1?"[]":"";if(colprop.type=="text"||colprop.type=="date"){input=$("<input>").addClass("ff_"+col).attr({type:"text",name:"_"+col+name_suffix,size:colprop.size}).appendTo(cell);this.init_edit_field(col,input);if(colprop.type=="date"&&$.datepicker){input.datepicker()}}else{if(colprop.type=="textarea"){input=$("<textarea>").addClass("ff_"+col).attr({name:"_"+col+name_suffix,cols:colprop.size,rows:colprop.rows}).appendTo(cell);this.init_edit_field(col,input)}else{if(colprop.type=="composite"){var childcol,cp,first,templ,cols=[],suffices=[];if((templ=this.env[col+"_template"])){for(var j=0;j<templ.length;j++){cols.push(templ[j][1]);suffices.push(templ[j][2])}}else{for(childcol in colprop.childs){cols.push(childcol)}}for(var i=0;i<cols.length;i++){childcol=cols[i];cp=colprop.childs[childcol];input=$("<input>").addClass("ff_"+childcol).attr({type:"text",name:"_"+childcol+name_suffix,size:cp.size}).appendTo(cell);cell.append(suffices[i]||" ");this.init_edit_field(childcol,input);if(!first){first=input}}input=first}else{if(colprop.type=="select"){input=$("<select>").addClass("ff_"+col).attr("name","_"+col+name_suffix).appendTo(cell);var options=input.attr("options");options[options.length]=new Option("---","");if(colprop.options){$.each(colprop.options,function(i,val){options[options.length]=new Option(val,i)})}}}}}if(input){var delbutton=$('<a href="#del"></a>').addClass("contactfieldbutton deletebutton").attr({title:this.get_label("delete"),rel:col}).html(this.env.delbutton).click(function(){ref.delete_edit_field(this);return false}).appendTo(cell);row.append(label).append(cell).appendTo(appendcontainer.show());input.first().focus();if(!colprop.count){colprop.count=0}if(++colprop.count==colprop.limit&&colprop.limit){$(menu).children('option[value="'+col+'"]').prop("disabled",true)}}}}};this.delete_edit_field=function(elem){var col=$(elem).attr("rel"),colprop=this.env.coltypes[col],fieldset=$(elem).parents("fieldset.contactfieldgroup"),addmenu=fieldset.parent().find("select.addfieldmenu");if(--colprop.count<=0&&colprop.visible){$(elem).parent().children("input").val("").blur()}else{$(elem).parents("div.row").remove();if(!fieldset.children("div.row").length){fieldset.hide()}}if(addmenu.length){var option=addmenu.children('option[value="'+col+'"]');if(option.length){option.prop("disabled",false)}else{option=$("<option>").attr("value",col).html(colprop.label).appendTo(addmenu)}addmenu.show()}};this.upload_contact_photo=function(form){if(form&&form.elements._photo.value){this.async_upload_form(form,"upload-photo",function(e){rcmail.set_busy(false,null,rcmail.file_upload_id)});this.file_upload_id=this.set_busy(true,"uploading")}};this.replace_contact_photo=function(id){var img_src=id=="-del-"?this.env.photo_placeholder:this.env.comm_path+"&_action=photo&_source="+this.env.source+"&_cid="+this.env.cid+"&_photo="+id;this.set_photo_actions(id);$(this.gui_objects.contactphoto).children("img").attr("src",img_src)};this.photo_upload_end=function(){this.set_busy(false,null,this.file_upload_id);delete this.file_upload_id};this.set_photo_actions=function(id){var n,buttons=this.buttons["upload-photo"];for(n=0;buttons&&n<buttons.length;n++){$("a#"+buttons[n].id).html(this.get_label(id=="-del-"?"addphoto":"replacephoto"))}$("#ff_photo").val(id);this.enable_command("upload-photo",this.env.coltypes.photo?true:false);this.enable_command("delete-photo",this.env.coltypes.photo&&id!="-del-")};this.advanced_search=function(){var win,url={_form:1,_action:"search"},target=window;if(win=this.get_frame_window(this.env.contentframe)){url._framed=1;target=win;this.contact_list.clear_selection()}this.location_href(url,target,true);return true};this.unselect_directory=function(){this.select_folder("");this.enable_command("search-delete",false)};this.insert_saved_search=function(name,id){this.reset_add_input();var key="S"+id,link=$("<a>").attr("href","#").attr("rel",id).click(function(){return rcmail.command("listsearch",id,this)}).html(name),li=$("<li>").attr({id:"rcmli"+this.html_identifier(key),"class":"contactsearch"}).append(link),prop={name:name,id:id,li:li[0]};this.add_saved_search_row(prop,li);this.select_folder("S"+id);this.enable_command("search-delete",true);this.env.search_id=id;this.triggerEvent("abook_search_insert",prop)};this.add_saved_search_row=function(prop,li,reloc){var row,sibling,name=prop.name.toUpperCase();if(reloc){row=li.clone(true);li.remove()}else{row=li}$('li[class~="contactsearch"]',this.gui_objects.folderlist).each(function(i,elem){if(!sibling){sibling=this.previousSibling}if(name>=$(this).text().toUpperCase()){sibling=elem}else{return false}});if(sibling){row.insertAfter(sibling)}else{row.appendTo(this.gui_objects.folderlist)}};this.search_create=function(){this.add_input_row("contactsearch")};this.search_delete=function(){if(this.env.search_request){var lock=this.set_busy(true,"savedsearchdeleting");this.http_post("search-delete",{_sid:this.env.search_id},lock)}};this.remove_search_item=function(id){var li,key="S"+id;if((li=this.get_folder_li(key))){this.triggerEvent("search_delete",{id:id,li:li});li.parentNode.removeChild(li)}this.env.search_id=null;this.env.search_request=null;this.list_contacts_clear();this.reset_qsearch();this.enable_command("search-delete","search-create",false)};this.listsearch=function(id){var folder,lock=this.set_busy(true,"searching");if(this.contact_list){this.list_contacts_clear()}this.reset_qsearch();this.select_folder("S"+id);this.env.current_page=1;this.http_request("search",{_sid:id},lock)};this.section_select=function(list){var win,id=list.get_single_selection(),target=window,url={_action:"edit-prefs",_section:id};if(id){if(win=this.get_frame_window(this.env.contentframe)){url._framed=1;target=win}this.location_href(url,target,true)}return true};this.identity_select=function(list){var id;if(id=list.get_single_selection()){this.enable_command("delete",list.rowcount>1&&this.env.identities_level<2);this.load_identity(id,"edit-identity")}};this.load_identity=function(id,action){if(action=="edit-identity"&&(!id||id==this.env.iid)){return false}var win,target=window,url={_action:action,_iid:id};if(win=this.get_frame_window(this.env.contentframe)){url._framed=1;target=win}if(action&&(id||action=="add-identity")){this.set_busy(true);this.location_href(url,target)}return true};this.delete_identity=function(id){var selection=this.identity_list.get_selection();if(!(selection.length||this.env.iid)){return}if(!id){id=this.env.iid?this.env.iid:selection[0]}if(confirm(this.get_label("deleteidentityconfirm"))){this.goto_url("delete-identity",{_iid:id,_token:this.env.request_token},true)}return true};this.update_identity_row=function(id,name,add){var row,col,list=this.identity_list,rid=this.html_identifier(id);if(list.rows[rid]&&(row=list.rows[rid].obj)){$(row.cells[0]).html(name)}else{if(add){row=$("<tr>").attr("id","rcmrow"+rid).get(0);col=$("<td>").addClass("mail").html(name).appendTo(row);list.insert_row(row);list.select(rid)}}};this.init_subscription_list=function(){var p=this;this.subscription_list=new rcube_list_widget(this.gui_objects.subscriptionlist,{multiselect:false,draggable:true,keyboard:false,toggleselect:true});this.subscription_list.addEventListener("select",function(o){p.subscription_select(o)});this.subscription_list.addEventListener("dragstart",function(o){p.drag_active=true});this.subscription_list.addEventListener("dragend",function(o){p.subscription_move_folder(o)});this.subscription_list.row_init=function(row){row.obj.onmouseover=function(){p.focus_subscription(row.id)};row.obj.onmouseout=function(){p.unfocus_subscription(row.id)}};this.subscription_list.init();$("#mailboxroot").mouseover(function(){p.focus_subscription(this.id)}).mouseout(function(){p.unfocus_subscription(this.id)})};this.focus_subscription=function(id){var row,folder,delim=RegExp.escape(this.env.delimiter),reg=RegExp("["+delim+"]?[^"+delim+"]+$");if(this.drag_active&&this.env.mailbox&&(row=document.getElementById(id))){if(this.env.subscriptionrows[id]&&(folder=this.env.subscriptionrows[id][0])!==null){if(this.check_droptarget(folder)&&!this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2]&&(folder!=this.env.mailbox.replace(reg,""))&&(!folder.match(new RegExp("^"+RegExp.escape(this.env.mailbox+this.env.delimiter))))){this.env.dstfolder=folder;$(row).addClass("droptarget")}}}};this.unfocus_subscription=function(id){var row=$("#"+id);this.env.dstfolder=null;if(this.env.subscriptionrows[id]&&row[0]){row.removeClass("droptarget")}else{$(this.subscription_list.frame).removeClass("droptarget")}};this.subscription_select=function(list){var id,folder;if(list&&(id=list.get_single_selection())&&(folder=this.env.subscriptionrows["rcmrow"+id])){this.env.mailbox=folder[0];this.show_folder(folder[0]);this.enable_command("delete-folder",!folder[2])}else{this.env.mailbox=null;this.show_contentframe(false);this.enable_command("delete-folder","purge",false)}};this.subscription_move_folder=function(list){var delim=RegExp.escape(this.env.delimiter),reg=RegExp("["+delim+"]?[^"+delim+"]+$");if(this.env.mailbox&&this.env.dstfolder!==null&&(this.env.dstfolder!=this.env.mailbox)&&(this.env.dstfolder!=this.env.mailbox.replace(reg,""))){reg=new RegExp("[^"+delim+"]*["+delim+"]","g");var basename=this.env.mailbox.replace(reg,""),newname=this.env.dstfolder===""?basename:this.env.dstfolder+this.env.delimiter+basename;if(newname!=this.env.mailbox){this.http_post("rename-folder",{_folder_oldname:this.env.mailbox,_folder_newname:newname},this.set_busy(true,"foldermoving"));this.subscription_list.draglayer.hide()}}this.drag_active=false;this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder))};this.create_folder=function(){this.show_folder("",this.env.mailbox)};this.delete_folder=function(name){var id=this.get_folder_row_id(name?name:this.env.mailbox),folder=this.env.subscriptionrows[id][0];if(folder&&confirm(this.get_label("deletefolderconfirm"))){var lock=this.set_busy(true,"folderdeleting");this.http_post("delete-folder",{_mbox:folder},lock)}};this.add_folder_row=function(name,display_name,is_protected,subscribed,skip_init,class_name){if(!this.gui_objects.subscriptionlist){return false}var row,n,i,tmp,tmp_name,folders,rowid,list=[],slist=[],tbody=this.gui_objects.subscriptionlist.tBodies[0],refrow=$("tr",tbody).get(1),id="rcmrow"+((new Date).getTime());if(!refrow){this.goto_url("folders");return false}row=$(refrow).clone(true);row.attr("id",id);row.attr("class",class_name);row.find("td:first").html(display_name);$('input[name="_subscribed[]"]',row).val(name).prop({checked:subscribed?true:false,disabled:is_protected?true:false});this.env.subscriptionrows[id]=[name,display_name,0];folders=[];$.each(this.env.subscriptionrows,function(k,v){folders.push(v)});folders.sort(function(a,b){return a[0]<b[0]?-1:(a[0]>b[0]?1:0)});for(n in folders){if(folders[n][2]){tmp_name=folders[n][0]+this.env.delimiter;if(tmp_name==this.env.prefix_ns){continue}slist.push(folders[n][0]);tmp=tmp_name}else{if(tmp&&folders[n][0].indexOf(tmp)==0){slist.push(folders[n][0])}else{list.push(folders[n][0]);tmp=null}}}for(n=0;n<slist.length;n++){if(name.indexOf(slist[n]+this.env.delimiter)==0){rowid=this.get_folder_row_id(slist[n])}}for(n=0;!rowid&&n<list.length;n++){if(n&&list[n]==name){rowid=this.get_folder_row_id(list[n-1])}}if(rowid){$("#"+rowid).after(row)}else{row.appendTo(tbody)}this.subscription_list.clear_selection();if(!skip_init){this.init_subscription_list()}row=row.get(0);if(row.scrollIntoView){row.scrollIntoView()}return row};this.replace_folder_row=function(oldfolder,newfolder,display_name,is_protected,class_name){if(!this.gui_objects.subscriptionlist){return false}var i,n,len,name,dispname,oldrow,tmprow,row,level,tbody=this.gui_objects.subscriptionlist.tBodies[0],folders=this.env.subscriptionrows,id=this.get_folder_row_id(oldfolder),regex=new RegExp("^"+RegExp.escape(oldfolder)),subscribed=$('input[name="_subscribed[]"]',$("#"+id)).prop("checked"),list=this.get_subfolders(oldfolder);this._remove_folder_row(id);row=$(this.add_folder_row(newfolder,display_name,is_protected,subscribed,true,class_name));if(len=list.length){level=(oldfolder.split(this.env.delimiter)).length-(newfolder.split(this.env.delimiter)).length}for(n=0;n<len;n++){id=list[n];name=this.env.subscriptionrows[id][0];dispname=this.env.subscriptionrows[id][1];oldrow=$("#"+id);tmprow=oldrow.clone(true);oldrow.remove();row.after(tmprow);row=tmprow;name=name.replace(regex,newfolder);$('input[name="_subscribed[]"]',row).val(name);this.env.subscriptionrows[id][0]=name;if(level!=0){if(level>0){for(i=level;i>0;i--){dispname=dispname.replace(/^ /,"")}}else{for(i=level;i<0;i++){dispname=" "+dispname}}row.find("td:first").html(dispname);this.env.subscriptionrows[id][1]=dispname}}this.init_subscription_list()};this.remove_folder_row=function(folder,subs){var n,len,list=[],id=this.get_folder_row_id(folder);if(subs){list=this.get_subfolders(folder)}this._remove_folder_row(id);for(n=0,len=list.length;n<len;n++){this._remove_folder_row(list[n])}};this._remove_folder_row=function(id){this.subscription_list.remove_row(id.replace(/^rcmrow/,""));$("#"+id).remove();delete this.env.subscriptionrows[id]};this.get_subfolders=function(folder){var name,list=[],regex=new RegExp("^"+RegExp.escape(folder)+RegExp.escape(this.env.delimiter)),row=$("#"+this.get_folder_row_id(folder)).get(0);while(row=row.nextSibling){if(row.id){name=this.env.subscriptionrows[row.id][0];if(regex.test(name)){list.push(row.id)}else{break}}}return list};this.subscribe=function(folder){if(folder){var lock=this.display_message(this.get_label("foldersubscribing"),"loading");this.http_post("subscribe",{_mbox:folder},lock)}};this.unsubscribe=function(folder){if(folder){var lock=this.display_message(this.get_label("folderunsubscribing"),"loading");this.http_post("unsubscribe",{_mbox:folder},lock)}};this.get_folder_row_id=function(folder){var id,folders=this.env.subscriptionrows;for(id in folders){if(folders[id]&&folders[id][0]==folder){break}}return id};this.show_folder=function(folder,path,force){var win,target=window,url="&_action=edit-folder&_mbox="+urlencode(folder);if(path){url+="&_path="+urlencode(path)}if(win=this.get_frame_window(this.env.contentframe)){target=win;url+="&_framed=1"}if(String(target.location.href).indexOf(url)>=0&&!force){this.show_contentframe(true)}else{this.location_href(this.env.comm_path+url,target,true)}};this.disable_subscription=function(folder){var id=this.get_folder_row_id(folder);if(id){$('input[name="_subscribed[]"]',$("#"+id)).prop("disabled",true)}};this.folder_size=function(folder){var lock=this.set_busy(true,"loading");this.http_post("folder-size",{_mbox:folder},lock)};this.folder_size_update=function(size){$("#folder-size").replaceWith(size)};var init_button=function(cmd,prop){var elm=document.getElementById(prop.id);if(!elm){return}var preload=false;if(prop.type=="image"){elm=elm.parentNode;preload=true}elm._command=cmd;elm._id=prop.id;if(prop.sel){elm.onmousedown=function(e){return rcmail.button_sel(this._command,this._id)};elm.onmouseup=function(e){return rcmail.button_out(this._command,this._id)};if(preload){new Image().src=prop.sel}}if(prop.over){elm.onmouseover=function(e){return rcmail.button_over(this._command,this._id)};elm.onmouseout=function(e){return rcmail.button_out(this._command,this._id)};if(preload){new Image().src=prop.over}}};this.init_buttons=function(){for(var cmd in this.buttons){if(typeof cmd!=="string"){continue}for(var i=0;i<this.buttons[cmd].length;i++){init_button(cmd,this.buttons[cmd][i])}}this.set_button(this.task,"sel")};this.set_button=function(command,state){var n,button,obj,a_buttons=this.buttons[command],len=a_buttons?a_buttons.length:0;for(n=0;n<len;n++){button=a_buttons[n];obj=document.getElementById(button.id);if(!obj){continue}if(button.type=="image"&&!button.status){button.pas=obj._original_src?obj._original_src:obj.src;if(obj.runtimeStyle&&obj.runtimeStyle.filter&&obj.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/)){button.pas=RegExp.$1}}else{if(!button.status){button.pas=String(obj.className)}}if(button.type=="image"&&button[state]){button.status=state;obj.src=button[state]}else{if(button[state]!==undefined){button.status=state;obj.className=button[state]}}if(button.type=="input"){button.status=state;obj.disabled=!state}}};this.set_alttext=function(command,label){var n,button,obj,link,a_buttons=this.buttons[command],len=a_buttons?a_buttons.length:0;for(n=0;n<len;n++){button=a_buttons[n];obj=document.getElementById(button.id);if(button.type=="image"&&obj){obj.setAttribute("alt",this.get_label(label));if((link=obj.parentNode)&&link.tagName.toLowerCase()=="a"){link.setAttribute("title",this.get_label(label))}}else{if(obj){obj.setAttribute("title",this.get_label(label))}}}};this.button_over=function(command,id){var n,button,obj,a_buttons=this.buttons[command],len=a_buttons?a_buttons.length:0;for(n=0;n<len;n++){button=a_buttons[n];if(button.id==id&&button.status=="act"){obj=document.getElementById(button.id);if(obj&&button.over){if(button.type=="image"){obj.src=button.over}else{obj.className=button.over}}}}};this.button_sel=function(command,id){var n,button,obj,a_buttons=this.buttons[command],len=a_buttons?a_buttons.length:0;for(n=0;n<len;n++){button=a_buttons[n];if(button.id==id&&button.status=="act"){obj=document.getElementById(button.id);if(obj&&button.sel){if(button.type=="image"){obj.src=button.sel}else{obj.className=button.sel}}this.buttons_sel[id]=command}}};this.button_out=function(command,id){var n,button,obj,a_buttons=this.buttons[command],len=a_buttons?a_buttons.length:0;for(n=0;n<len;n++){button=a_buttons[n];if(button.id==id&&button.status=="act"){obj=document.getElementById(button.id);if(obj&&button.act){if(button.type=="image"){obj.src=button.act}else{obj.className=button.act}}}}};this.set_pagetitle=function(title){if(title&&document.title){document.title=title}};this.display_message=function(msg,type,timeout){if(this.is_framed()){return parent.rcmail.display_message(msg,type,timeout)}if(!this.gui_objects.message){if(type!="loading"){this.pending_message=[msg,type,timeout]}return 1}type=type?type:"notice";var ref=this,key=this.html_identifier(msg),date=new Date(),id=type+date.getTime();if(!timeout){timeout=this.message_time*(type=="error"||type=="warning"?2:1)}if(type=="loading"){key="loading";timeout=this.env.request_timeout*1000;if(!msg){msg=this.get_label("loading")}}if(this.messages[key]){if(this.messages[key].obj){this.messages[key].obj.html(msg)}if(type=="loading"){this.messages[key].labels.push({id:id,msg:msg})}this.messages[key].elements.push(id);setTimeout(function(){ref.hide_message(id,type=="loading")},timeout);return id}var obj=$("<div>").addClass(type).html(msg).data("key",key),cont=$(this.gui_objects.message).append(obj).show();this.messages[key]={obj:obj,elements:[id]};if(type=="loading"){this.messages[key].labels=[{id:id,msg:msg}]}else{obj.click(function(){return ref.hide_message(obj)})}this.triggerEvent("message",{message:msg,type:type,timeout:timeout,object:obj});if(timeout>0){setTimeout(function(){ref.hide_message(id,type=="loading")},timeout)}return id};this.hide_message=function(obj,fade){if(this.is_framed()){return parent.rcmail.hide_message(obj,fade)}if(!this.gui_objects.message){return}var k,n,i,msg,m=this.messages;if(typeof obj==="object"){$(obj)[fade?"fadeOut":"hide"]();msg=$(obj).data("key");if(this.messages[msg]){delete this.messages[msg]}}else{for(k in m){for(n in m[k].elements){if(m[k]&&m[k].elements[n]==obj){m[k].elements.splice(n,1);if(!m[k].elements.length){m[k].obj[fade?"fadeOut":"hide"]();delete m[k]}else{if(k=="loading"){for(i in m[k].labels){if(m[k].labels[i].id==obj){delete m[k].labels[i]}else{msg=m[k].labels[i].msg}m[k].obj.html(msg)}}}}}}}};this.clear_messages=function(){if(this.is_framed()){return parent.rcmail.clear_messages()}var k,n,m=this.messages;for(k in m){for(n in m[k].elements){if(m[k].obj){m[k].obj.hide()}}}this.messages={}};this.show_popup_dialog=function(html,title){if(this.is_framed()){parent.rcmail.show_popup_dialog(html,title);return}var popup=$('<div class="popup">').html(html).dialog({title:title,modal:true,resizable:true,width:580,close:function(event,ui){$(this).remove()}});var win=$(window),w=win.width(),h=win.height(),width=popup.width(),height=popup.height();popup.dialog("option",{height:Math.min(h-40,height+50),width:Math.min(w-20,width+50)}).dialog("option","position",["center","center"])};this.set_page_buttons=function(){this.enable_command("nextpage","lastpage",(this.env.pagecount>this.env.current_page));this.enable_command("previouspage","firstpage",(this.env.current_page>1))};this.select_folder=function(name,prefix,encode){if(this.gui_objects.folderlist){var current_li,target_li;if((current_li=$("li.selected",this.gui_objects.folderlist))){current_li.removeClass("selected").addClass("unfocused")}if((target_li=this.get_folder_li(name,prefix,encode))){$(target_li).removeClass("unfocused").addClass("selected")}this.triggerEvent("selectfolder",{folder:name,prefix:prefix})}};this.mark_folder=function(name,class_name,prefix,encode){$(this.get_folder_li(name,prefix,encode)).addClass(class_name)};this.unmark_folder=function(name,class_name,prefix,encode){$(this.get_folder_li(name,prefix,encode)).removeClass(class_name)};this.get_folder_li=function(name,prefix,encode){if(!prefix){prefix="rcmli"}if(this.gui_objects.folderlist){name=this.html_identifier(name,encode);return document.getElementById(prefix+name)}return null};this.set_message_coltypes=function(coltypes,repl,smart_col){var list=this.message_list,thead=list?list.list.tHead:null,cell,col,n,len,th,tr;this.env.coltypes=coltypes;if(thead){if(repl){th=document.createElement("thead");tr=document.createElement("tr");for(c=0,len=repl.length;c<len;c++){cell=document.createElement("td");cell.innerHTML=repl[c].html||"";if(repl[c].id){cell.id=repl[c].id}if(repl[c].className){cell.className=repl[c].className}tr.appendChild(cell)}th.appendChild(tr);thead.parentNode.replaceChild(th,thead);list.thead=thead=th}for(n=0,len=this.env.coltypes.length;n<len;n++){col=this.env.coltypes[n];if((cell=thead.rows[0].cells[n])&&(col=="from"||col=="to"||col=="fromto")){cell.id="rcm"+col;$("span,a",cell).text(this.get_label(col=="fromto"?smart_col:col));$("a",cell).click(function(){return rcmail.command("sort",this.id.replace(/^rcm/,""),this)})}}}this.env.subject_col=null;this.env.flagged_col=null;this.env.status_col=null;if((n=$.inArray("subject",this.env.coltypes))>=0){this.env.subject_col=n;if(list){list.subject_col=n}}if((n=$.inArray("flag",this.env.coltypes))>=0){this.env.flagged_col=n}if((n=$.inArray("status",this.env.coltypes))>=0){this.env.status_col=n}if(list){list.init_header()}};this.set_rowcount=function(text,mbox){if(mbox&&mbox!=this.env.mailbox){return false}$(this.gui_objects.countdisplay).html(text);this.set_page_buttons()};this.set_mailboxname=function(content){if(this.gui_objects.mailboxname&&content){this.gui_objects.mailboxname.innerHTML=content}};this.set_quota=function(content){if(this.gui_objects.quotadisplay&&content&&content.type=="text"){$(this.gui_objects.quotadisplay).html(content.percent+"%").attr("title",content.title)}this.triggerEvent("setquota",content);this.env.quota_content=content};this.set_unread_count=function(mbox,count,set_title,mark){if(!this.gui_objects.mailboxlist){return false}this.env.unread_counts[mbox]=count;this.set_unread_count_display(mbox,set_title);if(mark){this.mark_folder(mbox,mark,"",true)}else{if(!count){this.unmark_folder(mbox,"recent","",true)}}};this.set_unread_count_display=function(mbox,set_title){var reg,link,text_obj,item,mycount,childcount,div;if(item=this.get_folder_li(mbox,"",true)){mycount=this.env.unread_counts[mbox]?this.env.unread_counts[mbox]:0;link=$(item).children("a").eq(0);text_obj=link.children("span.unreadcount");if(!text_obj.length&&mycount){text_obj=$("<span>").addClass("unreadcount").appendTo(link)}reg=/\s+\([0-9]+\)$/i;childcount=0;if((div=item.getElementsByTagName("div")[0])&&div.className.match(/collapsed/)){for(var k in this.env.unread_counts){if(k.indexOf(mbox+this.env.delimiter)==0){childcount+=this.env.unread_counts[k]}}}if(mycount&&text_obj.length){text_obj.html(this.env.unreadwrap.replace(/%[sd]/,mycount))}else{if(text_obj.length){text_obj.remove()}}reg=new RegExp(RegExp.escape(this.env.delimiter)+"[^"+RegExp.escape(this.env.delimiter)+"]+$");if(mbox.match(reg)){this.set_unread_count_display(mbox.replace(reg,""),false)}if((mycount+childcount)>0){$(item).addClass("unread")}else{$(item).removeClass("unread")}}reg=/^\([0-9]+\)\s+/i;if(set_title&&document.title){var new_title="",doc_title=String(document.title);if(mycount&&doc_title.match(reg)){new_title=doc_title.replace(reg,"("+mycount+") ")}else{if(mycount){new_title="("+mycount+") "+doc_title}else{new_title=doc_title.replace(reg,"")}}this.set_pagetitle(new_title)}};this.set_headers=function(content){if(this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box&&content){$(this.gui_objects.all_headers_box).html(content).show()}};this.show_headers=function(props,elem){if(!this.gui_objects.all_headers_row||!this.gui_objects.all_headers_box||!this.env.uid){return}$(elem).removeClass("show-headers").addClass("hide-headers");$(this.gui_objects.all_headers_row).show();elem.onclick=function(){rcmail.command("hide-headers","",elem)};if(!this.gui_objects.all_headers_box.innerHTML){var lock=this.display_message(this.get_label("loading"),"loading");this.http_post("headers",{_uid:this.env.uid},lock)}};this.hide_headers=function(props,elem){if(!this.gui_objects.all_headers_row||!this.gui_objects.all_headers_box){return}$(elem).removeClass("hide-headers").addClass("show-headers");$(this.gui_objects.all_headers_row).hide();elem.onclick=function(){rcmail.command("show-headers","",elem)}};this.html2plain=function(htmlText,id){var rcmail=this,url="?_task=utils&_action=html2text",lock=this.set_busy(true,"converting");this.log("HTTP POST: "+url);$.ajax({type:"POST",url:url,data:htmlText,contentType:"application/octet-stream",error:function(o,status,err){rcmail.http_error(o,status,err,lock)},success:function(data){rcmail.set_busy(false,null,lock);$("#"+id).val(data);rcmail.log(data)}})};this.plain2html=function(plain,id){var lock=this.set_busy(true,"converting");plain=plain.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");$("#"+id).val(plain?"<pre>"+plain+"</pre>":"");this.set_busy(false,null,lock)};this.url=function(action,query){var querystring=typeof query==="string"?"&"+query:"";if(typeof action!=="string"){query=action}else{if(!query||typeof query!=="object"){query={}}}if(action){query._action=action}else{query._action=this.env.action}var base=this.env.comm_path,k,param={};if(query._action.match(/([a-z]+)\/([a-z0-9-_.]+)/)){query._action=RegExp.$2;base=base.replace(/\_task=[a-z]+/,"_task="+RegExp.$1)}for(k in query){if(query[k]!==undefined&&query[k]!==null){param[k]=query[k]}}return base+"&"+$.param(param)+querystring};this.redirect=function(url,lock){if(lock||lock===null){this.set_busy(true)}if(this.is_framed()){parent.rcmail.redirect(url,lock)}else{if(this.env.extwin){if(typeof url=="string"){url+=(url.indexOf("?")<0?"?":"&")+"_extwin=1"}else{url._extwin=1}}this.location_href(url,window)}};this.goto_url=function(action,query,lock){this.redirect(this.url(action,query))};this.location_href=function(url,target,frame){if(frame){this.lock_frame()}if(typeof url=="object"){url=this.env.comm_path+"&"+$.param(url)}if(bw.ie&&target==window){$("<a>").attr("href",url).appendTo(document.body).get(0).click()}else{target.location.href=url}this.start_keepalive()};this.http_request=function(action,query,lock){var url=this.url(action,query);var result=this.triggerEvent("request"+action,query);if(result!==undefined){if(result===false){return false}else{query=result}}url+="&_remote=1";this.log("HTTP GET: "+url);this.start_keepalive();return $.ajax({type:"GET",url:url,data:{_unlock:(lock?lock:0)},dataType:"json",success:function(data){ref.http_response(data)},error:function(o,status,err){ref.http_error(o,status,err,lock,action)}})};this.http_post=function(action,postdata,lock){var url=this.url(action);if(postdata&&typeof postdata==="object"){postdata._remote=1;postdata._unlock=(lock?lock:0)}else{postdata+=(postdata?"&":"")+"_remote=1"+(lock?"&_unlock="+lock:"")}var result=this.triggerEvent("request"+action,postdata);if(result!==undefined){if(result===false){return false}else{postdata=result}}this.log("HTTP POST: "+url);this.start_keepalive();return $.ajax({type:"POST",url:url,data:postdata,dataType:"json",success:function(data){ref.http_response(data)},error:function(o,status,err){ref.http_error(o,status,err,lock,action)}})};this.abort_request=function(r){if(r.request){r.request.abort()}if(r.lock){this.set_busy(false,null,r.lock)}};this.http_response=function(response){if(!response){return}if(response.unlock){this.set_busy(false)}this.triggerEvent("responsebefore",{response:response});this.triggerEvent("responsebefore"+response.action,{response:response});if(response.env){this.set_env(response.env)}if(typeof response.texts==="object"){for(var name in response.texts){if(typeof response.texts[name]==="string"){this.add_label(name,response.texts[name])}}}if(response.exec){this.log(response.exec);eval(response.exec)}if(response.callbacks&&response.callbacks.length){for(var i=0;i<response.callbacks.length;i++){this.triggerEvent(response.callbacks[i][0],response.callbacks[i][1])}}switch(response.action){case"delete":if(this.task=="addressbook"){var sid,uid=this.contact_list.get_selection(),writable=false;if(uid&&this.contact_list.rows[uid]){if(this.env.source==""){sid=String(uid).replace(/^[^-]+-/,"");writable=sid&&this.env.address_sources[sid]&&!this.env.address_sources[sid].readonly}else{writable=!this.env.address_sources[this.env.source].readonly}}this.enable_command("compose",(uid&&this.contact_list.rows[uid]));this.enable_command("delete","edit",writable);this.enable_command("export",(this.contact_list&&this.contact_list.rowcount>0))}case"moveto":if(this.env.action=="show"){this.enable_command(this.env.message_commands,true);if(!this.env.list_post){this.enable_command("reply-list",false)}}else{if(this.task=="addressbook"){this.triggerEvent("listupdate",{folder:this.env.source,rowcount:this.contact_list.rowcount})}}case"purge":case"expunge":if(this.task=="mail"){if(!this.env.exists){if(this.env.contentframe){this.show_contentframe(false)}this.enable_command(this.env.message_commands,"purge","expunge","select-all","select-none","expand-all","expand-unread","collapse-all",false)}if(this.message_list){this.triggerEvent("listupdate",{folder:this.env.mailbox,rowcount:this.message_list.rowcount})}}break;case"refresh":case"check-recent":case"getunread":case"search":this.env.qsearch=null;case"list":if(this.task=="mail"){this.enable_command("show","select-all","select-none",this.env.messagecount>0);this.enable_command("expunge",this.env.exists);this.enable_command("purge",this.purge_mailbox_test());this.enable_command("expand-all","expand-unread","collapse-all",this.env.threading&&this.env.messagecount);if((response.action=="list"||response.action=="search")&&this.message_list){this.msglist_select(this.message_list);this.triggerEvent("listupdate",{folder:this.env.mailbox,rowcount:this.message_list.rowcount})}}else{if(this.task=="addressbook"){this.enable_command("export",(this.contact_list&&this.contact_list.rowcount>0));if(response.action=="list"||response.action=="search"){this.enable_command("search-create",this.env.source=="");this.enable_command("search-delete",this.env.search_id);this.update_group_commands();this.triggerEvent("listupdate",{folder:this.env.source,rowcount:this.contact_list.rowcount})}}}break}if(response.unlock){this.hide_message(response.unlock)}this.triggerEvent("responseafter",{response:response});this.triggerEvent("responseafter"+response.action,{response:response});this.start_keepalive()};this.http_error=function(request,status,err,lock,action){var errmsg=request.statusText;this.set_busy(false,null,lock);request.abort();if(this.unload){return}if(request.status&&errmsg){this.display_message(this.get_label("servererror")+" ("+errmsg+")","error")}else{if(status=="timeout"){this.display_message(this.get_label("requesttimedout"),"error")}else{if(request.status==0&&status!="abort"){this.display_message(this.get_label("servererror")+" (No connection)","error")}}}var location_url=request.getResponseHeader("Location");if(location_url&&this.env.action!="compose"){this.redirect(location_url)}if(request.status==403){(this.is_framed()?parent:window).location.reload();return}if(action=="keep-alive"){setTimeout(function(){ref.keep_alive();ref.start_keepalive()},30000)}};this.iframe_loaded=function(unlock){this.set_busy(false,null,unlock);if(this.submit_timer){clearTimeout(this.submit_timer)}};this.async_upload_form=function(form,action,onload){var frame,ts=new Date().getTime(),frame_name="rcmupload"+ts;if(this.env.upload_progress_name){var fname=this.env.upload_progress_name,field=$("input[name="+fname+"]",form);if(!field.length){field=$("<input>").attr({type:"hidden",name:fname});field.prependTo(form)}field.val(ts)}if(document.all){document.body.insertAdjacentHTML("BeforeEnd",'<iframe name="'+frame_name+'" src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>');frame=$('iframe[name="'+frame_name+'"]')}else{frame=$("<iframe>").attr("name",frame_name).css({border:"none",width:0,height:0,visibility:"hidden"}).appendTo(document.body)}frame.bind("load",{ts:ts},onload);$(form).attr({target:frame_name,action:this.url(action,{_id:this.env.compose_id||"",_uploadid:ts}),method:"POST"}).attr(form.encoding?"encoding":"enctype","multipart/form-data").submit();return frame_name};this.document_drag_hover=function(e,over){e.preventDefault();$(ref.gui_objects.filedrop)[(over?"addClass":"removeClass")]("active")};this.file_drag_hover=function(e,over){e.preventDefault();e.stopPropagation();$(ref.gui_objects.filedrop)[(over?"addClass":"removeClass")]("hover")};this.file_dropped=function(e){this.file_drag_hover(e,false);var files=e.target.files||e.dataTransfer.files,formdata=window.FormData?new FormData():null,fieldname=(this.env.filedrop.fieldname||"_file")+(this.env.filedrop.single?"":"[]"),boundary="------multipartformboundary"+(new Date).getTime(),dashdash="--",crlf="\r\n",multipart=dashdash+boundary+crlf;if(!files||!files.length){return}var submit_data=function(){var multiple=files.length>1,ts=new Date().getTime(),content="<span>"+(multiple?ref.get_label("uploadingmany"):files[0].name)+"</span>";if(!ref.add2attachment_list(ts,{name:"",html:content,classname:"uploading",complete:false})){ref.file_upload_id=ref.set_busy(true,"uploading")}multipart+=dashdash+boundary+dashdash+crlf;$.ajax({type:"POST",dataType:"json",url:ref.url(ref.env.filedrop.action||"upload",{_id:ref.env.compose_id||ref.env.cid||"",_uploadid:ts,_remote:1}),contentType:formdata?false:"multipart/form-data; boundary="+boundary,processData:false,timeout:0,data:formdata||multipart,headers:{"X-Roundcube-Request":ref.env.request_token},xhr:function(){var xhr=jQuery.ajaxSettings.xhr();if(!formdata&&xhr.sendAsBinary){xhr.send=xhr.sendAsBinary}return xhr},success:function(data){ref.http_response(data)},error:function(o,status,err){ref.http_error(o,status,err,null,"attachment")}})};var last=this.env.filedrop.single?0:files.length-1;for(var j=0,i=0,f;j<=last&&(f=files[i]);i++){if(!f.name){f.name=f.fileName}if(!f.size){f.size=f.fileSize}if(!f.type){f.type="application/octet-stream"}if(!formdata&&/[^\x20-\x7E]/.test(f.name)){f.name_bin=unescape(encodeURIComponent(f.name))}if(this.env.filedrop.filter&&!f.type.match(new RegExp(this.env.filedrop.filter))){continue}if(formdata){formdata.append(fieldname,f);if(j==last){return submit_data()}}else{if(window.FileReader){var reader=new FileReader();reader.onload=(function(file,j){return function(e){multipart+='Content-Disposition: form-data; name="'+fieldname+'"';multipart+='; filename="'+(f.name_bin||file.name)+'"'+crlf;multipart+="Content-Length: "+file.size+crlf;multipart+="Content-Type: "+file.type+crlf+crlf;multipart+=reader.result+crlf;multipart+=dashdash+boundary+crlf;if(j==last){return submit_data()}}})(f,j);reader.readAsBinaryString(f)}else{if(f.getAsBinary){multipart+='Content-Disposition: form-data; name="'+fieldname+'"';multipart+='; filename="'+(f.name_bin||f.name)+'"'+crlf;multipart+="Content-Length: "+f.size+crlf;multipart+="Content-Type: "+f.type+crlf+crlf;multipart+=f.getAsBinary()+crlf;multipart+=dashdash+boundary+crlf;if(j==last){return submit_data()}}}}j++}};this.start_keepalive=function(){if(!this.env.session_lifetime||this.env.framed||this.env.extwin||this.task=="login"||this.env.action=="print"){return}if(this._keepalive){clearInterval(this._keepalive)}this._keepalive=setInterval(function(){ref.keep_alive()},this.env.session_lifetime*0.5*1000)};this.start_refresh=function(){if(!this.env.refresh_interval||this.env.framed||this.env.extwin||this.task=="login"||this.env.action=="print"){return}if(this._refresh){clearInterval(this._refresh)}this._refresh=setInterval(function(){ref.refresh()},this.env.refresh_interval*1000)};this.keep_alive=function(){if(!this.busy){this.http_request("keep-alive")}};this.refresh=function(){if(this.busy){setTimeout(function(){ref.refresh();ref.start_refresh()},10000);return}var params={},lock=this.set_busy(true,"refreshing");if(this.task=="mail"&&this.gui_objects.mailboxlist){params=this.check_recent_params()}this.http_request("refresh",params,lock)};this.check_recent_params=function(){var params={_mbox:this.env.mailbox};if(this.gui_objects.mailboxlist){params._folderlist=1}if(this.gui_objects.messagelist){params._list=1}if(this.gui_objects.quotadisplay){params._quota=1}if(this.env.search_request){params._search=this.env.search_request}return params};this.opener=function(){try{if(window.opener&&!opener.closed&&opener.rcmail){return opener.rcmail}}catch(e){}};this.get_single_uid=function(){return this.env.uid?this.env.uid:(this.message_list?this.message_list.get_single_selection():null)};this.get_single_cid=function(){return this.env.cid?this.env.cid:(this.contact_list?this.contact_list.get_single_selection():null)};this.get_caret_pos=function(obj){if(obj.selectionEnd!==undefined){return obj.selectionEnd}if(document.selection&&document.selection.createRange){var range=document.selection.createRange();if(range.parentElement()!=obj){return 0}var gm=range.duplicate();if(obj.tagName=="TEXTAREA"){gm.moveToElementText(obj)}else{gm.expand("textedit")}gm.setEndPoint("EndToStart",range);var p=gm.text.length;return p<=obj.value.length?p:-1}return obj.value.length};this.set_caret_pos=function(obj,pos){if(obj.setSelectionRange){obj.setSelectionRange(pos,pos)}else{if(obj.createTextRange){var range=obj.createTextRange();range.collapse(true);range.moveEnd("character",pos);range.moveStart("character",pos);range.select()}}};this.lock_form=function(form,lock){if(!form||!form.elements){return}var n,len,elm;if(lock){this.disabled_form_elements=[]}for(n=0,len=form.elements.length;n<len;n++){elm=form.elements[n];if(elm.type=="hidden"){continue}if(lock&&elm.disabled){this.disabled_form_elements.push(elm)}else{if(lock||(this.disabled_form_elements&&$.inArray(elm,this.disabled_form_elements)<0)){elm.disabled=lock}}}};this.mailto_handler_uri=function(){return location.href.split("?")[0]+"?_task=mail&_action=compose&_to=%s"};this.register_protocol_handler=function(name){try{window.navigator.registerProtocolHandler("mailto",this.mailto_handler_uri(),name)}catch(e){}};this.check_protocol_handler=function(name,elem){var nav=window.navigator;if(!nav||(typeof nav.registerProtocolHandler!="function")||((typeof nav.isProtocolHandlerRegistered=="function")&&nav.isProtocolHandlerRegistered("mailto",this.mailto_handler_uri())=="registered")){$(elem).addClass("disabled")}else{$(elem).click(function(){rcmail.register_protocol_handler(name);return false})}};this.browser_capabilities_check=function(){if(!this.env.browser_capabilities){this.env.browser_capabilities={}}if(this.env.browser_capabilities.pdf===undefined){this.env.browser_capabilities.pdf=this.pdf_support_check()}if(this.env.browser_capabilities.flash===undefined){this.env.browser_capabilities.flash=this.flash_support_check()}if(this.env.browser_capabilities.tif===undefined){this.tif_support_check()}};this.browser_capabilities=function(){if(!this.env.browser_capabilities){return""}var n,ret=[];for(n in this.env.browser_capabilities){ret.push(n+"="+this.env.browser_capabilities[n])}return ret.join()};this.tif_support_check=function(){var img=new Image();img.onload=function(){rcmail.env.browser_capabilities.tif=1};img.onerror=function(){rcmail.env.browser_capabilities.tif=0};img.src="program/resources/blank.tif"};this.pdf_support_check=function(){var plugin=navigator.mimeTypes?navigator.mimeTypes["application/pdf"]:{},plugins=navigator.plugins,len=plugins.length,regex=/Adobe Reader|PDF|Acrobat/i;if(plugin&&plugin.enabledPlugin){return 1}if(window.ActiveXObject){try{if(axObj=new ActiveXObject("AcroPDF.PDF")){return 1}}catch(e){}try{if(axObj=new ActiveXObject("PDF.PdfCtrl")){return 1}}catch(e){}}for(i=0;i<len;i++){plugin=plugins[i];if(typeof plugin==="String"){if(regex.test(plugin)){return 1}}else{if(plugin.name&®ex.test(plugin.name)){return 1}}}return 0};this.flash_support_check=function(){var plugin=navigator.mimeTypes?navigator.mimeTypes["application/x-shockwave-flash"]:{};if(plugin&&plugin.enabledPlugin){return 1}if(window.ActiveXObject){try{if(axObj=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")){return 1}}catch(e){}}return 0};this.set_cookie=function(name,value,expires){setCookie(name,value,expires,this.env.cookie_path,this.env.cookie_domain,this.env.cookie_secure)}}rcube_webmail.long_subject_title=function(d,a){if(!d.title){var b=$(d);if(b.width()+a*15>b.parent().width()){d.title=b.text()}}};rcube_webmail.long_subject_title_ex=function(g,b){if(!g.title){var e=$(g),a=$.trim(e.text()),f=$("<span>").text(a).css({position:"absolute","float":"left",visibility:"hidden","font-size":e.css("font-size"),"font-weight":e.css("font-weight")}).appendTo($("body")),d=f.width();f.remove();if(d+b*15>e.width()){g.title=a}}};rcube_webmail.prototype.get_cookie=getCookie;rcube_webmail.prototype.addEventListener=rcube_event_engine.prototype.addEventListener;rcube_webmail.prototype.removeEventListener=rcube_event_engine.prototype.removeEventListener;rcube_webmail.prototype.triggerEvent=rcube_event_engine.prototype.triggerEvent;
\ No newline at end of file diff --git a/program/js/common.js b/program/js/common.js index afaf91639..f6fa154ef 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -1,723 +1 @@ -/* - +-----------------------------------------------------------------------+ - | Roundcube common js library | - | | - | This file is part of the Roundcube web development suite | - | 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. | - | See the README file for a full license statement. | - | | - +-----------------------------------------------------------------------+ - | Author: Thomas Bruederli <roundcube@gmail.com> | - +-----------------------------------------------------------------------+ -*/ - -// Constants -var CONTROL_KEY = 1; -var SHIFT_KEY = 2; -var CONTROL_SHIFT_KEY = 3; - - -/** - * Default browser check class - * @constructor - */ -function roundcube_browser() -{ - var n = navigator; - - this.ver = parseFloat(n.appVersion); - this.appver = n.appVersion; - this.agent = n.userAgent; - this.agent_lc = n.userAgent.toLowerCase(); - this.name = n.appName; - this.vendor = n.vendor ? n.vendor : ''; - this.vendver = n.vendorSub ? parseFloat(n.vendorSub) : 0; - this.product = n.product ? n.product : ''; - this.platform = String(n.platform).toLowerCase(); - this.lang = (n.language) ? n.language.substring(0,2) : - (n.browserLanguage) ? n.browserLanguage.substring(0,2) : - (n.systemLanguage) ? n.systemLanguage.substring(0,2) : 'en'; - - this.win = (this.platform.indexOf('win') >= 0); - this.mac = (this.platform.indexOf('mac') >= 0); - this.linux = (this.platform.indexOf('linux') >= 0); - this.unix = (this.platform.indexOf('unix') >= 0); - - this.dom = document.getElementById ? true : false; - this.dom2 = (document.addEventListener && document.removeEventListener); - - this.ie = (document.all && !window.opera); - this.ie4 = (this.ie && !this.dom); - this.ie5 = (this.dom && this.appver.indexOf('MSIE 5')>0); - this.ie8 = (this.dom && this.appver.indexOf('MSIE 8')>0); - this.ie9 = (this.dom && this.appver.indexOf('MSIE 9')>0); - this.ie7 = (this.dom && this.appver.indexOf('MSIE 7')>0); - this.ie6 = (this.dom && !this.ie8 && !this.ie7 && this.appver.indexOf('MSIE 6')>0); - - this.ns = ((this.ver < 5 && this.name == 'Netscape') || (this.ver >= 5 && this.vendor.indexOf('Netscape') >= 0)); - this.chrome = (this.agent_lc.indexOf('chrome') > 0); - this.safari = (!this.chrome && (this.agent_lc.indexOf('safari') > 0 || this.agent_lc.indexOf('applewebkit') > 0)); - this.konq = (this.agent_lc.indexOf('konqueror') > 0); - this.mz = (this.dom && !this.ie && !this.ns && !this.chrome && !this.safari && !this.konq && this.agent.indexOf('Mozilla') >= 0); - this.iphone = (this.safari && (this.agent_lc.indexOf('iphone') > 0 || this.agent_lc.indexOf('ipod') > 0)); - this.ipad = (this.safari && this.agent_lc.indexOf('ipad') > 0); - this.opera = window.opera ? true : false; - - if (this.opera && window.RegExp) - this.vendver = (/opera(\s|\/)([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$2) : -1; - else if (this.chrome && window.RegExp) - this.vendver = (/chrome\/([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0; - else if (!this.vendver && this.safari) - this.vendver = (/(safari|applewebkit)\/([0-9]+)/.test(this.agent_lc)) ? parseInt(RegExp.$2) : 0; - else if ((!this.vendver && this.mz) || this.agent.indexOf('Camino')>0) - this.vendver = (/rv:([0-9\.]+)/.test(this.agent)) ? parseFloat(RegExp.$1) : 0; - else if (this.ie && window.RegExp) - this.vendver = (/msie\s+([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0; - else if (this.konq && window.RegExp) - this.vendver = (/khtml\/([0-9\.]+)/.test(this.agent_lc)) ? parseFloat(RegExp.$1) : 0; - - // get real language out of safari's user agent - if (this.safari && (/;\s+([a-z]{2})-[a-z]{2}\)/.test(this.agent_lc))) - this.lang = RegExp.$1; - - this.tablet = /ipad|android|xoom|sch-i800|playbook|tablet|kindle/i.test(this.agent_lc); - this.mobile = /iphone|ipod|blackberry|iemobile|opera mini|opera mobi|mobile/i.test(this.agent_lc); - this.touch = this.mobile || this.tablet; - this.dhtml = ((this.ie4 && this.win) || this.ie5 || this.ie6 || this.ns4 || this.mz); - this.vml = (this.win && this.ie && this.dom && !this.opera); - this.pngalpha = (this.mz || (this.opera && this.vendver >= 6) || (this.ie && this.mac && this.vendver >= 5) || - (this.ie && this.win && this.vendver >= 5.5) || this.safari); - this.opacity = (this.mz || (this.ie && this.vendver >= 5.5 && !this.opera) || (this.safari && this.vendver >= 100)); - this.cookies = n.cookieEnabled; - - // test for XMLHTTP support - this.xmlhttp_test = function() - { - var activeX_test = new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}"); - this.xmlhttp = (window.XMLHttpRequest || (window.ActiveXObject && activeX_test())); - return this.xmlhttp; - }; - - // set class names to html tag according to the current user agent detection - // this allows browser-specific css selectors like "html.chrome .someclass" - this.set_html_class = function() - { - var classname = ' js'; - - if (this.ie) - classname += ' ie ie'+parseInt(this.vendver); - else if (this.opera) - classname += ' opera'; - else if (this.konq) - classname += ' konqueror'; - else if (this.safari) - classname += ' chrome'; - else if (this.chrome) - classname += ' chrome'; - else if (this.mz) - classname += ' mozilla'; - - if (this.iphone) - classname += ' iphone'; - else if (this.ipad) - classname += ' ipad'; - else if (this.safari || this.chrome) - classname += ' webkit'; - - if (this.mobile) - classname += ' mobile'; - if (this.tablet) - classname += ' tablet'; - - if (document.documentElement) - document.documentElement.className += classname; - }; -}; - - -// static functions for DOM event handling -var rcube_event = { - -/** - * returns the event target element - */ -get_target: function(e) -{ - e = e || window.event; - return e && e.target ? e.target : e.srcElement; -}, - -/** - * returns the event key code - */ -get_keycode: function(e) -{ - e = e || window.event; - return e && e.keyCode ? e.keyCode : (e && e.which ? e.which : 0); -}, - -/** - * returns the event key code - */ -get_button: function(e) -{ - e = e || window.event; - return e && e.button !== undefined ? e.button : (e && e.which ? e.which : 0); -}, - -/** - * returns modifier key (constants defined at top of file) - */ -get_modifier: function(e) -{ - var opcode = 0; - e = e || window.event; - - if (bw.mac && e) - opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY); - else if (e) - opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY); - - return opcode; -}, - -/** - * Return absolute mouse position of an event - */ -get_mouse_pos: function(e) -{ - if (!e) e = window.event; - var mX = (e.pageX) ? e.pageX : e.clientX, - mY = (e.pageY) ? e.pageY : e.clientY; - - if (document.body && document.all) { - mX += document.body.scrollLeft; - mY += document.body.scrollTop; - } - - if (e._offset) { - mX += e._offset.left; - mY += e._offset.top; - } - - return { x:mX, y:mY }; -}, - -/** - * Add an object method as event listener to a certain element - */ -add_listener: function(p) -{ - if (!p.object || !p.method) // not enough arguments - return; - if (!p.element) - p.element = document; - - if (!p.object._rc_events) - p.object._rc_events = []; - - var key = p.event + '*' + p.method; - if (!p.object._rc_events[key]) - p.object._rc_events[key] = function(e){ return p.object[p.method](e); }; - - if (p.element.addEventListener) - p.element.addEventListener(p.event, p.object._rc_events[key], false); - else if (p.element.attachEvent) { - // IE allows multiple events with the same function to be applied to the same object - // forcibly detach the event, then attach - p.element.detachEvent('on'+p.event, p.object._rc_events[key]); - p.element.attachEvent('on'+p.event, p.object._rc_events[key]); - } - else - p.element['on'+p.event] = p.object._rc_events[key]; -}, - -/** - * Remove event listener - */ -remove_listener: function(p) -{ - if (!p.element) - p.element = document; - - var key = p.event + '*' + p.method; - if (p.object && p.object._rc_events && p.object._rc_events[key]) { - if (p.element.removeEventListener) - p.element.removeEventListener(p.event, p.object._rc_events[key], false); - else if (p.element.detachEvent) - p.element.detachEvent('on'+p.event, p.object._rc_events[key]); - else - p.element['on'+p.event] = null; - } -}, - -/** - * Prevent event propagation and bubbling - */ -cancel: function(evt) -{ - var e = evt ? evt : window.event; - if (e.preventDefault) - e.preventDefault(); - if (e.stopPropagation) - e.stopPropagation(); - - e.cancelBubble = true; - e.returnValue = false; - return false; -}, - -touchevent: function(e) -{ - return { pageX:e.pageX, pageY:e.pageY, offsetX:e.pageX - e.target.offsetLeft, offsetY:e.pageY - e.target.offsetTop, target:e.target, istouch:true }; -} - -}; - - -/** - * rcmail objects event interface - */ -function rcube_event_engine() -{ - this._events = {}; -}; - -rcube_event_engine.prototype = { - -/** - * Setter for object event handlers - * - * @param {String} Event name - * @param {Function} Handler function - * @return Listener ID (used to remove this handler later on) - */ -addEventListener: function(evt, func, obj) -{ - if (!this._events) - this._events = {}; - if (!this._events[evt]) - this._events[evt] = []; - - this._events[evt].push({func:func, obj:obj ? obj : window}); -}, - -/** - * Removes a specific event listener - * - * @param {String} Event name - * @param {Int} Listener ID to remove - */ -removeEventListener: function(evt, func, obj) -{ - if (obj === undefined) - obj = window; - - for (var h,i=0; this._events && this._events[evt] && i < this._events[evt].length; i++) - if ((h = this._events[evt][i]) && h.func == func && h.obj == obj) - this._events[evt][i] = null; -}, - -/** - * This will execute all registered event handlers - * - * @param {String} Event to trigger - * @param {Object} Event object/arguments - */ -triggerEvent: function(evt, e) -{ - var ret, h; - if (e === undefined) - e = this; - else if (typeof e === 'object') - e.event = evt; - - if (this._events && this._events[evt] && !this._event_exec) { - this._event_exec = true; - for (var i=0; i < this._events[evt].length; i++) { - if ((h = this._events[evt][i])) { - if (typeof h.func === 'function') - ret = h.func.call ? h.func.call(h.obj, e) : h.func(e); - else if (typeof h.obj[h.func] === 'function') - ret = h.obj[h.func](e); - - // cancel event execution - if (ret !== undefined && !ret) - break; - } - } - if (ret && ret.event) { - try { - delete ret.event; - } catch (err) { - // IE6-7 doesn't support deleting HTMLFormElement attributes (#1488017) - $(ret).removeAttr('event'); - } - } - } - - this._event_exec = false; - if (e.event) { - try { - delete e.event; - } catch (err) { - // IE6-7 doesn't support deleting HTMLFormElement attributes (#1488017) - $(e).removeAttr('event'); - } - } - - return ret; -} - -}; // end rcube_event_engine.prototype - - -// check if input is a valid email address -// By Cal Henderson <cal@iamcal.com> -// http://code.iamcal.com/php/rfc822/ -function rcube_check_email(input, inline) -{ - if (input && window.RegExp) { - var qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]', - dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]', - atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+', - quoted_pair = '\\x5c[\\x00-\\x7f]', - quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22', - ipv4 = '\\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\\]', - ipv6 = '\\[IPv6:[0-9a-f:.]+\\]', - ip_addr = '(' + ipv4 + ')|(' + ipv6 + ')', - // Use simplified domain matching, because we need to allow Unicode characters here - // So, e-mail address should be validated also on server side after idn_to_ascii() use - //domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d', - //sub_domain = '('+atom+'|'+domain_literal+')', - // allow punycode/unicode top-level domain - domain = '(('+ip_addr+')|(([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})))', - // ICANN e-mail test (http://idn.icann.org/E-mail_test) - icann_domains = [ - '\\u0645\\u062b\\u0627\\u0644\\x2e\\u0625\\u062e\\u062a\\u0628\\u0627\\u0631', - '\\u4f8b\\u5b50\\x2e\\u6d4b\\u8bd5', - '\\u4f8b\\u5b50\\x2e\\u6e2c\\u8a66', - '\\u03c0\\u03b1\\u03c1\\u03ac\\u03b4\\u03b5\\u03b9\\u03b3\\u03bc\\u03b1\\x2e\\u03b4\\u03bf\\u03ba\\u03b9\\u03bc\\u03ae', - '\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923\\x2e\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e', - '\\u4f8b\\u3048\\x2e\\u30c6\\u30b9\\u30c8', - '\\uc2e4\\ub840\\x2e\\ud14c\\uc2a4\\ud2b8', - '\\u0645\\u062b\\u0627\\u0644\\x2e\\u0622\\u0632\\u0645\\u0627\\u06cc\\u0634\u06cc', - '\\u043f\\u0440\\u0438\\u043c\\u0435\\u0440\\x2e\\u0438\\u0441\\u043f\\u044b\\u0442\\u0430\\u043d\\u0438\\u0435', - '\\u0b89\\u0ba4\\u0bbe\\u0bb0\\u0ba3\\u0bae\\u0bcd\\x2e\\u0baa\\u0bb0\\u0bbf\\u0b9f\\u0bcd\\u0b9a\\u0bc8', - '\\u05d1\\u05f2\\u05b7\\u05e9\\u05e4\\u05bc\\u05d9\\u05dc\\x2e\\u05d8\\u05e2\\u05e1\\u05d8' - ], - icann_addr = 'mailtest\\x40('+icann_domains.join('|')+')', - word = '('+atom+'|'+quoted_string+')', - delim = '[,;\s\n]', - local_part = word+'(\\x2e'+word+')*', - addr_spec = '(('+local_part+'\\x40'+domain+')|('+icann_addr+'))', - reg1 = inline ? new RegExp('(^|<|'+delim+')'+addr_spec+'($|>|'+delim+')', 'i') : new RegExp('^'+addr_spec+'$', 'i'); - - return reg1.test(input) ? true : false; - } - - return false; -}; - -// recursively copy an object -function rcube_clone_object(obj) -{ - var out = {}; - - for (var key in obj) { - if (obj[key] && typeof obj[key] === 'object') - out[key] = rcube_clone_object(obj[key]); - else - out[key] = obj[key]; - } - - return out; -}; - -// make a string URL safe (and compatible with PHP's rawurlencode()) -function urlencode(str) -{ - if (window.encodeURIComponent) - return encodeURIComponent(str).replace('*', '%2A'); - - return escape(str) - .replace('+', '%2B') - .replace('*', '%2A') - .replace('/', '%2F') - .replace('@', '%40'); -}; - - -// get any type of html objects by id/name -function rcube_find_object(id, d) -{ - var n, f, obj, e; - if(!d) d = document; - - if(d.getElementsByName && (e = d.getElementsByName(id))) - obj = e[0]; - if(!obj && d.getElementById) - obj = d.getElementById(id); - if(!obj && d.all) - obj = d.all[id]; - - if(!obj && d.images.length) - obj = d.images[id]; - - if (!obj && d.forms.length) { - for (f=0; f<d.forms.length; f++) { - if(d.forms[f].name == id) - obj = d.forms[f]; - else if(d.forms[f].elements[id]) - obj = d.forms[f].elements[id]; - } - } - - if (!obj && d.layers) { - if (d.layers[id]) obj = d.layers[id]; - for (n=0; !obj && n<d.layers.length; n++) - obj = rcube_find_object(id, d.layers[n].document); - } - - return obj; -}; - -// determine whether the mouse is over the given object or not -function rcube_mouse_is_over(ev, obj) -{ - var mouse = rcube_event.get_mouse_pos(ev), - pos = $(obj).offset(); - - return ((mouse.x >= pos.left) && (mouse.x < (pos.left + obj.offsetWidth)) && - (mouse.y >= pos.top) && (mouse.y < (pos.top + obj.offsetHeight))); -}; - - -// cookie functions by GoogieSpell -function setCookie(name, value, expires, path, domain, secure) -{ - var curCookie = name + "=" + escape(value) + - (expires ? "; expires=" + expires.toGMTString() : "") + - (path ? "; path=" + path : "") + - (domain ? "; domain=" + domain : "") + - (secure ? "; secure" : ""); - document.cookie = curCookie; -}; - -function getCookie(name) -{ - var dc = document.cookie, - prefix = name + "=", - begin = dc.indexOf("; " + prefix); - - if (begin == -1) { - begin = dc.indexOf(prefix); - if (begin != 0) - return null; - } - else { - begin += 2; - } - - var end = dc.indexOf(";", begin); - if (end == -1) - end = dc.length; - - return unescape(dc.substring(begin + prefix.length, end)); -}; - -// deprecated aliases, to be removed, use rcmail.set_cookie/rcmail.get_cookie -roundcube_browser.prototype.set_cookie = setCookie; -roundcube_browser.prototype.get_cookie = getCookie; - -// tiny replacement for Firebox functionality -function rcube_console() -{ - this.log = function(msg) - { - var box = rcube_find_object('dbgconsole'); - - if (box) { - if (msg.charAt(msg.length-1)=='\n') - msg += '--------------------------------------\n'; - else - msg += '\n--------------------------------------\n'; - - // Konqueror doesn't allow to just change the value of hidden element - if (bw.konq) { - box.innerText += msg; - box.value = box.innerText; - } else - box.value += msg; - } - }; - - this.reset = function() - { - var box = rcube_find_object('dbgconsole'); - if (box) - box.innerText = box.value = ''; - }; -}; - -var bw = new roundcube_browser(); -bw.set_html_class(); - - -// Add escape() method to RegExp object -// http://dev.rubyonrails.org/changeset/7271 -RegExp.escape = function(str) -{ - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; - -// Extend Date prototype to detect Standard timezone without DST -// from http://www.michaelapproved.com/articles/timezone-detect-and-ignore-daylight-saving-time-dst/ -Date.prototype.getStdTimezoneOffset = function() -{ - var m = 12, - d = new Date(null, m, 1), - tzo = d.getTimezoneOffset(); - - while (--m) { - d.setUTCMonth(m); - if (tzo != d.getTimezoneOffset()) { - return Math.max(tzo, d.getTimezoneOffset()); - } - } - - return tzo; -} - -// Make getElementById() case-sensitive on IE -if (bw.ie) { - document._getElementById = document.getElementById; - document.getElementById = function(id) { - var i = 0, obj = document._getElementById(id); - - if (obj && obj.id != id) - while ((obj = document.all[i]) && obj.id != id) - i++; - - return obj; - } -} - -// jQuery plugin to emulate HTML5 placeholder attributes on input elements -jQuery.fn.placeholder = function(text) { - return this.each(function() { - var active = false, elem = $(this); - this.title = text; - - // Try HTML5 placeholder attribute first - if ('placeholder' in this) { - elem.attr('placeholder', text); - } - // Fallback to Javascript emulation of placeholder - else { - this._placeholder = text; - elem.blur(function(e) { - if ($.trim(elem.val()) == "") - elem.val(text); - elem.triggerHandler('change'); - }) - .focus(function(e) { - if ($.trim(elem.val()) == text) - elem.val(""); - elem.triggerHandler('change'); - }) - .change(function(e) { - var active = elem.val() == text; - elem[(active ? 'addClass' : 'removeClass')]('placeholder').attr('spellcheck', active); - }); - - // Do not blur currently focused element (catch exception: #1489008) - try { active = this == document.activeElement; } catch(e) {} - if (!active) - elem.blur(); - } - }); -}; - - -// This code was written by Tyler Akins and has been placed in the -// public domain. It would be nice if you left this header intact. -// Base64 code from Tyler Akins -- http://rumkin.com -var Base64 = (function () { - var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - - var obj = { - /** - * Encodes a string in base64 - * @param {String} input The string to encode in base64. - */ - encode: function (input) { - if (typeof(window.btoa) === 'function') - return btoa(input); - - var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0, output = '', len = input.length; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) - enc3 = enc4 = 64; - else if (isNaN(chr3)) - enc4 = 64; - - output = output - + keyStr.charAt(enc1) + keyStr.charAt(enc2) - + keyStr.charAt(enc3) + keyStr.charAt(enc4); - } while (i < len); - - return output; - }, - - /** - * Decodes a base64 string. - * @param {String} input The string to decode. - */ - decode: function (input) { - if (typeof(window.atob) === 'function') - return atob(input); - - var chr1, chr2, chr3, enc1, enc2, enc3, enc4, len, i = 0, output = ''; - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - len = input.length; - - do { - enc1 = keyStr.indexOf(input.charAt(i++)); - enc2 = keyStr.indexOf(input.charAt(i++)); - enc3 = keyStr.indexOf(input.charAt(i++)); - enc4 = keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) - output = output + String.fromCharCode(chr2); - if (enc4 != 64) - output = output + String.fromCharCode(chr3); - } while (i < len); - - return output; - } - }; - - return obj; -})(); +var CONTROL_KEY=1;var SHIFT_KEY=2;var CONTROL_SHIFT_KEY=3;function roundcube_browser(){var a=navigator;this.ver=parseFloat(a.appVersion);this.appver=a.appVersion;this.agent=a.userAgent;this.agent_lc=a.userAgent.toLowerCase();this.name=a.appName;this.vendor=a.vendor?a.vendor:"";this.vendver=a.vendorSub?parseFloat(a.vendorSub):0;this.product=a.product?a.product:"";this.platform=String(a.platform).toLowerCase();this.lang=(a.language)?a.language.substring(0,2):(a.browserLanguage)?a.browserLanguage.substring(0,2):(a.systemLanguage)?a.systemLanguage.substring(0,2):"en";this.win=(this.platform.indexOf("win")>=0);this.mac=(this.platform.indexOf("mac")>=0);this.linux=(this.platform.indexOf("linux")>=0);this.unix=(this.platform.indexOf("unix")>=0);this.dom=document.getElementById?true:false;this.dom2=(document.addEventListener&&document.removeEventListener);this.ie=(document.all&&!window.opera);this.ie4=(this.ie&&!this.dom);this.ie5=(this.dom&&this.appver.indexOf("MSIE 5")>0);this.ie8=(this.dom&&this.appver.indexOf("MSIE 8")>0);this.ie9=(this.dom&&this.appver.indexOf("MSIE 9")>0);this.ie7=(this.dom&&this.appver.indexOf("MSIE 7")>0);this.ie6=(this.dom&&!this.ie8&&!this.ie7&&this.appver.indexOf("MSIE 6")>0);this.ns=((this.ver<5&&this.name=="Netscape")||(this.ver>=5&&this.vendor.indexOf("Netscape")>=0));this.chrome=(this.agent_lc.indexOf("chrome")>0);this.safari=(!this.chrome&&(this.agent_lc.indexOf("safari")>0||this.agent_lc.indexOf("applewebkit")>0));this.konq=(this.agent_lc.indexOf("konqueror")>0);this.mz=(this.dom&&!this.ie&&!this.ns&&!this.chrome&&!this.safari&&!this.konq&&this.agent.indexOf("Mozilla")>=0);this.iphone=(this.safari&&(this.agent_lc.indexOf("iphone")>0||this.agent_lc.indexOf("ipod")>0));this.ipad=(this.safari&&this.agent_lc.indexOf("ipad")>0);this.opera=window.opera?true:false;if(this.opera&&window.RegExp){this.vendver=(/opera(\s|\/)([0-9\.]+)/.test(this.agent_lc))?parseFloat(RegExp.$2):-1}else{if(this.chrome&&window.RegExp){this.vendver=(/chrome\/([0-9\.]+)/.test(this.agent_lc))?parseFloat(RegExp.$1):0}else{if(!this.vendver&&this.safari){this.vendver=(/(safari|applewebkit)\/([0-9]+)/.test(this.agent_lc))?parseInt(RegExp.$2):0}else{if((!this.vendver&&this.mz)||this.agent.indexOf("Camino")>0){this.vendver=(/rv:([0-9\.]+)/.test(this.agent))?parseFloat(RegExp.$1):0}else{if(this.ie&&window.RegExp){this.vendver=(/msie\s+([0-9\.]+)/.test(this.agent_lc))?parseFloat(RegExp.$1):0}else{if(this.konq&&window.RegExp){this.vendver=(/khtml\/([0-9\.]+)/.test(this.agent_lc))?parseFloat(RegExp.$1):0}}}}}}if(this.safari&&(/;\s+([a-z]{2})-[a-z]{2}\)/.test(this.agent_lc))){this.lang=RegExp.$1}this.tablet=/ipad|android|xoom|sch-i800|playbook|tablet|kindle/i.test(this.agent_lc);this.mobile=/iphone|ipod|blackberry|iemobile|opera mini|opera mobi|mobile/i.test(this.agent_lc);this.touch=this.mobile||this.tablet;this.dhtml=((this.ie4&&this.win)||this.ie5||this.ie6||this.ns4||this.mz);this.vml=(this.win&&this.ie&&this.dom&&!this.opera);this.pngalpha=(this.mz||(this.opera&&this.vendver>=6)||(this.ie&&this.mac&&this.vendver>=5)||(this.ie&&this.win&&this.vendver>=5.5)||this.safari);this.opacity=(this.mz||(this.ie&&this.vendver>=5.5&&!this.opera)||(this.safari&&this.vendver>=100));this.cookies=a.cookieEnabled;this.xmlhttp_test=function(){var b=new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}");this.xmlhttp=(window.XMLHttpRequest||(window.ActiveXObject&&b()));return this.xmlhttp};this.set_html_class=function(){var b=" js";if(this.ie){b+=" ie ie"+parseInt(this.vendver)}else{if(this.opera){b+=" opera"}else{if(this.konq){b+=" konqueror"}else{if(this.safari){b+=" chrome"}else{if(this.chrome){b+=" chrome"}else{if(this.mz){b+=" mozilla"}}}}}}if(this.iphone){b+=" iphone"}else{if(this.ipad){b+=" ipad"}else{if(this.safari||this.chrome){b+=" webkit"}}}if(this.mobile){b+=" mobile"}if(this.tablet){b+=" tablet"}if(document.documentElement){document.documentElement.className+=b}}}var rcube_event={get_target:function(a){a=a||window.event;return a&&a.target?a.target:a.srcElement},get_keycode:function(a){a=a||window.event;return a&&a.keyCode?a.keyCode:(a&&a.which?a.which:0)},get_button:function(a){a=a||window.event;return a&&a.button!==undefined?a.button:(a&&a.which?a.which:0)},get_modifier:function(b){var a=0;b=b||window.event;if(bw.mac&&b){a+=(b.metaKey&&CONTROL_KEY)+(b.shiftKey&&SHIFT_KEY)}else{if(b){a+=(b.ctrlKey&&CONTROL_KEY)+(b.shiftKey&&SHIFT_KEY)}}return a},get_mouse_pos:function(c){if(!c){c=window.event}var b=(c.pageX)?c.pageX:c.clientX,a=(c.pageY)?c.pageY:c.clientY;if(document.body&&document.all){b+=document.body.scrollLeft;a+=document.body.scrollTop}if(c._offset){b+=c._offset.left;a+=c._offset.top}return{x:b,y:a}},add_listener:function(b){if(!b.object||!b.method){return}if(!b.element){b.element=document}if(!b.object._rc_events){b.object._rc_events=[]}var a=b.event+"*"+b.method;if(!b.object._rc_events[a]){b.object._rc_events[a]=function(c){return b.object[b.method](c)}}if(b.element.addEventListener){b.element.addEventListener(b.event,b.object._rc_events[a],false)}else{if(b.element.attachEvent){b.element.detachEvent("on"+b.event,b.object._rc_events[a]);b.element.attachEvent("on"+b.event,b.object._rc_events[a])}else{b.element["on"+b.event]=b.object._rc_events[a]}}},remove_listener:function(b){if(!b.element){b.element=document}var a=b.event+"*"+b.method;if(b.object&&b.object._rc_events&&b.object._rc_events[a]){if(b.element.removeEventListener){b.element.removeEventListener(b.event,b.object._rc_events[a],false)}else{if(b.element.detachEvent){b.element.detachEvent("on"+b.event,b.object._rc_events[a])}else{b.element["on"+b.event]=null}}}},cancel:function(a){var b=a?a:window.event;if(b.preventDefault){b.preventDefault()}if(b.stopPropagation){b.stopPropagation()}b.cancelBubble=true;b.returnValue=false;return false},touchevent:function(a){return{pageX:a.pageX,pageY:a.pageY,offsetX:a.pageX-a.target.offsetLeft,offsetY:a.pageY-a.target.offsetTop,target:a.target,istouch:true}}};function rcube_event_engine(){this._events={}}rcube_event_engine.prototype={addEventListener:function(a,b,d){if(!this._events){this._events={}}if(!this._events[a]){this._events[a]=[]}var c={func:b,obj:d?d:window};this._events[a][this._events[a].length]=c},removeEventListener:function(a,d,e){if(e===undefined){e=window}for(var c,b=0;this._events&&this._events[a]&&b<this._events[a].length;b++){if((c=this._events[a][b])&&c.func==d&&c.obj==e){this._events[a][b]=null}}},triggerEvent:function(a,g){var b,d;if(g===undefined){g=this}else{if(typeof g==="object"){g.event=a}}if(this._events&&this._events[a]&&!this._event_exec){this._event_exec=true;for(var c=0;c<this._events[a].length;c++){if((d=this._events[a][c])){if(typeof d.func==="function"){b=d.func.call?d.func.call(d.obj,g):d.func(g)}else{if(typeof d.obj[d.func]==="function"){b=d.obj[d.func](g)}}if(b!==undefined&&!b){break}}}if(b&&b.event){try{delete b.event}catch(f){$(b).removeAttr("event")}}}this._event_exec=false;if(g.event){try{delete g.event}catch(f){$(g).removeAttr("event")}}return b}};function rcube_layer(b,a){this.name=b;this.create=function(m){var d=(m.x)?m.x:0,k=(m.y)?m.y:0,j=m.width,f=m.height,g=m.zindex,c=m.vis,i=m.parent,e=document.createElement("DIV");e.id=this.name;e.style.position="absolute";e.style.visibility=(c)?(c==2)?"inherit":"visible":"hidden";e.style.left=d+"px";e.style.top=k+"px";if(j){e.style.width=j.toString().match(/\%$/)?j:j+"px"}if(f){e.style.height=f.toString().match(/\%$/)?f:f+"px"}if(g){e.style.zIndex=g}if(i){i.appendChild(e)}else{document.body.appendChild(e)}this.elm=e};if(a!=null){this.create(a);this.name=this.elm.id}else{this.elm=document.getElementById(b)}if(!this.elm){return false}this.css=this.elm.style;this.event=this.elm;this.width=this.elm.offsetWidth;this.height=this.elm.offsetHeight;this.x=parseInt(this.elm.offsetLeft);this.y=parseInt(this.elm.offsetTop);this.visible=(this.css.visibility=="visible"||this.css.visibility=="show"||this.css.visibility=="inherit")?true:false;this.move=function(c,d){this.x=c;this.y=d;this.css.left=Math.round(this.x)+"px";this.css.top=Math.round(this.y)+"px"};this.resize=function(c,d){this.css.width=c+"px";this.css.height=d+"px";this.width=c;this.height=d};this.show=function(c){if(c==1){this.css.visibility="visible";this.visible=true}else{if(c==2){this.css.visibility="inherit";this.visible=true}else{this.css.visibility="hidden";this.visible=false}}};this.write=function(c){this.elm.innerHTML=c}}function rcube_check_email(h,c){if(h&&window.RegExp){var f="[^\\x0d\\x22\\x5c\\x80-\\xff]",e="[^\\x0d\\x5b-\\x5d\\x80-\\xff]",a="[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+",g="\\x5c[\\x00-\\x7f]",l="\\x22("+f+"|"+g+")*\\x22",k="\\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\\]",j="\\[IPv6:[0-9a-f:.]+\\]",i="("+k+")|("+j+")",r="(("+i+")|(([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})))",d=["\\u0645\\u062b\\u0627\\u0644\\x2e\\u0625\\u062e\\u062a\\u0628\\u0627\\u0631","\\u4f8b\\u5b50\\x2e\\u6d4b\\u8bd5","\\u4f8b\\u5b50\\x2e\\u6e2c\\u8a66","\\u03c0\\u03b1\\u03c1\\u03ac\\u03b4\\u03b5\\u03b9\\u03b3\\u03bc\\u03b1\\x2e\\u03b4\\u03bf\\u03ba\\u03b9\\u03bc\\u03ae","\\u0909\\u0926\\u093e\\u0939\\u0930\\u0923\\x2e\\u092a\\u0930\\u0940\\u0915\\u094d\\u0937\\u093e","\\u4f8b\\u3048\\x2e\\u30c6\\u30b9\\u30c8","\\uc2e4\\ub840\\x2e\\ud14c\\uc2a4\\ud2b8","\\u0645\\u062b\\u0627\\u0644\\x2e\\u0622\\u0632\\u0645\\u0627\\u06cc\\u0634\u06cc","\\u043f\\u0440\\u0438\\u043c\\u0435\\u0440\\x2e\\u0438\\u0441\\u043f\\u044b\\u0442\\u0430\\u043d\\u0438\\u0435","\\u0b89\\u0ba4\\u0bbe\\u0bb0\\u0ba3\\u0bae\\u0bcd\\x2e\\u0baa\\u0bb0\\u0bbf\\u0b9f\\u0bcd\\u0b9a\\u0bc8","\\u05d1\\u05f2\\u05b7\\u05e9\\u05e4\\u05bc\\u05d9\\u05dc\\x2e\\u05d8\\u05e2\\u05e1\\u05d8"],p="mailtest\\x40("+d.join("|")+")",n="("+a+"|"+l+")",q="[,;s\n]",m=n+"(\\x2e"+n+")*",b="(("+m+"\\x40"+r+")|("+p+"))",o=c?new RegExp("(^|<|"+q+")"+b+"($|>|"+q+")","i"):new RegExp("^"+b+"$","i");return o.test(h)?true:false}return false}function rcube_clone_object(c){var a={};for(var b in c){if(c[b]&&typeof c[b]==="object"){a[b]=clone_object(c[b])}else{a[b]=c[b]}}return a}function urlencode(a){if(window.encodeURIComponent){return encodeURIComponent(a).replace("*","%2A")}return escape(a).replace("+","%2B").replace("*","%2A").replace("/","%2F").replace("@","%40")}function rcube_find_object(i,g){var h,a,c,b;if(!g){g=document}if(g.getElementsByName&&(b=g.getElementsByName(i))){c=b[0]}if(!c&&g.getElementById){c=g.getElementById(i)}if(!c&&g.all){c=g.all[i]}if(!c&&g.images.length){c=g.images[i]}if(!c&&g.forms.length){for(a=0;a<g.forms.length;a++){if(g.forms[a].name==i){c=g.forms[a]}else{if(g.forms[a].elements[i]){c=g.forms[a].elements[i]}}}}if(!c&&g.layers){if(g.layers[i]){c=g.layers[i]}for(h=0;!c&&h<g.layers.length;h++){c=rcube_find_object(i,g.layers[h].document)}}return c}function rcube_mouse_is_over(b,c){var a=rcube_event.get_mouse_pos(b),d=$(c).offset();return((a.x>=d.left)&&(a.x<(d.left+c.offsetWidth))&&(a.y>=d.top)&&(a.y<(d.top+c.offsetHeight)))}function setCookie(c,e,a,g,d,f){var b=c+"="+escape(e)+(a?"; expires="+a.toGMTString():"")+(g?"; path="+g:"")+(d?"; domain="+d:"")+(f?"; secure":"");document.cookie=b}function getCookie(c){var b=document.cookie,e=c+"=",d=b.indexOf("; "+e);if(d==-1){d=b.indexOf(e);if(d!=0){return null}}else{d+=2}var a=b.indexOf(";",d);if(a==-1){a=b.length}return unescape(b.substring(d+e.length,a))}roundcube_browser.prototype.set_cookie=setCookie;roundcube_browser.prototype.get_cookie=getCookie;function rcube_console(){this.log=function(b){var a=rcube_find_object("dbgconsole");if(a){if(b.charAt(b.length-1)=="\n"){b+="--------------------------------------\n"}else{b+="\n--------------------------------------\n"}if(bw.konq){a.innerText+=b;a.value=a.innerText}else{a.value+=b}}};this.reset=function(){var a=rcube_find_object("dbgconsole");if(a){a.innerText=a.value=""}}}var bw=new roundcube_browser();bw.set_html_class();RegExp.escape=function(a){return String(a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")};Date.prototype.getStdTimezoneOffset=function(){var a=12,c=new Date(null,a,1),b=c.getTimezoneOffset();while(--a){c.setUTCMonth(a);if(b!=c.getTimezoneOffset()){return Math.max(b,c.getTimezoneOffset())}}return b};if(bw.ie){document._getElementById=document.getElementById;document.getElementById=function(c){var a=0,b=document._getElementById(c);if(b&&b.id!=c){while((b=document.all[a])&&b.id!=c){a++}}return b}}jQuery.fn.placeholder=function(a){return this.each(function(){var d=false,b=$(this);this.title=a;if("placeholder" in this){b.attr("placeholder",a)}else{this._placeholder=a;b.blur(function(f){if($.trim(b.val())==""){b.val(a)}b.triggerHandler("change")}).focus(function(f){if($.trim(b.val())==a){b.val("")}b.triggerHandler("change")}).change(function(g){var f=b.val()==a;b[(f?"addClass":"removeClass")]("placeholder").attr("spellcheck",f)});try{d=this==document.activeElement}catch(c){}if(!d){b.blur()}}})};var Base64=(function(){var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var b={encode:function(f){if(typeof(window.btoa)==="function"){return btoa(f)}var n,l,j,m,k,h,g,d=0,c="",e=f.length;do{n=f.charCodeAt(d++);l=f.charCodeAt(d++);j=f.charCodeAt(d++);m=n>>2;k=((n&3)<<4)|(l>>4);h=((l&15)<<2)|(j>>6);g=j&63;if(isNaN(l)){h=g=64}else{if(isNaN(j)){g=64}}c=c+a.charAt(m)+a.charAt(k)+a.charAt(h)+a.charAt(g)}while(d<e);return c},decode:function(f){if(typeof(window.atob)==="function"){return atob(f)}var n,l,j,m,k,h,g,e,d=0,c="";f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");e=f.length;do{m=a.indexOf(f.charAt(d++));k=a.indexOf(f.charAt(d++));h=a.indexOf(f.charAt(d++));g=a.indexOf(f.charAt(d++));n=(m<<2)|(k>>4);l=((k&15)<<4)|(h>>2);j=((h&3)<<6)|g;c=c+String.fromCharCode(n);if(h!=64){c=c+String.fromCharCode(l)}if(g!=64){c=c+String.fromCharCode(j)}}while(d<e);return c}};return b})();
\ No newline at end of file diff --git a/program/js/editor.js b/program/js/editor.js index e403d1f63..bc36e9a39 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -41,7 +41,7 @@ function rcmail_editor_init(config) $.extend(conf, { plugins: 'paste,tabfocus', theme_advanced_buttons1: 'bold,italic,underline,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,separator,outdent,indent,charmap,hr,link,unlink,code,forecolor', - theme_advanced_buttons2: 'fontselect,fontsizeselect' + theme_advanced_buttons2: ',fontselect,fontsizeselect' }); else { // mail compose $.extend(conf, { diff --git a/program/js/googiespell.js b/program/js/googiespell.js index 9832116dd..6d0a19c06 100644 --- a/program/js/googiespell.js +++ b/program/js/googiespell.js @@ -1,1135 +1 @@ -/* - +-----------------------------------------------------------------------+ - | Roundcube SpellCheck script | - | jQuery'fied spell checker based on GoogieSpell 4.0 | - | (which was published under GPL "version 2 or any later version") | - | | - | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006 Amir Salihefendic | - | Copyright (C) 2009 The Roundcube Dev Team | - | Copyright (C) 2011 Kolab Systems AG | - | | - | Licensed under the GNU General Public License version 3 or | - | any later version with exceptions for skins & plugins. | - | See the README file for a full license statement. | - | | - +-----------------------------------------------------------------------+ - | Authors: 4mir Salihefendic <amix@amix.dk> | - | Aleksander Machniak - <alec [at] alec.pl> | - +-----------------------------------------------------------------------+ -*/ - -var GOOGIE_CUR_LANG, - GOOGIE_DEFAULT_LANG = 'en'; - -function GoogieSpell(img_dir, server_url, has_dict) -{ - var ref = this, - cookie_value = rcmail.get_cookie('language'); - - GOOGIE_CUR_LANG = cookie_value != null ? cookie_value : GOOGIE_DEFAULT_LANG; - - this.array_keys = function(arr) { - var res = []; - for (var key in arr) { res.push([key]); } - return res; - } - - this.img_dir = img_dir; - this.server_url = server_url; - - this.org_lang_to_word = { - "da": "Dansk", "de": "Deutsch", "en": "English", - "es": "Español", "fr": "Français", "it": "Italiano", - "nl": "Nederlands", "pl": "Polski", "pt": "Português", - "ru": "РуÑÑкий", "fi": "Suomi", "sv": "Svenska" - }; - this.lang_to_word = this.org_lang_to_word; - this.langlist_codes = this.array_keys(this.lang_to_word); - this.show_change_lang_pic = true; - this.change_lang_pic_placement = 'right'; - this.report_state_change = true; - - this.ta_scroll_top = 0; - this.el_scroll_top = 0; - - this.lang_chck_spell = "Check spelling"; - this.lang_revert = "Revert to"; - this.lang_close = "Close"; - this.lang_rsm_edt = "Resume editing"; - this.lang_no_error_found = "No spelling errors found"; - this.lang_no_suggestions = "No suggestions"; - this.lang_learn_word = "Add to dictionary"; - - this.show_spell_img = false; // roundcube mod. - this.decoration = true; - this.use_close_btn = false; - this.edit_layer_dbl_click = true; - this.report_ta_not_found = true; - - // Extensions - this.custom_ajax_error = null; - this.custom_no_spelling_error = null; - this.custom_menu_builder = []; // Should take an eval function and a build menu function - this.custom_item_evaulator = null; // Should take an eval function and a build menu function - this.extra_menu_items = []; - this.custom_spellcheck_starter = null; - this.main_controller = true; - this.has_dictionary = has_dict; - - // Observers - this.lang_state_observer = null; - this.spelling_state_observer = null; - this.show_menu_observer = null; - this.all_errors_fixed_observer = null; - - // Focus links - used to give the text box focus - this.use_focus = false; - this.focus_link_t = null; - this.focus_link_b = null; - - // Counters - this.cnt_errors = 0; - this.cnt_errors_fixed = 0; - - // Set document's onclick to hide the language and error menu - $(document).bind('click', function(e) { - var target = $(e.target); - if(target.attr('googie_action_btn') != '1' && ref.isLangWindowShown()) - ref.hideLangWindow(); - if(target.attr('googie_action_btn') != '1' && ref.isErrorWindowShown()) - ref.hideErrorWindow(); - }); - - -this.decorateTextarea = function(id) -{ - this.text_area = typeof id === 'string' ? document.getElementById(id) : id; - - if (this.text_area) { - if (!this.spell_container && this.decoration) { - var table = document.createElement('table'), - tbody = document.createElement('tbody'), - tr = document.createElement('tr'), - spell_container = document.createElement('td'), - r_width = this.isDefined(this.force_width) ? this.force_width : this.text_area.offsetWidth, - r_height = this.isDefined(this.force_height) ? this.force_height : 16; - - tr.appendChild(spell_container); - tbody.appendChild(tr); - $(table).append(tbody).insertBefore(this.text_area).width('100%').height(r_height); - $(spell_container).height(r_height).width(r_width).css('text-align', 'right'); - - this.spell_container = spell_container; - } - - this.checkSpellingState(); - } - else if (this.report_ta_not_found) - alert('Text area not found'); -}; - -////// -// API Functions (the ones that you can call) -///// -this.setSpellContainer = function(id) -{ - this.spell_container = typeof id === 'string' ? document.getElementById(id) : id; -}; - -this.setLanguages = function(lang_dict) -{ - this.lang_to_word = lang_dict; - this.langlist_codes = this.array_keys(lang_dict); -}; - -this.setCurrentLanguage = function(lan_code) -{ - GOOGIE_CUR_LANG = lan_code; - - //Set cookie - var now = new Date(); - now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); - rcmail.set_cookie('language', lan_code, now); -}; - -this.setForceWidthHeight = function(width, height) -{ - // Set to null if you want to use one of them - this.force_width = width; - this.force_height = height; -}; - -this.setDecoration = function(bool) -{ - this.decoration = bool; -}; - -this.dontUseCloseButtons = function() -{ - this.use_close_btn = false; -}; - -this.appendNewMenuItem = function(name, call_back_fn, checker) -{ - this.extra_menu_items.push([name, call_back_fn, checker]); -}; - -this.appendCustomMenuBuilder = function(eval_fn, builder) -{ - this.custom_menu_builder.push([eval_fn, builder]); -}; - -this.setFocus = function() -{ - try { - this.focus_link_b.focus(); - this.focus_link_t.focus(); - return true; - } - catch(e) { - return false; - } -}; - - -////// -// Set functions (internal) -///// -this.setStateChanged = function(current_state) -{ - this.state = current_state; - if (this.spelling_state_observer != null && this.report_state_change) - this.spelling_state_observer(current_state, this); -}; - -this.setReportStateChange = function(bool) -{ - this.report_state_change = bool; -}; - - -////// -// Request functions -///// -this.getUrl = function() -{ - return this.server_url + GOOGIE_CUR_LANG; -}; - -this.escapeSpecial = function(val) -{ - return val ? val.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") : ''; -}; - -this.createXMLReq = function (text) -{ - return '<?xml version="1.0" encoding="utf-8" ?>' - + '<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">' - + '<text>' + text + '</text></spellrequest>'; -}; - -this.spellCheck = function(ignore) -{ - this.prepare(ignore); - - var req_text = this.escapeSpecial(this.orginal_text), - ref = this; - - $.ajax({ type: 'POST', url: this.getUrl(), data: this.createXMLReq(req_text), dataType: 'text', - error: function(o) { - if (ref.custom_ajax_error) - ref.custom_ajax_error(ref); - else - alert('An error was encountered on the server. Please try again later.'); - if (ref.main_controller) { - $(ref.spell_span).remove(); - ref.removeIndicator(); - } - ref.checkSpellingState(); - }, - success: function(data) { - ref.processData(data); - if (!ref.results.length) { - if (!ref.custom_no_spelling_error) - ref.flashNoSpellingErrorState(); - else - ref.custom_no_spelling_error(ref); - } - ref.removeIndicator(); - } - }); -}; - -this.learnWord = function(word, id) -{ - word = this.escapeSpecial(word.innerHTML); - - var ref = this, - req_text = '<?xml version="1.0" encoding="utf-8" ?><learnword><text>' + word + '</text></learnword>'; - - $.ajax({ type: 'POST', url: this.getUrl(), data: req_text, dataType: 'text', - error: function(o) { - if (ref.custom_ajax_error) - ref.custom_ajax_error(ref); - else - alert('An error was encountered on the server. Please try again later.'); - }, - success: function(data) { - } - }); -}; - - -////// -// Spell checking functions -///// -this.prepare = function(ignore, no_indicator) -{ - this.cnt_errors_fixed = 0; - this.cnt_errors = 0; - this.setStateChanged('checking_spell'); - - if (!no_indicator && this.main_controller) - this.appendIndicator(this.spell_span); - - this.error_links = []; - this.ta_scroll_top = this.text_area.scrollTop; - this.ignore = ignore; - this.hideLangWindow(); - - if ($(this.text_area).val() == '' || ignore) { - if (!this.custom_no_spelling_error) - this.flashNoSpellingErrorState(); - else - this.custom_no_spelling_error(this); - this.removeIndicator(); - return; - } - - this.createEditLayer(this.text_area.offsetWidth, this.text_area.offsetHeight); - this.createErrorWindow(); - $('body').append(this.error_window); - - try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } - catch (e) { } - - if (this.main_controller) - $(this.spell_span).unbind('click'); - - this.orginal_text = $(this.text_area).val(); -}; - -this.parseResult = function(r_text) -{ - // Returns an array: result[item] -> ['attrs'], ['suggestions'] - var re_split_attr_c = /\w+="(\d+|true)"/g, - re_split_text = /\t/g, - matched_c = r_text.match(/<c[^>]*>[^<]*<\/c>/g), - results = []; - - if (matched_c == null) - return results; - - for (var i=0, len=matched_c.length; i < len; i++) { - var item = []; - this.errorFound(); - - // Get attributes - item['attrs'] = []; - var c_attr, val, - split_c = matched_c[i].match(re_split_attr_c); - for (var j=0; j < split_c.length; j++) { - c_attr = split_c[j].split(/=/); - val = c_attr[1].replace(/"/g, ''); - item['attrs'][c_attr[0]] = val != 'true' ? parseInt(val) : val; - } - - // Get suggestions - item['suggestions'] = []; - var only_text = matched_c[i].replace(/<[^>]*>/g, ''), - split_t = only_text.split(re_split_text); - for (var k=0; k < split_t.length; k++) { - if(split_t[k] != '') - item['suggestions'].push(split_t[k]); - } - results.push(item); - } - - return results; -}; - -this.processData = function(data) -{ - this.results = this.parseResult(data); - if (this.results.length) { - this.showErrorsInIframe(); - this.resumeEditingState(); - } -}; - -////// -// Error menu functions -///// -this.createErrorWindow = function() -{ - this.error_window = document.createElement('div'); - $(this.error_window).addClass('googie_window popupmenu').attr('googie_action_btn', '1'); -}; - -this.isErrorWindowShown = function() -{ - return $(this.error_window).is(':visible'); -}; - -this.hideErrorWindow = function() -{ - $(this.error_window).hide(); - $(this.error_window_iframe).hide(); -}; - -this.updateOrginalText = function(offset, old_value, new_value, id) -{ - var part_1 = this.orginal_text.substring(0, offset), - part_2 = this.orginal_text.substring(offset+old_value.length), - add_2_offset = new_value.length - old_value.length; - - this.orginal_text = part_1 + new_value + part_2; - $(this.text_area).val(this.orginal_text); - for (var j=0, len=this.results.length; j<len; j++) { - // Don't edit the offset of the current item - if (j != id && j > id) - this.results[j]['attrs']['o'] += add_2_offset; - } -}; - -this.saveOldValue = function(elm, old_value) { - elm.is_changed = true; - elm.old_value = old_value; -}; - -this.createListSeparator = function() -{ - var td = document.createElement('td'), - tr = document.createElement('tr'); - - $(td).html(' ').attr('googie_action_btn', '1') - .css({'cursor': 'default', 'font-size': '3px', 'border-top': '1px solid #ccc', 'padding-top': '3px'}); - tr.appendChild(td); - - return tr; -}; - -this.correctError = function(id, elm, l_elm, rm_pre_space) -{ - var old_value = elm.innerHTML, - new_value = l_elm.nodeType == 3 ? l_elm.nodeValue : l_elm.innerHTML, - offset = this.results[id]['attrs']['o']; - - if (rm_pre_space) { - var pre_length = elm.previousSibling.innerHTML; - elm.previousSibling.innerHTML = pre_length.slice(0, pre_length.length-1); - old_value = " " + old_value; - offset--; - } - - this.hideErrorWindow(); - this.updateOrginalText(offset, old_value, new_value, id); - - $(elm).html(new_value).css('color', 'green').attr('is_corrected', true); - - this.results[id]['attrs']['l'] = new_value.length; - - if (!this.isDefined(elm.old_value)) - this.saveOldValue(elm, old_value); - - this.errorFixed(); -}; - -this.ignoreError = function(elm, id) -{ - // @TODO: ignore all same words - $(elm).removeAttr('class').css('color', '').unbind(); - this.hideErrorWindow(); -}; - -this.showErrorWindow = function(elm, id) -{ - if (this.show_menu_observer) - this.show_menu_observer(this); - - var ref = this, - pos = $(elm).offset(), - table = document.createElement('table'), - list = document.createElement('tbody'); - - $(this.error_window).html(''); - $(table).addClass('googie_list').attr('googie_action_btn', '1'); - - // Check if we should use custom menu builder, if not we use the default - var changed = false; - for (var k=0; k<this.custom_menu_builder.length; k++) { - var eb = this.custom_menu_builder[k]; - if (eb[0](this.results[id])) { - changed = eb[1](this, list, elm); - break; - } - } - - if (!changed) { - // Build up the result list - var suggestions = this.results[id]['suggestions'], - offset = this.results[id]['attrs']['o'], - len = this.results[id]['attrs']['l'], - row, item, dummy; - - // [Add to dictionary] button - if (this.has_dictionary && !$(elm).attr('is_corrected')) { - row = document.createElement('tr'), - item = document.createElement('td'), - dummy = document.createElement('span'); - - $(dummy).text(this.lang_learn_word); - $(item).attr('googie_action_btn', '1').css('cursor', 'default') - .mouseover(ref.item_onmouseover) - .mouseout(ref.item_onmouseout) - .click(function(e) { - ref.learnWord(elm, id); - ref.ignoreError(elm, id); - }); - - item.appendChild(dummy); - row.appendChild(item); - list.appendChild(row); - } -/* - if (suggestions.length == 0) { - row = document.createElement('tr'), - item = document.createElement('td'), - dummy = document.createElement('span'); - - $(dummy).text(this.lang_no_suggestions); - $(item).attr('googie_action_btn', '1').css('cursor', 'default'); - - item.appendChild(dummy); - row.appendChild(item); - list.appendChild(row); - } -*/ - for (var i=0, len=suggestions.length; i < len; i++) { - row = document.createElement('tr'), - item = document.createElement('td'), - dummy = document.createElement('span'); - - $(dummy).html(suggestions[i]); - - $(item).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout) - .click(function(e) { ref.correctError(id, elm, e.target.firstChild) }); - - item.appendChild(dummy); - row.appendChild(item); - list.appendChild(row); - } - - // The element is changed, append the revert - if (elm.is_changed && elm.innerHTML != elm.old_value) { - var old_value = elm.old_value, - revert_row = document.createElement('tr'), - revert = document.createElement('td'), - rev_span = document.createElement('span'); - - $(rev_span).addClass('googie_list_revert').html(this.lang_revert + ' ' + old_value); - - $(revert).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout) - .click(function(e) { - ref.updateOrginalText(offset, elm.innerHTML, old_value, id); - $(elm).removeAttr('is_corrected').css('color', '#b91414').html(old_value); - ref.hideErrorWindow(); - }); - - revert.appendChild(rev_span); - revert_row.appendChild(revert); - list.appendChild(revert_row); - } - - // Append the edit box - var edit_row = document.createElement('tr'), - edit = document.createElement('td'), - edit_input = document.createElement('input'), - ok_pic = document.createElement('img'), - edit_form = document.createElement('form'); - - var onsub = function () { - if (edit_input.value != '') { - if (!ref.isDefined(elm.old_value)) - ref.saveOldValue(elm, elm.innerHTML); - - ref.updateOrginalText(offset, elm.innerHTML, edit_input.value, id); - $(elm).attr('is_corrected', true).css('color', 'green').html(edit_input.value); - ref.hideErrorWindow(); - } - return false; - }; - - $(edit_input).width(120).css({'margin': 0, 'padding': 0}); - $(edit_input).val(elm.innerHTML).attr('googie_action_btn', '1'); - $(edit).css('cursor', 'default').attr('googie_action_btn', '1'); - - $(ok_pic).attr('src', this.img_dir + 'ok.gif') - .width(32).height(16) - .css({'cursor': 'pointer', 'margin-left': '2px', 'margin-right': '2px'}) - .click(onsub); - - $(edit_form).attr('googie_action_btn', '1') - .css({'margin': 0, 'padding': 0, 'cursor': 'default', 'white-space': 'nowrap'}) - .submit(onsub); - - edit_form.appendChild(edit_input); - edit_form.appendChild(ok_pic); - edit.appendChild(edit_form); - edit_row.appendChild(edit); - list.appendChild(edit_row); - - // Append extra menu items - if (this.extra_menu_items.length > 0) - list.appendChild(this.createListSeparator()); - - var loop = function(i) { - if (i < ref.extra_menu_items.length) { - var e_elm = ref.extra_menu_items[i]; - - if (!e_elm[2] || e_elm[2](elm, ref)) { - var e_row = document.createElement('tr'), - e_col = document.createElement('td'); - - $(e_col).html(e_elm[0]) - .mouseover(ref.item_onmouseover) - .mouseout(ref.item_onmouseout) - .click(function() { return e_elm[1](elm, ref) }); - - e_row.appendChild(e_col); - list.appendChild(e_row); - } - loop(i+1); - } - }; - - loop(0); - loop = null; - - //Close button - if (this.use_close_btn) { - list.appendChild(this.createCloseButton(this.hideErrorWindow)); - } - } - - table.appendChild(list); - this.error_window.appendChild(table); - - // calculate and set position - var height = $(this.error_window).height(), - width = $(this.error_window).width(), - pageheight = $(document).height(), - pagewidth = $(document).width(), - top = pos.top + height + 20 < pageheight ? pos.top + 20 : pos.top - height, - left = pos.left + width < pagewidth ? pos.left : pos.left - width; - - $(this.error_window).css({'top': top+'px', 'left': left+'px'}).show(); - - // Dummy for IE - dropdown bug fix - if (document.all && !window.opera) { - if (!this.error_window_iframe) { - var iframe = $('<iframe>').css({'position': 'absolute', 'z-index': -1}); - $('body').append(iframe); - this.error_window_iframe = iframe; - } - - $(this.error_window_iframe) - .css({'top': this.error_window.offsetTop, 'left': this.error_window.offsetLeft, - 'width': this.error_window.offsetWidth, 'height': this.error_window.offsetHeight}) - .show(); - } -}; - - -////// -// Edit layer (the layer where the suggestions are stored) -////// -this.createEditLayer = function(width, height) -{ - this.edit_layer = document.createElement('div'); - $(this.edit_layer).addClass('googie_edit_layer').attr('id', 'googie_edit_layer') - .width('auto').height(height); - - if (this.text_area.nodeName.toLowerCase() != 'input' || $(this.text_area).val() == '') { - $(this.edit_layer).css('overflow', 'auto').height(height-4); - } else { - $(this.edit_layer).css('overflow', 'hidden'); - } - - var ref = this; - - if (this.edit_layer_dbl_click) { - $(this.edit_layer).dblclick(function(e) { - if (e.target.className != 'googie_link' && !ref.isErrorWindowShown()) { - ref.resumeEditing(); - var fn1 = function() { - $(ref.text_area).focus(); - fn1 = null; - }; - window.setTimeout(fn1, 10); - } - return false; - }); - } -}; - -this.resumeEditing = function() -{ - this.setStateChanged('ready'); - - if (this.edit_layer) - this.el_scroll_top = this.edit_layer.scrollTop; - - this.hideErrorWindow(); - - if (this.main_controller) - $(this.spell_span).removeClass().addClass('googie_no_style'); - - if (!this.ignore) { - if (this.use_focus) { - $(this.focus_link_t).remove(); - $(this.focus_link_b).remove(); - } - - $(this.edit_layer).remove(); - $(this.text_area).show(); - - if (this.el_scroll_top != undefined) - this.text_area.scrollTop = this.el_scroll_top; - } - this.checkSpellingState(false); -}; - -this.createErrorLink = function(text, id) -{ - var elm = document.createElement('span'), - ref = this, - d = function (e) { - ref.showErrorWindow(elm, id); - d = null; - return false; - }; - - $(elm).html(text).addClass('googie_link').click(d).removeAttr('is_corrected') - .attr({'googie_action_btn' : '1', 'g_id' : id}); - - return elm; -}; - -this.createPart = function(txt_part) -{ - if (txt_part == " ") - return document.createTextNode(" "); - - txt_part = this.escapeSpecial(txt_part); - txt_part = txt_part.replace(/\n/g, "<br>"); - txt_part = txt_part.replace(/ /g, " "); - txt_part = txt_part.replace(/^ /g, " "); - txt_part = txt_part.replace(/ $/g, " "); - - var span = document.createElement('span'); - $(span).html(txt_part); - return span; -}; - -this.showErrorsInIframe = function() -{ - var output = document.createElement('div'), - pointer = 0, - results = this.results; - - if (results.length > 0) { - for (var i=0, length=results.length; i < length; i++) { - var offset = results[i]['attrs']['o'], - len = results[i]['attrs']['l'], - part_1_text = this.orginal_text.substring(pointer, offset), - part_1 = this.createPart(part_1_text); - - output.appendChild(part_1); - pointer += offset - pointer; - - // If the last child was an error, then insert some space - var err_link = this.createErrorLink(this.orginal_text.substr(offset, len), i); - this.error_links.push(err_link); - output.appendChild(err_link); - pointer += len; - } - - // Insert the rest of the orginal text - var part_2_text = this.orginal_text.substr(pointer, this.orginal_text.length), - part_2 = this.createPart(part_2_text); - - output.appendChild(part_2); - } - else - output.innerHTML = this.orginal_text; - - $(output).css('text-align', 'left'); - - var me = this; - if (this.custom_item_evaulator) - $.map(this.error_links, function(elm){me.custom_item_evaulator(me, elm)}); - - $(this.edit_layer).append(output); - - // Hide text area and show edit layer - $(this.text_area).hide(); - $(this.edit_layer).insertBefore(this.text_area); - - if (this.use_focus) { - this.focus_link_t = this.createFocusLink('focus_t'); - this.focus_link_b = this.createFocusLink('focus_b'); - - $(this.focus_link_t).insertBefore(this.edit_layer); - $(this.focus_link_b).insertAfter(this.edit_layer); - } - -// this.edit_layer.scrollTop = this.ta_scroll_top; -}; - - -////// -// Choose language menu -////// -this.createLangWindow = function() -{ - this.language_window = document.createElement('div'); - $(this.language_window).addClass('googie_window popupmenu') - .width(100).attr('googie_action_btn', '1'); - - // Build up the result list - var table = document.createElement('table'), - list = document.createElement('tbody'), - ref = this, - row, item, span; - - $(table).addClass('googie_list').width('100%'); - this.lang_elms = []; - - for (i=0; i < this.langlist_codes.length; i++) { - row = document.createElement('tr'); - item = document.createElement('td'); - span = document.createElement('span'); - - $(span).text(this.lang_to_word[this.langlist_codes[i]]); - this.lang_elms.push(item); - - $(item).attr('googieId', this.langlist_codes[i]) - .bind('click', function(e) { - ref.deHighlightCurSel(); - ref.setCurrentLanguage($(this).attr('googieId')); - - if (ref.lang_state_observer != null) { - ref.lang_state_observer(); - } - - ref.highlightCurSel(); - ref.hideLangWindow(); - }) - .bind('mouseover', function(e) { - if (this.className != "googie_list_selected") - this.className = "googie_list_onhover"; - }) - .bind('mouseout', function(e) { - if (this.className != "googie_list_selected") - this.className = "googie_list_onout"; - }); - - item.appendChild(span); - row.appendChild(item); - list.appendChild(row); - } - - // Close button - if (this.use_close_btn) { - list.appendChild(this.createCloseButton(function () { ref.hideLangWindow.apply(ref) })); - } - - this.highlightCurSel(); - - table.appendChild(list); - this.language_window.appendChild(table); -}; - -this.isLangWindowShown = function() -{ - return $(this.language_window).is(':visible'); -}; - -this.hideLangWindow = function() -{ - $(this.language_window).hide(); - $(this.switch_lan_pic).removeClass().addClass('googie_lang_3d_on'); -}; - -this.showLangWindow = function(elm) -{ - if (this.show_menu_observer) - this.show_menu_observer(this); - - this.createLangWindow(); - $('body').append(this.language_window); - - var pos = $(elm).offset(), - height = $(elm).height(), - width = $(elm).width(), - h = $(this.language_window).height(), - pageheight = $(document).height(), - left = this.change_lang_pic_placement == 'right' ? - pos.left - 100 + width : pos.left + width, - top = pos.top + h < pageheight ? pos.top + height : pos.top - h - 4; - - $(this.language_window).css({'top' : top+'px','left' : left+'px'}).show(); - - this.highlightCurSel(); -}; - -this.deHighlightCurSel = function() -{ - $(this.lang_cur_elm).removeClass().addClass('googie_list_onout'); -}; - -this.highlightCurSel = function() -{ - if (GOOGIE_CUR_LANG == null) - GOOGIE_CUR_LANG = GOOGIE_DEFAULT_LANG; - for (var i=0; i < this.lang_elms.length; i++) { - if ($(this.lang_elms[i]).attr('googieId') == GOOGIE_CUR_LANG) { - this.lang_elms[i].className = 'googie_list_selected'; - this.lang_cur_elm = this.lang_elms[i]; - } - else { - this.lang_elms[i].className = 'googie_list_onout'; - } - } -}; - -this.createChangeLangPic = function() -{ - var img = $('<img>') - .attr({src: this.img_dir + 'change_lang.gif', 'alt': 'Change language', 'googie_action_btn': '1'}), - switch_lan = document.createElement('span'); - ref = this; - - $(switch_lan).addClass('googie_lang_3d_on') - .append(img) - .bind('click', function(e) { - var elm = this.tagName.toLowerCase() == 'img' ? this.parentNode : this; - if($(elm).hasClass('googie_lang_3d_click')) { - elm.className = 'googie_lang_3d_on'; - ref.hideLangWindow(); - } - else { - elm.className = 'googie_lang_3d_click'; - ref.showLangWindow(elm); - } - }); - - return switch_lan; -}; - -this.createSpellDiv = function() -{ - var span = document.createElement('span'); - - $(span).addClass('googie_check_spelling_link').text(this.lang_chck_spell); - - if (this.show_spell_img) { - $(span).append(' ').append($('<img>').attr('src', this.img_dir + 'spellc.gif')); - } - return span; -}; - - -////// -// State functions -///// -this.flashNoSpellingErrorState = function(on_finish) -{ - this.setStateChanged('no_error_found'); - - var ref = this; - if (this.main_controller) { - var no_spell_errors; - if (on_finish) { - var fn = function() { - on_finish(); - ref.checkSpellingState(); - }; - no_spell_errors = fn; - } - else - no_spell_errors = function () { ref.checkSpellingState() }; - - var rsm = $('<span>').text(this.lang_no_error_found); - - $(this.switch_lan_pic).hide(); - $(this.spell_span).empty().append(rsm) - .removeClass().addClass('googie_check_spelling_ok'); - - window.setTimeout(no_spell_errors, 1000); - } -}; - -this.resumeEditingState = function() -{ - this.setStateChanged('resume_editing'); - - //Change link text to resume - if (this.main_controller) { - var rsm = $('<span>').text(this.lang_rsm_edt); - var ref = this; - - $(this.switch_lan_pic).hide(); - $(this.spell_span).empty().unbind().append(rsm) - .bind('click', function() { ref.resumeEditing() }) - .removeClass().addClass('googie_resume_editing'); - } - - try { this.edit_layer.scrollTop = this.ta_scroll_top; } - catch (e) {}; -}; - -this.checkSpellingState = function(fire) -{ - if (fire) - this.setStateChanged('ready'); - - if (this.show_change_lang_pic) - this.switch_lan_pic = this.createChangeLangPic(); - else - this.switch_lan_pic = document.createElement('span'); - - var span_chck = this.createSpellDiv(), - ref = this; - - if (this.custom_spellcheck_starter) - $(span_chck).bind('click', function(e) { ref.custom_spellcheck_starter() }); - else { - $(span_chck).bind('click', function(e) { ref.spellCheck() }); - } - - if (this.main_controller) { - if (this.change_lang_pic_placement == 'left') { - $(this.spell_container).empty().append(this.switch_lan_pic).append(' ').append(span_chck); - } else { - $(this.spell_container).empty().append(span_chck).append(' ').append(this.switch_lan_pic); - } - } - - this.spell_span = span_chck; -}; - - -////// -// Misc. functions -///// -this.isDefined = function(o) -{ - return (o !== undefined && o !== null) -}; - -this.errorFixed = function() -{ - this.cnt_errors_fixed++; - if (this.all_errors_fixed_observer) - if (this.cnt_errors_fixed == this.cnt_errors) { - this.hideErrorWindow(); - this.all_errors_fixed_observer(); - } -}; - -this.errorFound = function() -{ - this.cnt_errors++; -}; - -this.createCloseButton = function(c_fn) -{ - return this.createButton(this.lang_close, 'googie_list_close', c_fn); -}; - -this.createButton = function(name, css_class, c_fn) -{ - var btn_row = document.createElement('tr'), - btn = document.createElement('td'), - spn_btn; - - if (css_class) { - spn_btn = document.createElement('span'); - $(spn_btn).addClass(css_class).html(name); - } else { - spn_btn = document.createTextNode(name); - } - - $(btn).bind('click', c_fn) - .bind('mouseover', this.item_onmouseover) - .bind('mouseout', this.item_onmouseout); - - btn.appendChild(spn_btn); - btn_row.appendChild(btn); - - return btn_row; -}; - -this.removeIndicator = function(elm) -{ - //$(this.indicator).remove(); - // roundcube mod. - if (window.rcmail) - rcmail.set_busy(false, null, this.rc_msg_id); -}; - -this.appendIndicator = function(elm) -{ - // modified by roundcube - if (window.rcmail) - this.rc_msg_id = rcmail.set_busy(true, 'checking'); -/* - this.indicator = document.createElement('img'); - $(this.indicator).attr('src', this.img_dir + 'indicator.gif') - .css({'margin-right': '5px', 'text-decoration': 'none'}).width(16).height(16); - - if (elm) - $(this.indicator).insertBefore(elm); - else - $('body').append(this.indicator); -*/ -} - -this.createFocusLink = function(name) -{ - var link = document.createElement('a'); - $(link).attr({'href': 'javascript:;', 'name': name}); - return link; -}; - -this.item_onmouseover = function(e) -{ - if (this.className != 'googie_list_revert' && this.className != 'googie_list_close') - this.className = 'googie_list_onhover'; - else - this.parentNode.className = 'googie_list_onhover'; -}; - -this.item_onmouseout = function(e) -{ - if (this.className != 'googie_list_revert' && this.className != 'googie_list_close') - this.className = 'googie_list_onout'; - else - this.parentNode.className = 'googie_list_onout'; -}; - - -}; +var GOOGIE_CUR_LANG,GOOGIE_DEFAULT_LANG="en";function GoogieSpell(c,a,e){var b=this,d=rcmail.get_cookie("language");GOOGIE_CUR_LANG=d!=null?d:GOOGIE_DEFAULT_LANG;this.array_keys=function(f){var h=[];for(var g in f){h.push([g])}return h};this.img_dir=c;this.server_url=a;this.org_lang_to_word={da:"Dansk",de:"Deutsch",en:"English",es:"Español",fr:"Français",it:"Italiano",nl:"Nederlands",pl:"Polski",pt:"Português",ru:"РуÑÑкий",fi:"Suomi",sv:"Svenska"};this.lang_to_word=this.org_lang_to_word;this.langlist_codes=this.array_keys(this.lang_to_word);this.show_change_lang_pic=true;this.change_lang_pic_placement="right";this.report_state_change=true;this.ta_scroll_top=0;this.el_scroll_top=0;this.lang_chck_spell="Check spelling";this.lang_revert="Revert to";this.lang_close="Close";this.lang_rsm_edt="Resume editing";this.lang_no_error_found="No spelling errors found";this.lang_no_suggestions="No suggestions";this.lang_learn_word="Add to dictionary";this.show_spell_img=false;this.decoration=true;this.use_close_btn=false;this.edit_layer_dbl_click=true;this.report_ta_not_found=true;this.custom_ajax_error=null;this.custom_no_spelling_error=null;this.custom_menu_builder=[];this.custom_item_evaulator=null;this.extra_menu_items=[];this.custom_spellcheck_starter=null;this.main_controller=true;this.has_dictionary=e;this.lang_state_observer=null;this.spelling_state_observer=null;this.show_menu_observer=null;this.all_errors_fixed_observer=null;this.use_focus=false;this.focus_link_t=null;this.focus_link_b=null;this.cnt_errors=0;this.cnt_errors_fixed=0;$(document).bind("click",function(g){var f=$(g.target);if(f.attr("googie_action_btn")!="1"&&b.isLangWindowShown()){b.hideLangWindow()}if(f.attr("googie_action_btn")!="1"&&b.isErrorWindowShown()){b.hideErrorWindow()}});this.decorateTextarea=function(m){this.text_area=typeof m==="string"?document.getElementById(m):m;if(this.text_area){if(!this.spell_container&&this.decoration){var j=document.createElement("table"),g=document.createElement("tbody"),l=document.createElement("tr"),k=document.createElement("td"),f=this.isDefined(this.force_width)?this.force_width:this.text_area.offsetWidth,h=this.isDefined(this.force_height)?this.force_height:16;l.appendChild(k);g.appendChild(l);$(j).append(g).insertBefore(this.text_area).width("100%").height(h);$(k).height(h).width(f).css("text-align","right");this.spell_container=k}this.checkSpellingState()}else{if(this.report_ta_not_found){alert("Text area not found")}}};this.setSpellContainer=function(f){this.spell_container=typeof f==="string"?document.getElementById(f):f};this.setLanguages=function(f){this.lang_to_word=f;this.langlist_codes=this.array_keys(f)};this.setCurrentLanguage=function(g){GOOGIE_CUR_LANG=g;var f=new Date();f.setTime(f.getTime()+365*24*60*60*1000);rcmail.set_cookie("language",g,f)};this.setForceWidthHeight=function(g,f){this.force_width=g;this.force_height=f};this.setDecoration=function(f){this.decoration=f};this.dontUseCloseButtons=function(){this.use_close_btn=false};this.appendNewMenuItem=function(g,h,f){this.extra_menu_items.push([g,h,f])};this.appendCustomMenuBuilder=function(g,f){this.custom_menu_builder.push([g,f])};this.setFocus=function(){try{this.focus_link_b.focus();this.focus_link_t.focus();return true}catch(f){return false}};this.setStateChanged=function(f){this.state=f;if(this.spelling_state_observer!=null&&this.report_state_change){this.spelling_state_observer(f,this)}};this.setReportStateChange=function(f){this.report_state_change=f};this.getUrl=function(){return this.server_url+GOOGIE_CUR_LANG};this.escapeSpecial=function(f){return f?f.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"):""};this.createXMLReq=function(f){return'<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>'+f+"</text></spellrequest>"};this.spellCheck=function(h){this.prepare(h);var g=this.escapeSpecial(this.orginal_text),f=this;$.ajax({type:"POST",url:this.getUrl(),data:this.createXMLReq(g),dataType:"text",error:function(j){if(f.custom_ajax_error){f.custom_ajax_error(f)}else{alert("An error was encountered on the server. Please try again later.")}if(f.main_controller){$(f.spell_span).remove();f.removeIndicator()}f.checkSpellingState()},success:function(j){f.processData(j);if(!f.results.length){if(!f.custom_no_spelling_error){f.flashNoSpellingErrorState()}else{f.custom_no_spelling_error(f)}}f.removeIndicator()}})};this.learnWord=function(h,j){h=this.escapeSpecial(h.innerHTML);var g=this,f='<?xml version="1.0" encoding="utf-8" ?><learnword><text>'+h+"</text></learnword>";$.ajax({type:"POST",url:this.getUrl(),data:f,dataType:"text",error:function(k){if(g.custom_ajax_error){g.custom_ajax_error(g)}else{alert("An error was encountered on the server. Please try again later.")}},success:function(k){}})};this.prepare=function(h,g){this.cnt_errors_fixed=0;this.cnt_errors=0;this.setStateChanged("checking_spell");if(!g&&this.main_controller){this.appendIndicator(this.spell_span)}this.error_links=[];this.ta_scroll_top=this.text_area.scrollTop;this.ignore=h;this.hideLangWindow();if($(this.text_area).val()==""||h){if(!this.custom_no_spelling_error){this.flashNoSpellingErrorState()}else{this.custom_no_spelling_error(this)}this.removeIndicator();return}this.createEditLayer(this.text_area.offsetWidth,this.text_area.offsetHeight);this.createErrorWindow();$("body").append(this.error_window);try{netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead")}catch(f){}if(this.main_controller){$(this.spell_span).unbind("click")}this.orginal_text=$(this.text_area).val()};this.parseResult=function(s){var l=/\w+="(\d+|true)"/g,o=/\t/g,f=s.match(/<c[^>]*>[^<]*<\/c>/g),p=[];if(f==null){return p}for(var q=0,r=f.length;q<r;q++){var w=[];this.errorFound();w.attrs=[];var u,h,v=f[q].match(l);for(var n=0;n<v.length;n++){u=v[n].split(/=/);h=u[1].replace(/"/g,"");w.attrs[u[0]]=h!="true"?parseInt(h):h}w.suggestions=[];var t=f[q].replace(/<[^>]*>/g,""),g=t.split(o);for(var m=0;m<g.length;m++){if(g[m]!=""){w.suggestions.push(g[m])}}p.push(w)}return p};this.processData=function(f){this.results=this.parseResult(f);if(this.results.length){this.showErrorsInIframe();this.resumeEditingState()}};this.createErrorWindow=function(){this.error_window=document.createElement("div");$(this.error_window).addClass("googie_window popupmenu").attr("googie_action_btn","1")};this.isErrorWindowShown=function(){return $(this.error_window).is(":visible")};this.hideErrorWindow=function(){$(this.error_window).hide();$(this.error_window_iframe).hide()};this.updateOrginalText=function(k,n,p,f){var h=this.orginal_text.substring(0,k),g=this.orginal_text.substring(k+n.length),o=p.length-n.length;this.orginal_text=h+p+g;$(this.text_area).val(this.orginal_text);for(var l=0,m=this.results.length;l<m;l++){if(l!=f&&l>f){this.results[l]["attrs"]["o"]+=o}}};this.saveOldValue=function(g,f){g.is_changed=true;g.old_value=f};this.createListSeparator=function(){var g=document.createElement("td"),f=document.createElement("tr");$(g).html(" ").attr("googie_action_btn","1").css({cursor:"default","font-size":"3px","border-top":"1px solid #ccc","padding-top":"3px"});f.appendChild(g);return f};this.correctError=function(n,m,l,f){var g=m.innerHTML,h=l.nodeType==3?l.nodeValue:l.innerHTML,k=this.results[n]["attrs"]["o"];if(f){var j=m.previousSibling.innerHTML;m.previousSibling.innerHTML=j.slice(0,j.length-1);g=" "+g;k--}this.hideErrorWindow();this.updateOrginalText(k,g,h,n);$(m).html(h).css("color","green").attr("is_corrected",true);this.results[n]["attrs"]["l"]=h.length;if(!this.isDefined(m.old_value)){this.saveOldValue(m,g)}this.errorFixed()};this.ignoreError=function(g,f){$(g).removeAttr("class").css("color","").unbind();this.hideErrorWindow()};this.showErrorWindow=function(u,B){if(this.show_menu_observer){this.show_menu_observer(this)}var o=this,p=$(u).offset(),I=document.createElement("table"),J=document.createElement("tbody");$(this.error_window).html("");$(I).addClass("googie_list").attr("googie_action_btn","1");var r=false;for(var F=0;F<this.custom_menu_builder.length;F++){var q=this.custom_menu_builder[F];if(q[0](this.results[B])){r=q[1](this,J,u);break}}if(!r){var z=this.results[B]["suggestions"],n=this.results[B]["attrs"]["o"],H=this.results[B]["attrs"]["l"],t,K,O;if(this.has_dictionary&&!$(u).attr("is_corrected")){t=document.createElement("tr"),K=document.createElement("td"),O=document.createElement("span");$(O).text(this.lang_learn_word);$(K).attr("googie_action_btn","1").css("cursor","default").mouseover(o.item_onmouseover).mouseout(o.item_onmouseout).click(function(k){o.learnWord(u,B);o.ignoreError(u,B)});K.appendChild(O);t.appendChild(K);J.appendChild(t)}for(var G=0,H=z.length;G<H;G++){t=document.createElement("tr"),K=document.createElement("td"),O=document.createElement("span");$(O).html(z[G]);$(K).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout).click(function(k){o.correctError(B,u,k.target.firstChild)});K.appendChild(O);t.appendChild(K);J.appendChild(t)}if(u.is_changed&&u.innerHTML!=u.old_value){var g=u.old_value,j=document.createElement("tr"),f=document.createElement("td"),s=document.createElement("span");$(s).addClass("googie_list_revert").html(this.lang_revert+" "+g);$(f).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout).click(function(k){o.updateOrginalText(n,u.innerHTML,g,B);$(u).removeAttr("is_corrected").css("color","#b91414").html(g);o.hideErrorWindow()});f.appendChild(s);j.appendChild(f);J.appendChild(j)}var M=document.createElement("tr"),C=document.createElement("td"),N=document.createElement("input"),w=document.createElement("img"),h=document.createElement("form");var m=function(){if(N.value!=""){if(!o.isDefined(u.old_value)){o.saveOldValue(u,u.innerHTML)}o.updateOrginalText(n,u.innerHTML,N.value,B);$(u).attr("is_corrected",true).css("color","green").html(N.value);o.hideErrorWindow()}return false};$(N).width(120).css({margin:0,padding:0});$(N).val(u.innerHTML).attr("googie_action_btn","1");$(C).css("cursor","default").attr("googie_action_btn","1");$(w).attr("src",this.img_dir+"ok.gif").width(32).height(16).css({cursor:"pointer","margin-left":"2px","margin-right":"2px"}).click(m);$(h).attr("googie_action_btn","1").css({margin:0,padding:0,cursor:"default","white-space":"nowrap"}).submit(m);h.appendChild(N);h.appendChild(w);C.appendChild(h);M.appendChild(C);J.appendChild(M);if(this.extra_menu_items.length>0){J.appendChild(this.createListSeparator())}var L=function(Q){if(Q<o.extra_menu_items.length){var P=o.extra_menu_items[Q];if(!P[2]||P[2](u,o)){var k=document.createElement("tr"),R=document.createElement("td");$(R).html(P[0]).mouseover(o.item_onmouseover).mouseout(o.item_onmouseout).click(function(){return P[1](u,o)});k.appendChild(R);J.appendChild(k)}L(Q+1)}};L(0);L=null;if(this.use_close_btn){J.appendChild(this.createCloseButton(this.hideErrorWindow))}}I.appendChild(J);this.error_window.appendChild(I);var A=$(this.error_window).height(),E=$(this.error_window).width(),x=$(document).height(),D=$(document).width(),y=p.top+A+20<x?p.top+20:p.top-A,l=p.left+E<D?p.left:p.left-E;$(this.error_window).css({top:y+"px",left:l+"px"}).show();if($.browser.msie){if(!this.error_window_iframe){var v=$("<iframe>").css({position:"absolute","z-index":-1});$("body").append(v);this.error_window_iframe=v}$(this.error_window_iframe).css({top:this.error_window.offsetTop,left:this.error_window.offsetLeft,width:this.error_window.offsetWidth,height:this.error_window.offsetHeight}).show()}};this.createEditLayer=function(g,f){this.edit_layer=document.createElement("div");$(this.edit_layer).addClass("googie_edit_layer").attr("id","googie_edit_layer").width("auto").height(f);if(this.text_area.nodeName.toLowerCase()!="input"||$(this.text_area).val()==""){$(this.edit_layer).css("overflow","auto").height(f-4)}else{$(this.edit_layer).css("overflow","hidden")}var h=this;if(this.edit_layer_dbl_click){$(this.edit_layer).dblclick(function(k){if(k.target.className!="googie_link"&&!h.isErrorWindowShown()){h.resumeEditing();var j=function(){$(h.text_area).focus();j=null};window.setTimeout(j,10)}return false})}};this.resumeEditing=function(){this.setStateChanged("ready");if(this.edit_layer){this.el_scroll_top=this.edit_layer.scrollTop}this.hideErrorWindow();if(this.main_controller){$(this.spell_span).removeClass().addClass("googie_no_style")}if(!this.ignore){if(this.use_focus){$(this.focus_link_t).remove();$(this.focus_link_b).remove()}$(this.edit_layer).remove();$(this.text_area).show();if(this.el_scroll_top!=undefined){this.text_area.scrollTop=this.el_scroll_top}}this.checkSpellingState(false)};this.createErrorLink=function(h,k){var j=document.createElement("span"),f=this,g=function(l){f.showErrorWindow(j,k);g=null;return false};$(j).html(h).addClass("googie_link").click(g).removeAttr("is_corrected").attr({googie_action_btn:"1",g_id:k});return j};this.createPart=function(g){if(g==" "){return document.createTextNode(" ")}g=this.escapeSpecial(g);g=g.replace(/\n/g,"<br>");g=g.replace(/ /g," ");g=g.replace(/^ /g," ");g=g.replace(/ $/g," ");var f=document.createElement("span");$(f).html(g);return f};this.showErrorsInIframe=function(){var m=document.createElement("div"),f=0,o=this.results;if(o.length>0){for(var p=0,k=o.length;p<k;p++){var n=o[p]["attrs"]["o"],r=o[p]["attrs"]["l"],j=this.orginal_text.substring(f,n),l=this.createPart(j);m.appendChild(l);f+=n-f;var g=this.createErrorLink(this.orginal_text.substr(n,r),p);this.error_links.push(g);m.appendChild(g);f+=r}var q=this.orginal_text.substr(f,this.orginal_text.length),h=this.createPart(q);m.appendChild(h)}else{m.innerHTML=this.orginal_text}$(m).css("text-align","left");var s=this;if(this.custom_item_evaulator){$.map(this.error_links,function(t){s.custom_item_evaulator(s,t)})}$(this.edit_layer).append(m);$(this.text_area).hide();$(this.edit_layer).insertBefore(this.text_area);if(this.use_focus){this.focus_link_t=this.createFocusLink("focus_t");this.focus_link_b=this.createFocusLink("focus_b");$(this.focus_link_t).insertBefore(this.edit_layer);$(this.focus_link_b).insertAfter(this.edit_layer)}};this.createLangWindow=function(){this.language_window=document.createElement("div");$(this.language_window).addClass("googie_window popupmenu").width(100).attr("googie_action_btn","1");var j=document.createElement("table"),k=document.createElement("tbody"),h=this,l,g,f;$(j).addClass("googie_list").width("100%");this.lang_elms=[];for(i=0;i<this.langlist_codes.length;i++){l=document.createElement("tr");g=document.createElement("td");f=document.createElement("span");$(f).text(this.lang_to_word[this.langlist_codes[i]]);this.lang_elms.push(g);$(g).attr("googieId",this.langlist_codes[i]).bind("click",function(m){h.deHighlightCurSel();h.setCurrentLanguage($(this).attr("googieId"));if(h.lang_state_observer!=null){h.lang_state_observer()}h.highlightCurSel();h.hideLangWindow()}).bind("mouseover",function(m){if(this.className!="googie_list_selected"){this.className="googie_list_onhover"}}).bind("mouseout",function(m){if(this.className!="googie_list_selected"){this.className="googie_list_onout"}});g.appendChild(f);l.appendChild(g);k.appendChild(l)}if(this.use_close_btn){k.appendChild(this.createCloseButton(function(){h.hideLangWindow.apply(h)}))}this.highlightCurSel();j.appendChild(k);this.language_window.appendChild(j)};this.isLangWindowShown=function(){return $(this.language_window).is(":visible")};this.hideLangWindow=function(){$(this.language_window).hide();$(this.switch_lan_pic).removeClass().addClass("googie_lang_3d_on")};this.showLangWindow=function(o){if(this.show_menu_observer){this.show_menu_observer(this)}this.createLangWindow();$("body").append(this.language_window);var n=$(o).offset(),f=$(o).height(),j=$(o).width(),g=$(this.language_window).height(),k=$(document).height(),m=this.change_lang_pic_placement=="right"?n.left-100+j:n.left+j,l=n.top+g<k?n.top+f:n.top-g-4;$(this.language_window).css({top:l+"px",left:m+"px"}).show();this.highlightCurSel()};this.deHighlightCurSel=function(){$(this.lang_cur_elm).removeClass().addClass("googie_list_onout")};this.highlightCurSel=function(){if(GOOGIE_CUR_LANG==null){GOOGIE_CUR_LANG=GOOGIE_DEFAULT_LANG}for(var f=0;f<this.lang_elms.length;f++){if($(this.lang_elms[f]).attr("googieId")==GOOGIE_CUR_LANG){this.lang_elms[f].className="googie_list_selected";this.lang_cur_elm=this.lang_elms[f]}else{this.lang_elms[f].className="googie_list_onout"}}};this.createChangeLangPic=function(){var f=$("<img>").attr({src:this.img_dir+"change_lang.gif",alt:"Change language",googie_action_btn:"1"}),g=document.createElement("span");b=this;$(g).addClass("googie_lang_3d_on").append(f).bind("click",function(h){var j=this.tagName.toLowerCase()=="img"?this.parentNode:this;if($(j).hasClass("googie_lang_3d_click")){j.className="googie_lang_3d_on";b.hideLangWindow()}else{j.className="googie_lang_3d_click";b.showLangWindow(j)}});return g};this.createSpellDiv=function(){var f=document.createElement("span");$(f).addClass("googie_check_spelling_link").text(this.lang_chck_spell);if(this.show_spell_img){$(f).append(" ").append($("<img>").attr("src",this.img_dir+"spellc.gif"))}return f};this.flashNoSpellingErrorState=function(f){this.setStateChanged("no_error_found");var j=this;if(this.main_controller){var k;if(f){var h=function(){f();j.checkSpellingState()};k=h}else{k=function(){j.checkSpellingState()}}var g=$("<span>").text(this.lang_no_error_found);$(this.switch_lan_pic).hide();$(this.spell_span).empty().append(g).removeClass().addClass("googie_check_spelling_ok");window.setTimeout(k,1000)}};this.resumeEditingState=function(){this.setStateChanged("resume_editing");if(this.main_controller){var f=$("<span>").text(this.lang_rsm_edt);var g=this;$(this.switch_lan_pic).hide();$(this.spell_span).empty().unbind().append(f).bind("click",function(){g.resumeEditing()}).removeClass().addClass("googie_resume_editing")}try{this.edit_layer.scrollTop=this.ta_scroll_top}catch(h){}};this.checkSpellingState=function(g){if(g){this.setStateChanged("ready")}if(this.show_change_lang_pic){this.switch_lan_pic=this.createChangeLangPic()}else{this.switch_lan_pic=document.createElement("span")}var f=this.createSpellDiv(),h=this;if(this.custom_spellcheck_starter){$(f).bind("click",function(j){h.custom_spellcheck_starter()})}else{$(f).bind("click",function(j){h.spellCheck()})}if(this.main_controller){if(this.change_lang_pic_placement=="left"){$(this.spell_container).empty().append(this.switch_lan_pic).append(" ").append(f)}else{$(this.spell_container).empty().append(f).append(" ").append(this.switch_lan_pic)}}this.spell_span=f};this.isDefined=function(f){return(f!==undefined&&f!==null)};this.errorFixed=function(){this.cnt_errors_fixed++;if(this.all_errors_fixed_observer){if(this.cnt_errors_fixed==this.cnt_errors){this.hideErrorWindow();this.all_errors_fixed_observer()}}};this.errorFound=function(){this.cnt_errors++};this.createCloseButton=function(f){return this.createButton(this.lang_close,"googie_list_close",f)};this.createButton=function(g,j,l){var k=document.createElement("tr"),h=document.createElement("td"),f;if(j){f=document.createElement("span");$(f).addClass(j).html(g)}else{f=document.createTextNode(g)}$(h).bind("click",l).bind("mouseover",this.item_onmouseover).bind("mouseout",this.item_onmouseout);h.appendChild(f);k.appendChild(h);return k};this.removeIndicator=function(f){if(window.rcmail){rcmail.set_busy(false,null,this.rc_msg_id)}};this.appendIndicator=function(f){if(window.rcmail){this.rc_msg_id=rcmail.set_busy(true,"checking")}};this.createFocusLink=function(f){var g=document.createElement("a");$(g).attr({href:"javascript:;",name:f});return g};this.item_onmouseover=function(f){if(this.className!="googie_list_revert"&&this.className!="googie_list_close"){this.className="googie_list_onhover"}else{this.parentNode.className="googie_list_onhover"}};this.item_onmouseout=function(f){if(this.className!="googie_list_revert"&&this.className!="googie_list_close"){this.className="googie_list_onout"}else{this.parentNode.className="googie_list_onout"}}};
\ No newline at end of file diff --git a/program/js/jquery.min.js b/program/js/jquery.min.js index 83589daa7..5cb76ea03 100644..120000 --- a/program/js/jquery.min.js +++ b/program/js/jquery.min.js @@ -1,2 +1 @@ -/*! jQuery v1.8.3 jquery.com | jquery.org/license */
-(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);
\ No newline at end of file +../../../javascript/jquery/jquery.min.js
\ No newline at end of file diff --git a/program/js/jstz.min.js b/program/js/jstz.min.js index d5f888cac..81c5057fd 100644 --- a/program/js/jstz.min.js +++ b/program/js/jstz.min.js @@ -1,2 +1,11 @@ -/*! jsTimezoneDetect - v1.0.5 - 2013-04-01 */ -(function(e){var t=function(){"use strict";var e="s",n=2011,r=function(e){var t=-e.getTimezoneOffset();return t!==null?t:0},i=function(e,t,n){var r=new Date;return e!==undefined&&r.setFullYear(e),r.setDate(n),r.setMonth(t),r},s=function(e){return r(i(e,0,2))},o=function(e){return r(i(e,5,2))},u=function(e){var t=e.getMonth()>7?o(e.getFullYear()):s(e.getFullYear()),n=r(e);return t-n!==0},a=function(){var t=s(n),r=o(n),i=t-r;return i<0?t+",1":i>0?r+",1,"+e:t+",0"},f=function(){var e=a();return new t.TimeZone(t.olson.timezones[e])},l=function(e){var t=new Date(2010,6,15,1,0,0,0),n={"America/Denver":new Date(2011,2,13,3,0,0,0),"America/Mazatlan":new Date(2011,3,3,3,0,0,0),"America/Chicago":new Date(2011,2,13,3,0,0,0),"America/Mexico_City":new Date(2011,3,3,3,0,0,0),"America/Asuncion":new Date(2012,9,7,3,0,0,0),"America/Santiago":new Date(2012,9,3,3,0,0,0),"America/Campo_Grande":new Date(2012,9,21,5,0,0,0),"America/Montevideo":new Date(2011,9,2,3,0,0,0),"America/Sao_Paulo":new Date(2011,9,16,5,0,0,0),"America/Los_Angeles":new Date(2011,2,13,8,0,0,0),"America/Santa_Isabel":new Date(2011,3,5,8,0,0,0),"America/Havana":new Date(2012,2,10,2,0,0,0),"America/New_York":new Date(2012,2,10,7,0,0,0),"Asia/Beirut":new Date(2011,2,27,1,0,0,0),"Europe/Helsinki":new Date(2011,2,27,4,0,0,0),"Europe/Istanbul":new Date(2011,2,28,5,0,0,0),"Asia/Damascus":new Date(2011,3,1,2,0,0,0),"Asia/Jerusalem":new Date(2011,3,1,6,0,0,0),"Asia/Gaza":new Date(2009,2,28,0,30,0,0),"Africa/Cairo":new Date(2009,3,25,0,30,0,0),"Pacific/Auckland":new Date(2011,8,26,7,0,0,0),"Pacific/Fiji":new Date(2010,10,29,23,0,0,0),"America/Halifax":new Date(2011,2,13,6,0,0,0),"America/Goose_Bay":new Date(2011,2,13,2,1,0,0),"America/Miquelon":new Date(2011,2,13,5,0,0,0),"America/Godthab":new Date(2011,2,27,1,0,0,0),"Europe/Moscow":t,"Asia/Yekaterinburg":t,"Asia/Omsk":t,"Asia/Krasnoyarsk":t,"Asia/Irkutsk":t,"Asia/Yakutsk":t,"Asia/Vladivostok":t,"Asia/Kamchatka":t,"Europe/Minsk":t,"Pacific/Apia":new Date(2010,10,1,1,0,0,0),"Australia/Perth":new Date(2008,10,1,1,0,0,0)};return n[e]};return{determine:f,date_is_dst:u,dst_start_for:l}}();t.TimeZone=function(e){"use strict";var n={"America/Denver":["America/Denver","America/Mazatlan"],"America/Chicago":["America/Chicago","America/Mexico_City"],"America/Santiago":["America/Santiago","America/Asuncion","America/Campo_Grande"],"America/Montevideo":["America/Montevideo","America/Sao_Paulo"],"Asia/Beirut":["Asia/Beirut","Europe/Helsinki","Europe/Istanbul","Asia/Damascus","Asia/Jerusalem","Asia/Gaza"],"Pacific/Auckland":["Pacific/Auckland","Pacific/Fiji"],"America/Los_Angeles":["America/Los_Angeles","America/Santa_Isabel"],"America/New_York":["America/Havana","America/New_York"],"America/Halifax":["America/Goose_Bay","America/Halifax"],"America/Godthab":["America/Miquelon","America/Godthab"],"Asia/Dubai":["Europe/Moscow"],"Asia/Dhaka":["Asia/Yekaterinburg"],"Asia/Jakarta":["Asia/Omsk"],"Asia/Shanghai":["Asia/Krasnoyarsk","Australia/Perth"],"Asia/Tokyo":["Asia/Irkutsk"],"Australia/Brisbane":["Asia/Yakutsk"],"Pacific/Noumea":["Asia/Vladivostok"],"Pacific/Tarawa":["Asia/Kamchatka"],"Pacific/Tongatapu":["Pacific/Apia"],"Africa/Johannesburg":["Asia/Gaza","Africa/Cairo"],"Asia/Baghdad":["Europe/Minsk"]},r=e,i=function(){var e=n[r],i=e.length,s=0,o=e[0];for(;s<i;s+=1){o=e[s];if(t.date_is_dst(t.dst_start_for(o))){r=o;return}}},s=function(){return typeof n[r]!="undefined"};return s()&&i(),{name:function(){return r}}},t.olson={},t.olson.timezones={"-720,0":"Pacific/Majuro","-660,0":"Pacific/Pago_Pago","-600,1":"America/Adak","-600,0":"Pacific/Honolulu","-570,0":"Pacific/Marquesas","-540,0":"Pacific/Gambier","-540,1":"America/Anchorage","-480,1":"America/Los_Angeles","-480,0":"Pacific/Pitcairn","-420,0":"America/Phoenix","-420,1":"America/Denver","-360,0":"America/Guatemala","-360,1":"America/Chicago","-360,1,s":"Pacific/Easter","-300,0":"America/Bogota","-300,1":"America/New_York","-270,0":"America/Caracas","-240,1":"America/Halifax","-240,0":"America/Santo_Domingo","-240,1,s":"America/Santiago","-210,1":"America/St_Johns","-180,1":"America/Godthab","-180,0":"America/Argentina/Buenos_Aires","-180,1,s":"America/Montevideo","-120,0":"America/Noronha","-120,1":"America/Noronha","-60,1":"Atlantic/Azores","-60,0":"Atlantic/Cape_Verde","0,0":"UTC","0,1":"Europe/London","60,1":"Europe/Berlin","60,0":"Africa/Lagos","60,1,s":"Africa/Windhoek","120,1":"Asia/Beirut","120,0":"Africa/Johannesburg","180,0":"Asia/Baghdad","180,1":"Europe/Moscow","210,1":"Asia/Tehran","240,0":"Asia/Dubai","240,1":"Asia/Baku","270,0":"Asia/Kabul","300,1":"Asia/Yekaterinburg","300,0":"Asia/Karachi","330,0":"Asia/Kolkata","345,0":"Asia/Kathmandu","360,0":"Asia/Dhaka","360,1":"Asia/Omsk","390,0":"Asia/Rangoon","420,1":"Asia/Krasnoyarsk","420,0":"Asia/Jakarta","480,0":"Asia/Shanghai","480,1":"Asia/Irkutsk","525,0":"Australia/Eucla","525,1,s":"Australia/Eucla","540,1":"Asia/Yakutsk","540,0":"Asia/Tokyo","570,0":"Australia/Darwin","570,1,s":"Australia/Adelaide","600,0":"Australia/Brisbane","600,1":"Asia/Vladivostok","600,1,s":"Australia/Sydney","630,1,s":"Australia/Lord_Howe","660,1":"Asia/Kamchatka","660,0":"Pacific/Noumea","690,0":"Pacific/Norfolk","720,1,s":"Pacific/Auckland","720,0":"Pacific/Tarawa","765,1,s":"Pacific/Chatham","780,0":"Pacific/Tongatapu","780,1,s":"Pacific/Apia","840,0":"Pacific/Kiritimati"},typeof exports!="undefined"?exports.jstz=t:e.jstz=t})(this);
\ No newline at end of file +var jstz=function(){var b=function(a){a=-a.getTimezoneOffset();return null!==a?a:0},c=function(){return b(new Date(2010,0,1,0,0,0,0))},f=function(){return b(new Date(2010,5,1,0,0,0,0))},e=function(){var a=c(),d=f(),b=c()-f();return new jstz.TimeZone(jstz.olson.timezones[0>b?a+",1":0<b?d+",1,s":a+",0"])};return{determine_timezone:function(){"undefined"!==typeof console&&console.log("jstz.determine_timezone() is deprecated and will be removed in an upcoming version. Please use jstz.determine() instead."); +return e()},determine:e,date_is_dst:function(a){var d=5<a.getMonth()?f():c(),a=b(a);return 0!==d-a}}}();jstz.TimeZone=function(b){var c=null,c=b;"undefined"!==typeof jstz.olson.ambiguity_list[c]&&function(){for(var b=jstz.olson.ambiguity_list[c],e=b.length,a=0,d=b[0];a<e;a+=1)if(d=b[a],jstz.date_is_dst(jstz.olson.dst_start_dates[d])){c=d;break}}();return{name:function(){return c}}};jstz.olson={}; +jstz.olson.timezones={"-720,0":"Etc/GMT+12","-660,0":"Pacific/Pago_Pago","-600,1":"America/Adak","-600,0":"Pacific/Honolulu","-570,0":"Pacific/Marquesas","-540,0":"Pacific/Gambier","-540,1":"America/Anchorage","-480,1":"America/Los_Angeles","-480,0":"Pacific/Pitcairn","-420,0":"America/Phoenix","-420,1":"America/Denver","-360,0":"America/Guatemala","-360,1":"America/Chicago","-360,1,s":"Pacific/Easter","-300,0":"America/Bogota","-300,1":"America/New_York","-270,0":"America/Caracas","-240,1":"America/Halifax", +"-240,0":"America/Santo_Domingo","-240,1,s":"America/Asuncion","-210,1":"America/St_Johns","-180,1":"America/Godthab","-180,0":"America/Argentina/Buenos_Aires","-180,1,s":"America/Montevideo","-120,0":"America/Noronha","-120,1":"Etc/GMT+2","-60,1":"Atlantic/Azores","-60,0":"Atlantic/Cape_Verde","0,0":"Etc/UTC","0,1":"Europe/London","60,1":"Europe/Berlin","60,0":"Africa/Lagos","60,1,s":"Africa/Windhoek","120,1":"Asia/Beirut","120,0":"Africa/Johannesburg","180,1":"Europe/Moscow","180,0":"Asia/Baghdad", +"210,1":"Asia/Tehran","240,0":"Asia/Dubai","240,1":"Asia/Yerevan","270,0":"Asia/Kabul","300,1":"Asia/Yekaterinburg","300,0":"Asia/Karachi","330,0":"Asia/Kolkata","345,0":"Asia/Kathmandu","360,0":"Asia/Dhaka","360,1":"Asia/Omsk","390,0":"Asia/Rangoon","420,1":"Asia/Krasnoyarsk","420,0":"Asia/Jakarta","480,0":"Asia/Shanghai","480,1":"Asia/Irkutsk","525,0":"Australia/Eucla","525,1,s":"Australia/Eucla","540,1":"Asia/Yakutsk","540,0":"Asia/Tokyo","570,0":"Australia/Darwin","570,1,s":"Australia/Adelaide", +"600,0":"Australia/Brisbane","600,1":"Asia/Vladivostok","600,1,s":"Australia/Sydney","630,1,s":"Australia/Lord_Howe","660,1":"Asia/Kamchatka","660,0":"Pacific/Noumea","690,0":"Pacific/Norfolk","720,1,s":"Pacific/Auckland","720,0":"Pacific/Tarawa","765,1,s":"Pacific/Chatham","780,0":"Pacific/Tongatapu","780,1,s":"Pacific/Apia","840,0":"Pacific/Kiritimati"}; +jstz.olson.dst_start_dates={"America/Denver":new Date(2011,2,13,3,0,0,0),"America/Mazatlan":new Date(2011,3,3,3,0,0,0),"America/Chicago":new Date(2011,2,13,3,0,0,0),"America/Mexico_City":new Date(2011,3,3,3,0,0,0),"Atlantic/Stanley":new Date(2011,8,4,7,0,0,0),"America/Asuncion":new Date(2011,9,2,3,0,0,0),"America/Santiago":new Date(2011,9,9,3,0,0,0),"America/Campo_Grande":new Date(2011,9,16,5,0,0,0),"America/Montevideo":new Date(2011,9,2,3,0,0,0),"America/Sao_Paulo":new Date(2011,9,16,5,0,0,0),"America/Los_Angeles":new Date(2011, +2,13,8,0,0,0),"America/Santa_Isabel":new Date(2011,3,5,8,0,0,0),"America/Havana":new Date(2011,2,13,2,0,0,0),"America/New_York":new Date(2011,2,13,7,0,0,0),"Asia/Gaza":new Date(2011,2,26,23,0,0,0),"Asia/Beirut":new Date(2011,2,27,1,0,0,0),"Europe/Minsk":new Date(2011,2,27,2,0,0,0),"Europe/Helsinki":new Date(2011,2,27,4,0,0,0),"Europe/Istanbul":new Date(2011,2,28,5,0,0,0),"Asia/Damascus":new Date(2011,3,1,2,0,0,0),"Asia/Jerusalem":new Date(2011,3,1,6,0,0,0),"Africa/Cairo":new Date(2010,3,30,4,0,0, +0),"Asia/Yerevan":new Date(2011,2,27,4,0,0,0),"Asia/Baku":new Date(2011,2,27,8,0,0,0),"Pacific/Auckland":new Date(2011,8,26,7,0,0,0),"Pacific/Fiji":new Date(2010,11,29,23,0,0,0),"America/Halifax":new Date(2011,2,13,6,0,0,0),"America/Goose_Bay":new Date(2011,2,13,2,1,0,0),"America/Miquelon":new Date(2011,2,13,5,0,0,0),"America/Godthab":new Date(2011,2,27,1,0,0,0)}; +jstz.olson.ambiguity_list={"America/Denver":["America/Denver","America/Mazatlan"],"America/Chicago":["America/Chicago","America/Mexico_City"],"America/Asuncion":["Atlantic/Stanley","America/Asuncion","America/Santiago","America/Campo_Grande"],"America/Montevideo":["America/Montevideo","America/Sao_Paulo"],"Asia/Beirut":"Asia/Gaza Asia/Beirut Europe/Minsk Europe/Helsinki Europe/Istanbul Asia/Damascus Asia/Jerusalem Africa/Cairo".split(" "),"Asia/Yerevan":["Asia/Yerevan","Asia/Baku"],"Pacific/Auckland":["Pacific/Auckland", +"Pacific/Fiji"],"America/Los_Angeles":["America/Los_Angeles","America/Santa_Isabel"],"America/New_York":["America/Havana","America/New_York"],"America/Halifax":["America/Goose_Bay","America/Halifax"],"America/Godthab":["America/Miquelon","America/Godthab"]};
\ No newline at end of file diff --git a/program/js/list.js b/program/js/list.js index c2ad3f7c3..fbb478db7 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -1,1606 +1 @@ -/* - +-----------------------------------------------------------------------+ - | Roundcube List Widget | - | | - | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2013, The Roundcube Dev Team | - | | - | Licensed under the GNU General Public License version 3 or | - | any later version with exceptions for skins & plugins. | - | See the README file for a full license statement. | - | | - +-----------------------------------------------------------------------+ - | Authors: Thomas Bruederli <roundcube@gmail.com> | - | Charles McNulty <charles@charlesmcnulty.com> | - +-----------------------------------------------------------------------+ - | Requires: common.js | - +-----------------------------------------------------------------------+ -*/ - - -/** - * Roundcube List Widget class - * @contructor - */ -function rcube_list_widget(list, p) -{ - // static contants - this.ENTER_KEY = 13; - this.DELETE_KEY = 46; - this.BACKSPACE_KEY = 8; - - this.list = list ? list : null; - this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table'; - this.thead; - this.tbody; - this.fixed_header; - this.frame = null; - this.rows = []; - this.selection = []; - this.rowcount = 0; - this.colcount = 0; - - this.subject_col = -1; - this.modkey = 0; - this.multiselect = false; - this.multiexpand = false; - this.multi_selecting = false; - this.draggable = false; - this.column_movable = false; - this.keyboard = false; - this.toggleselect = false; - - this.dont_select = false; - this.drag_active = false; - this.col_drag_active = false; - this.column_fixed = null; - this.last_selected = 0; - this.shift_start = 0; - this.in_selection_before = false; - this.focused = false; - this.drag_mouse_start = null; - this.dblclick_time = 500; // default value on MS Windows is 500 - this.row_init = function(){}; // @deprecated; use list.addEventListener('initrow') instead - - // overwrite default paramaters - if (p && typeof p === 'object') - for (var n in p) - this[n] = p[n]; -}; - - -rcube_list_widget.prototype = { - - -/** - * get all message rows from HTML table and init each row - */ -init: function() -{ - if (this.tagname == 'table' && this.list && this.list.tBodies[0]) { - this.thead = this.list.tHead; - this.tbody = this.list.tBodies[0]; - } - else if (this.tagname != 'table' && this.list) { - this.tbody = this.list; - } - - if (this.tbody) { - this.rows = []; - this.rowcount = 0; - - var r, len, rows = this.tbody.childNodes; - - for (r=0, len=rows.length; r<len; r++) { - this.init_row(rows[r]); - this.rowcount++; - } - - this.init_header(); - this.frame = this.list.parentNode; - - // set body events - if (this.keyboard) - rcube_event.add_listener({event:'keydown', object:this, method:'key_press'}); - } -}, - - -/** - * Init list row and set mouse events on it - */ -init_row: function(row) -{ - // make references in internal array and set event handlers - if (row && String(row.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)) { - var self = this, - uid = RegExp.$1; - row.uid = uid; - this.rows[uid] = {uid:uid, id:row.id, obj:row}; - - // set eventhandlers to table row - row.onmousedown = function(e){ return self.drag_row(e, this.uid); }; - row.onmouseup = function(e){ return self.click_row(e, this.uid); }; - - if (bw.touch) { - row.addEventListener('touchstart', function(e) { - if (e.touches.length == 1) { - self.touchmoved = false; - self.drag_row(rcube_event.touchevent(e.touches[0]), this.uid) - } - }, false); - row.addEventListener('touchend', function(e) { - if (e.changedTouches.length == 1) { - if (!self.touchmoved && !self.click_row(rcube_event.touchevent(e.changedTouches[0]), this.uid)) - e.preventDefault(); - } - }, false); - row.addEventListener('touchmove', function(e) { - if (e.changedTouches.length == 1) { - self.touchmoved = true; - if (self.drag_active) - e.preventDefault(); - } - }, false); - } - - if (document.all) - row.onselectstart = function() { return false; }; - - this.row_init(this.rows[uid]); // legacy support - this.triggerEvent('initrow', this.rows[uid]); - } -}, - - -/** - * Init list column headers and set mouse events on them - */ -init_header: function() -{ - if (this.thead) { - this.colcount = 0; - - if (this.fixed_header) { // copy (modified) fixed header back to the actual table - $(this.list.tHead).replaceWith($(this.fixed_header).find('thead').clone()); - $(this.list.tHead).find('tr td').attr('style', ''); // remove fixed widths - } - else if (!bw.touch && this.list.className.indexOf('fixedheader') >= 0) { - this.init_fixed_header(); - } - - var col, r, p = this; - // add events for list columns moving - if (this.column_movable && this.thead && this.thead.rows) { - for (r=0; r<this.thead.rows[0].cells.length; r++) { - if (this.column_fixed == r) - continue; - col = this.thead.rows[0].cells[r]; - col.onmousedown = function(e){ return p.drag_column(e, this); }; - this.colcount++; - } - } - } -}, - -init_fixed_header: function() -{ - var clone = $(this.list.tHead).clone(); - - if (!this.fixed_header) { - this.fixed_header = $('<table>') - .attr('class', this.list.className + ' fixedcopy') - .css({ position:'fixed' }) - .append(clone) - .append('<tbody></tbody>'); - $(this.list).before(this.fixed_header); - - var me = this; - $(window).resize(function(){ me.resize() }); - } - else { - $(this.fixed_header).find('thead').replaceWith(clone); - } - - this.thead = clone.get(0); - this.resize(); -}, - -resize: function() -{ - if (!this.fixed_header) - return; - - var column_widths = []; - - // get column widths from original thead - $(this.tbody).parent().find('thead tr td').each(function(index) { - column_widths[index] = $(this).width(); - }); - - // apply fixed widths to fixed table header - $(this.thead).parent().width($(this.tbody).parent().width()); - $(this.thead).find('tr td').each(function(index) { - $(this).css('width', column_widths[index]); - }); -}, - -/** - * Remove all list rows - */ -clear: function(sel) -{ - if (this.tagname == 'table') { - var tbody = document.createElement('tbody'); - this.list.insertBefore(tbody, this.tbody); - this.list.removeChild(this.list.tBodies[1]); - this.tbody = tbody; - } - else { - $(this.row_tagname() + ':not(.thead)', this.tbody).remove(); - } - - this.rows = []; - this.rowcount = 0; - - if (sel) - this.clear_selection(); - - // reset scroll position (in Opera) - if (this.frame) - this.frame.scrollTop = 0; -}, - - -/** - * 'remove' message row from list (just hide it) - */ -remove_row: function(uid, sel_next) -{ - var node = this.rows[uid] ? this.rows[uid].obj : null; - - if (!node) - return; - - node.style.display = 'none'; - - if (sel_next) - this.select_next(); - - delete this.rows[uid]; - this.rowcount--; -}, - - -/** - * Add row to the list and initialize it - */ -insert_row: function(row, before) -{ - var tbody = this.tbody; - - // create a real dom node first - if (row.nodeName === undefined) { - // for performance reasons use DOM instead of jQuery here - var domrow = document.createElement(this.row_tagname()); - if (row.id) domrow.id = row.id; - if (row.className) domrow.className = row.className; - if (row.style) $.extend(domrow.style, row.style); - - for (var domcell, col, i=0; row.cols && i < row.cols.length; i++) { - col = row.cols[i]; - domcell = document.createElement(this.col_tagname()); - if (col.className) domcell.className = col.className; - if (col.innerHTML) domcell.innerHTML = col.innerHTML; - domrow.appendChild(domcell); - } - - row = domrow; - } - - if (before && tbody.childNodes.length) - tbody.insertBefore(row, (typeof before == 'object' && before.parentNode == tbody) ? before : tbody.firstChild); - else - tbody.appendChild(row); - - this.init_row(row); - this.rowcount++; -}, - -/** - * - */ -update_row: function(id, cols, newid, select) -{ - var row = this.rows[id]; - if (!row) return false; - - var domrow = row.obj; - for (var domcell, col, i=0; cols && i < cols.length; i++) { - this.get_cell(domrow, i).html(cols[i]); - } - - if (newid) { - delete this.rows[id]; - domrow.id = 'rcmrow' + newid; - this.init_row(domrow); - - if (select) - this.selection[0] = newid; - } -}, - - -/** - * Set focus to the list - */ -focus: function(e) -{ - var n, id; - this.focused = true; - - for (n in this.selection) { - id = this.selection[n]; - if (this.rows[id] && this.rows[id].obj) { - $(this.rows[id].obj).addClass('selected').removeClass('unfocused'); - } - } - - // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) - // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) - $(':focus:not(body)').blur(); - window.focus(); - - if (e || (e = window.event)) - rcube_event.cancel(e); -}, - - -/** - * remove focus from the list - */ -blur: function() -{ - var n, id; - this.focused = false; - for (n in this.selection) { - id = this.selection[n]; - if (this.rows[id] && this.rows[id].obj) { - $(this.rows[id].obj).removeClass('selected focused').addClass('unfocused'); - } - } -}, - - -/** - * onmousedown-handler of message list column - */ -drag_column: function(e, col) -{ - if (this.colcount > 1) { - this.drag_start = true; - this.drag_mouse_start = rcube_event.get_mouse_pos(e); - - rcube_event.add_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); - rcube_event.add_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); - - // enable dragging over iframes - this.add_dragfix(); - - // find selected column number - for (var i=0; i<this.thead.rows[0].cells.length; i++) { - if (col == this.thead.rows[0].cells[i]) { - this.selected_column = i; - break; - } - } - } - - return false; -}, - - -/** - * onmousedown-handler of message list row - */ -drag_row: function(e, id) -{ - // don't do anything (another action processed before) - var evtarget = rcube_event.get_target(e), - tagname = evtarget.tagName.toLowerCase(); - - if (this.dont_select || (evtarget && (tagname == 'input' || tagname == 'img'))) - return true; - - // accept right-clicks - if (rcube_event.get_button(e) == 2) - return true; - - this.in_selection_before = e && e.istouch || this.in_selection(id) ? id : false; - - // selects currently unselected row - if (!this.in_selection_before) { - var mod_key = rcube_event.get_modifier(e); - this.select_row(id, mod_key, false); - } - - if (this.draggable && this.selection.length && this.in_selection(id)) { - this.drag_start = true; - this.drag_mouse_start = rcube_event.get_mouse_pos(e); - rcube_event.add_listener({event:'mousemove', object:this, method:'drag_mouse_move'}); - rcube_event.add_listener({event:'mouseup', object:this, method:'drag_mouse_up'}); - if (bw.touch) { - rcube_event.add_listener({event:'touchmove', object:this, method:'drag_mouse_move'}); - rcube_event.add_listener({event:'touchend', object:this, method:'drag_mouse_up'}); - } - - // enable dragging over iframes - this.add_dragfix(); - } - - return false; -}, - - -/** - * onmouseup-handler of message list row - */ -click_row: function(e, id) -{ - var now = new Date().getTime(), - mod_key = rcube_event.get_modifier(e), - evtarget = rcube_event.get_target(e), - tagname = evtarget.tagName.toLowerCase(); - - if ((evtarget && (tagname == 'input' || tagname == 'img'))) - return true; - - // don't do anything (another action processed before) - if (this.dont_select) { - this.dont_select = false; - return false; - } - - var dblclicked = now - this.rows[id].clicked < this.dblclick_time; - - // unselects currently selected row - if (!this.drag_active && this.in_selection_before == id && !dblclicked) - this.select_row(id, mod_key, false); - - this.drag_start = false; - this.in_selection_before = false; - - // row was double clicked - if (this.rows && dblclicked && this.in_selection(id)) { - this.triggerEvent('dblclick'); - now = 0; - } - else - this.triggerEvent('click'); - - if (!this.drag_active) { - // remove temp divs - this.del_dragfix(); - rcube_event.cancel(e); - } - - this.rows[id].clicked = now; - return false; -}, - - -/* - * Returns thread root ID for specified row ID - */ -find_root: function(uid) -{ - var r = this.rows[uid]; - - if (r && r.parent_uid) - return this.find_root(r.parent_uid); - else - return uid; -}, - - -expand_row: function(e, id) -{ - var row = this.rows[id], - evtarget = rcube_event.get_target(e), - mod_key = rcube_event.get_modifier(e); - - // Don't select this message - this.dont_select = true; - // Don't treat double click on the expando as double click on the message. - row.clicked = 0; - - if (row.expanded) { - evtarget.className = 'collapsed'; - if (mod_key == CONTROL_KEY || this.multiexpand) - this.collapse_all(row); - else - this.collapse(row); - } - else { - evtarget.className = 'expanded'; - if (mod_key == CONTROL_KEY || this.multiexpand) - this.expand_all(row); - else - this.expand(row); - } -}, - -collapse: function(row) -{ - row.expanded = false; - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - var depth = row.depth; - var new_row = row ? row.obj.nextSibling : null; - var r; - - while (new_row) { - if (new_row.nodeType == 1) { - var r = this.rows[new_row.uid]; - if (r && r.depth <= depth) - break; - $(new_row).css('display', 'none'); - if (r.expanded) { - r.expanded = false; - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - -expand: function(row) -{ - var r, p, depth, new_row, last_expanded_parent_depth; - - if (row) { - row.expanded = true; - depth = row.depth; - new_row = row.obj.nextSibling; - this.update_expando(row.uid, true); - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - } - else { - var tbody = this.tbody; - new_row = tbody.firstChild; - depth = 0; - last_expanded_parent_depth = 0; - } - - while (new_row) { - if (new_row.nodeType == 1) { - r = this.rows[new_row.uid]; - if (r) { - if (row && (!r.depth || r.depth <= depth)) - break; - - if (r.parent_uid) { - p = this.rows[r.parent_uid]; - if (p && p.expanded) { - if ((row && p == row) || last_expanded_parent_depth >= p.depth - 1) { - last_expanded_parent_depth = p.depth; - $(new_row).css('display', ''); - r.expanded = true; - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - else - if (row && (! p || p.depth <= depth)) - break; - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -collapse_all: function(row) -{ - var depth, new_row, r; - - if (row) { - row.expanded = false; - depth = row.depth; - new_row = row.obj.nextSibling; - this.update_expando(row.uid); - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - - // don't collapse sub-root tree in multiexpand mode - if (depth && this.multiexpand) - return false; - } - else { - new_row = this.tbody.firstChild; - depth = 0; - } - - while (new_row) { - if (new_row.nodeType == 1) { - if (r = this.rows[new_row.uid]) { - if (row && (!r.depth || r.depth <= depth)) - break; - - if (row || r.depth) - $(new_row).css('display', 'none'); - if (r.has_children && r.expanded) { - r.expanded = false; - this.update_expando(r.uid, false); - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -expand_all: function(row) -{ - var depth, new_row, r; - - if (row) { - row.expanded = true; - depth = row.depth; - new_row = row.obj.nextSibling; - this.update_expando(row.uid, true); - this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); - } - else { - new_row = this.tbody.firstChild; - depth = 0; - } - - while (new_row) { - if (new_row.nodeType == 1) { - if (r = this.rows[new_row.uid]) { - if (row && r.depth <= depth) - break; - - $(new_row).css('display', ''); - if (r.has_children && !r.expanded) { - r.expanded = true; - this.update_expando(r.uid, true); - this.triggerEvent('expandcollapse', { uid:r.uid, expanded:r.expanded, obj:new_row }); - } - } - } - new_row = new_row.nextSibling; - } - - this.resize(); - this.triggerEvent('listupdate'); - return false; -}, - - -update_expando: function(uid, expanded) -{ - var expando = document.getElementById('rcmexpando' + uid); - if (expando) - expando.className = expanded ? 'expanded' : 'collapsed'; -}, - - -/** - * get first/next/previous/last rows that are not hidden - */ -get_next_row: function() -{ - if (!this.rows) - return false; - - var last_selected_row = this.rows[this.last_selected], - new_row = last_selected_row ? last_selected_row.obj.nextSibling : null; - - while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) - new_row = new_row.nextSibling; - - return new_row; -}, - -get_prev_row: function() -{ - if (!this.rows) - return false; - - var last_selected_row = this.rows[this.last_selected], - new_row = last_selected_row ? last_selected_row.obj.previousSibling : null; - - while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) - new_row = new_row.previousSibling; - - return new_row; -}, - -get_first_row: function() -{ - if (this.rowcount) { - var i, len, rows = this.tbody.childNodes; - - for (i=0, len=rows.length-1; i<len; i++) - if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) - return RegExp.$1; - } - - return null; -}, - -get_last_row: function() -{ - if (this.rowcount) { - var i, rows = this.tbody.childNodes; - - for (i=rows.length-1; i>=0; i--) - if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) - return RegExp.$1; - } - - return null; -}, - -row_tagname: function() -{ - var row_tagnames = { table:'tr', ul:'li', '*':'div' }; - return row_tagnames[this.tagname] || row_tagnames['*']; -}, - -col_tagname: function() -{ - var col_tagnames = { table:'td', '*':'span' }; - return col_tagnames[this.tagname] || col_tagnames['*']; -}, - -get_cell: function(row, index) -{ - return $(this.col_tagname(), row).eq(index); -}, - -/** - * selects or unselects the proper row depending on the modifier key pressed - */ -select_row: function(id, mod_key, with_mouse) -{ - var select_before = this.selection.join(','); - if (!this.multiselect) - mod_key = 0; - - if (!this.shift_start) - this.shift_start = id - - if (!mod_key) { - this.shift_start = id; - this.highlight_row(id, false); - this.multi_selecting = false; - } - else { - switch (mod_key) { - case SHIFT_KEY: - this.shift_select(id, false); - break; - - case CONTROL_KEY: - if (!with_mouse) - this.highlight_row(id, true); - break; - - case CONTROL_SHIFT_KEY: - this.shift_select(id, true); - break; - - default: - this.highlight_row(id, false); - break; - } - this.multi_selecting = true; - } - - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - if (this.last_selected != 0 && this.rows[this.last_selected]) - $(this.rows[this.last_selected].obj).removeClass('focused'); - - // unselect if toggleselect is active and the same row was clicked again - if (this.toggleselect && this.last_selected == id) { - this.clear_selection(); - id = null; - } - else - $(this.rows[id].obj).addClass('focused'); - - if (!this.selection.length) - this.shift_start = null; - - this.last_selected = id; -}, - - -/** - * Alias method for select_row - */ -select: function(id) -{ - this.select_row(id, false); - this.scrollto(id); -}, - - -/** - * Select row next to the last selected one. - * Either below or above. - */ -select_next: function() -{ - var next_row = this.get_next_row(), - prev_row = this.get_prev_row(), - new_row = (next_row) ? next_row : prev_row; - - if (new_row) - this.select_row(new_row.uid, false, false); -}, - - -/** - * Select first row - */ -select_first: function(mod_key) -{ - var row = this.get_first_row(); - if (row) { - if (mod_key) { - this.shift_select(row, mod_key); - this.triggerEvent('select'); - this.scrollto(row); - } - else { - this.select(row); - } - } -}, - - -/** - * Select last row - */ -select_last: function(mod_key) -{ - var row = this.get_last_row(); - if (row) { - if (mod_key) { - this.shift_select(row, mod_key); - this.triggerEvent('select'); - this.scrollto(row); - } - else { - this.select(row); - } - } -}, - - -/** - * Add all childs of the given row to selection - */ -select_children: function(uid) -{ - var i, children = this.row_children(uid), len = children.length; - - for (i=0; i<len; i++) - if (!this.in_selection(children[i])) - this.select_row(children[i], CONTROL_KEY); -}, - - -/** - * Perform selection when shift key is pressed - */ -shift_select: function(id, control) -{ - if (!this.rows[this.shift_start] || !this.selection.length) - this.shift_start = id; - - var n, i, j, to_row = this.rows[id], - from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj), - to_rowIndex = this._rowIndex(to_row.obj); - - if (!to_row.expanded && to_row.has_children) - if (to_row = this.rows[(this.row_children(id)).pop()]) - to_rowIndex = this._rowIndex(to_row.obj); - - i = ((from_rowIndex < to_rowIndex) ? from_rowIndex : to_rowIndex), - j = ((from_rowIndex > to_rowIndex) ? from_rowIndex : to_rowIndex); - - // iterate through the entire message list - for (n in this.rows) { - if (this._rowIndex(this.rows[n].obj) >= i && this._rowIndex(this.rows[n].obj) <= j) { - if (!this.in_selection(n)) { - this.highlight_row(n, true); - } - } - else { - if (this.in_selection(n) && !control) { - this.highlight_row(n, true); - } - } - } -}, - -/** - * Helper method to emulate the rowIndex property of non-tr elements - */ -_rowIndex: function(obj) -{ - return (obj.rowIndex !== undefined) ? obj.rowIndex : $(obj).prevAll().length; -}, - -/** - * Check if given id is part of the current selection - */ -in_selection: function(id) -{ - for (var n in this.selection) - if (this.selection[n]==id) - return true; - - return false; -}, - - -/** - * Select each row in list - */ -select_all: function(filter) -{ - if (!this.rows || !this.rows.length) - return false; - - // reset but remember selection first - var n, select_before = this.selection.join(','); - this.selection = []; - - for (n in this.rows) { - if (!filter || this.rows[n][filter] == true) { - this.last_selected = n; - this.highlight_row(n, true, true); - } - else { - $(this.rows[n].obj).removeClass('selected').removeClass('unfocused'); - } - } - - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - this.focus(); - - return true; -}, - - -/** - * Invert selection - */ -invert_selection: function() -{ - if (!this.rows || !this.rows.length) - return false; - - // remember old selection - var n, select_before = this.selection.join(','); - - for (n in this.rows) - this.highlight_row(n, true); - - // trigger event if selection changed - if (this.selection.join(',') != select_before) - this.triggerEvent('select'); - - this.focus(); - - return true; -}, - - -/** - * Unselect selected row(s) - */ -clear_selection: function(id) -{ - var n, num_select = this.selection.length; - - // one row - if (id) { - for (n in this.selection) - if (this.selection[n] == id) { - this.selection.splice(n,1); - break; - } - } - // all rows - else { - for (n in this.selection) - if (this.rows[this.selection[n]]) { - $(this.rows[this.selection[n]].obj).removeClass('selected').removeClass('unfocused'); - } - - this.selection = []; - } - - if (num_select && !this.selection.length) - this.triggerEvent('select'); -}, - - -/** - * Getter for the selection array - */ -get_selection: function() -{ - return this.selection; -}, - - -/** - * Return the ID if only one row is selected - */ -get_single_selection: function() -{ - if (this.selection.length == 1) - return this.selection[0]; - else - return null; -}, - - -/** - * Highlight/unhighlight a row - */ -highlight_row: function(id, multiple, norecur) -{ - if (!this.rows[id]) - return; - - if (!multiple) { - if (this.selection.length > 1 || !this.in_selection(id)) { - this.clear_selection(); - this.selection[0] = id; - $(this.rows[id].obj).addClass('selected'); - } - } - else { - if (!this.in_selection(id)) { // select row - this.selection.push(id); - $(this.rows[id].obj).addClass('selected'); - if (!norecur && !this.rows[id].expanded) - this.highlight_children(id, true); - } - else { // unselect row - var p = $.inArray(id, this.selection), - a_pre = this.selection.slice(0, p), - a_post = this.selection.slice(p+1, this.selection.length); - - this.selection = a_pre.concat(a_post); - $(this.rows[id].obj).removeClass('selected').removeClass('unfocused'); - if (!norecur && !this.rows[id].expanded) - this.highlight_children(id, false); - } - } -}, - - -/** - * Highlight/unhighlight all childs of the given row - */ -highlight_children: function(id, status) -{ - var i, selected, - children = this.row_children(id), len = children.length; - - for (i=0; i<len; i++) { - selected = this.in_selection(children[i]); - if ((status && !selected) || (!status && selected)) - this.highlight_row(children[i], true, true); - } -}, - - -/** - * Handler for keyboard events - */ -key_press: function(e) -{ - var target = e.target || {}; - if (this.focused != true || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT') - return true; - - var keyCode = rcube_event.get_keycode(e), - mod_key = rcube_event.get_modifier(e); - - switch (keyCode) { - case 40: - case 38: - case 63233: // "down", in safari keypress - case 63232: // "up", in safari keypress - // Stop propagation so that the browser doesn't scroll - rcube_event.cancel(e); - return this.use_arrow_key(keyCode, mod_key); - case 61: - case 107: // Plus sign on a numeric keypad (fc11 + firefox 3.5.2) - case 109: - case 32: - // Stop propagation - rcube_event.cancel(e); - var ret = this.use_plusminus_key(keyCode, mod_key); - this.key_pressed = keyCode; - this.modkey = mod_key; - this.triggerEvent('keypress'); - this.modkey = 0; - return ret; - case 36: // Home - this.select_first(mod_key); - return rcube_event.cancel(e); - case 35: // End - this.select_last(mod_key); - return rcube_event.cancel(e); - case 27: - if (this.drag_active) - return this.drag_mouse_up(e); - if (this.col_drag_active) { - this.selected_column = null; - return this.column_drag_mouse_up(e); - } - return rcube_event.cancel(e); - default: - this.key_pressed = keyCode; - this.modkey = mod_key; - this.triggerEvent('keypress'); - this.modkey = 0; - - if (this.key_pressed == this.BACKSPACE_KEY) - return rcube_event.cancel(e); - } - - return true; -}, - - -/** - * Special handling method for arrow keys - */ -use_arrow_key: function(keyCode, mod_key) -{ - var new_row; - // Safari uses the nonstandard keycodes 63232/63233 for up/down, if we're - // using the keypress event (but not the keydown or keyup event). - if (keyCode == 40 || keyCode == 63233) // down arrow key pressed - new_row = this.get_next_row(); - else if (keyCode == 38 || keyCode == 63232) // up arrow key pressed - new_row = this.get_prev_row(); - - if (new_row) { - this.select_row(new_row.uid, mod_key, false); - this.scrollto(new_row.uid); - } - - return false; -}, - - -/** - * Special handling method for +/- keys - */ -use_plusminus_key: function(keyCode, mod_key) -{ - var selected_row = this.rows[this.last_selected]; - if (!selected_row) - return; - - if (keyCode == 32) - keyCode = selected_row.expanded ? 109 : 61; - if (keyCode == 61 || keyCode == 107) - if (mod_key == CONTROL_KEY || this.multiexpand) - this.expand_all(selected_row); - else - this.expand(selected_row); - else - if (mod_key == CONTROL_KEY || this.multiexpand) - this.collapse_all(selected_row); - else - this.collapse(selected_row); - - this.update_expando(selected_row.uid, selected_row.expanded); - - return false; -}, - - -/** - * Try to scroll the list to make the specified row visible - */ -scrollto: function(id) -{ - var row = this.rows[id].obj; - if (row && this.frame) { - var scroll_to = Number(row.offsetTop); - - // expand thread if target row is hidden (collapsed) - if (!scroll_to && this.rows[id].parent_uid) { - var parent = this.find_root(this.rows[id].uid); - this.expand_all(this.rows[parent]); - scroll_to = Number(row.offsetTop); - } - - if (scroll_to < Number(this.frame.scrollTop)) - this.frame.scrollTop = scroll_to; - else if (scroll_to + Number(row.offsetHeight) > Number(this.frame.scrollTop) + Number(this.frame.offsetHeight)) - this.frame.scrollTop = (scroll_to + Number(row.offsetHeight)) - Number(this.frame.offsetHeight); - } -}, - - -/** - * Handler for mouse move events - */ -drag_mouse_move: function(e) -{ - // convert touch event - if (e.type == 'touchmove') { - if (e.touches.length == 1 && e.changedTouches.length == 1) - e = rcube_event.touchevent(e.changedTouches[0]); - else - return rcube_event.cancel(e); - } - - if (this.drag_start) { - // check mouse movement, of less than 3 pixels, don't start dragging - var m = rcube_event.get_mouse_pos(e); - - if (!this.drag_mouse_start || (Math.abs(m.x - this.drag_mouse_start.x) < 3 && Math.abs(m.y - this.drag_mouse_start.y) < 3)) - return false; - - if (!this.draglayer) - this.draglayer = $('<div>').attr('id', 'rcmdraglayer') - .css({ position:'absolute', display:'none', 'z-index':2000 }) - .appendTo(document.body); - - // also select childs of (collapsed) threads for dragging - var n, uid, selection = $.merge([], this.selection); - for (n in selection) { - uid = selection[n]; - if (!this.rows[uid].expanded) - this.select_children(uid); - } - - // reset content - this.draglayer.html(''); - - // get subjects of selected messages - var i, n, obj, me; - for (n=0; n<this.selection.length; n++) { - // only show 12 lines - if (n>12) { - this.draglayer.append('...'); - break; - } - - me = this; - if (obj = this.rows[this.selection[n]].obj) { - $('> '+this.col_tagname(), obj).each(function(i,elem){ - if (n == 0) - me.drag_start_pos = $(elem).offset(); - - if (me.subject_col < 0 || (me.subject_col >= 0 && me.subject_col == i)) { - var subject = $(elem).text(); - - if (subject) { - // remove leading spaces - subject = $.trim(subject); - // truncate line to 50 characters - subject = (subject.length > 50 ? subject.substring(0, 50) + '...' : subject); - - var entry = $('<div>').text(subject); - me.draglayer.append(entry); - } - - return false; // break - } - }); - } - } - - this.draglayer.show(); - this.drag_active = true; - this.triggerEvent('dragstart'); - } - - if (this.drag_active && this.draglayer) { - var pos = rcube_event.get_mouse_pos(e); - this.draglayer.css({ left:(pos.x+20)+'px', top:(pos.y-5 + (bw.ie ? document.documentElement.scrollTop : 0))+'px' }); - this.triggerEvent('dragmove', e?e:window.event); - } - - this.drag_start = false; - - return false; -}, - - -/** - * Handler for mouse up events - */ -drag_mouse_up: function(e) -{ - document.onmousemove = null; - - if (e.type == 'touchend') { - if (e.changedTouches.length != 1) - return rcube_event.cancel(e); - } - - if (this.draglayer && this.draglayer.is(':visible')) { - if (this.drag_start_pos) - this.draglayer.animate(this.drag_start_pos, 300, 'swing').hide(20); - else - this.draglayer.hide(); - } - - if (this.drag_active) - this.focus(); - this.drag_active = false; - - rcube_event.remove_listener({event:'mousemove', object:this, method:'drag_mouse_move'}); - rcube_event.remove_listener({event:'mouseup', object:this, method:'drag_mouse_up'}); - - if (bw.touch) { - rcube_event.remove_listener({event:'touchmove', object:this, method:'drag_mouse_move'}); - rcube_event.remove_listener({event:'touchend', object:this, method:'drag_mouse_up'}); - } - - // remove temp divs - this.del_dragfix(); - - this.triggerEvent('dragend', e); - - return rcube_event.cancel(e); -}, - - -/** - * Handler for mouse move events for dragging list column - */ -column_drag_mouse_move: function(e) -{ - if (this.drag_start) { - // check mouse movement, of less than 3 pixels, don't start dragging - var i, m = rcube_event.get_mouse_pos(e); - - if (!this.drag_mouse_start || (Math.abs(m.x - this.drag_mouse_start.x) < 3 && Math.abs(m.y - this.drag_mouse_start.y) < 3)) - return false; - - if (!this.col_draglayer) { - var lpos = $(this.list).offset(), - cells = this.thead.rows[0].cells; - - // create dragging layer - this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer') - .css(lpos).css({ position:'absolute', 'z-index':2001, - 'background-color':'white', opacity:0.75, - height: (this.frame.offsetHeight-2)+'px', width: (this.frame.offsetWidth-2)+'px' }) - .appendTo(document.body) - // ... and column position indicator - .append($('<div>').attr('id', 'rcmcolumnindicator') - .css({ position:'absolute', 'border-right':'2px dotted #555', - 'z-index':2002, height: (this.frame.offsetHeight-2)+'px' })); - - this.cols = []; - this.list_pos = this.list_min_pos = lpos.left; - // save columns positions - for (i=0; i<cells.length; i++) { - this.cols[i] = cells[i].offsetWidth; - if (this.column_fixed !== null && i <= this.column_fixed) { - this.list_min_pos += this.cols[i]; - } - } - } - - this.col_draglayer.show(); - this.col_drag_active = true; - this.triggerEvent('column_dragstart'); - } - - // set column indicator position - if (this.col_drag_active && this.col_draglayer) { - var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); - - for (i=0; i<this.cols.length; i++) { - if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) - cpos += this.cols[i]; - else - break; - } - - // handle fixed columns on left - if (i == 0 && this.list_min_pos > pos.x) - cpos = this.list_min_pos - this.list_pos; - // empty list needs some assignment - else if (!this.list.rowcount && i == this.cols.length) - cpos -= 2; - $('#rcmcolumnindicator').css({ width: cpos+'px'}); - this.triggerEvent('column_dragmove', e?e:window.event); - } - - this.drag_start = false; - - return false; -}, - - -/** - * Handler for mouse up events for dragging list columns - */ -column_drag_mouse_up: function(e) -{ - document.onmousemove = null; - - if (this.col_draglayer) { - (this.col_draglayer).remove(); - this.col_draglayer = null; - } - - if (this.col_drag_active) - this.focus(); - this.col_drag_active = false; - - rcube_event.remove_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); - rcube_event.remove_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); - // remove temp divs - this.del_dragfix(); - - if (this.selected_column !== null && this.cols && this.cols.length) { - var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); - - // find destination position - for (i=0; i<this.cols.length; i++) { - if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) - cpos += this.cols[i]; - else - break; - } - - if (i != this.selected_column && i != this.selected_column+1) { - this.column_replace(this.selected_column, i); - } - } - - this.triggerEvent('column_dragend', e); - - return rcube_event.cancel(e); -}, - - -/** - * Returns IDs of all rows in a thread (except root) for specified root - */ -row_children: function(uid) -{ - if (!this.rows[uid] || !this.rows[uid].has_children) - return []; - - var res = [], depth = this.rows[uid].depth, - row = this.rows[uid].obj.nextSibling; - - while (row) { - if (row.nodeType == 1) { - if ((r = this.rows[row.uid])) { - if (!r.depth || r.depth <= depth) - break; - res.push(r.uid); - } - } - row = row.nextSibling; - } - - return res; -}, - - -/** - * Creates a layer for drag&drop over iframes - */ -add_dragfix: function() -{ - $('iframe').each(function() { - $('<div class="iframe-dragdrop-fix"></div>') - .css({background: '#fff', - width: this.offsetWidth+'px', height: this.offsetHeight+'px', - position: 'absolute', opacity: '0.001', zIndex: 1000 - }) - .css($(this).offset()) - .appendTo(document.body); - }); -}, - - -/** - * Removes the layer for drag&drop over iframes - */ -del_dragfix: function() -{ - $('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); }); -}, - - -/** - * Replaces two columns - */ -column_replace: function(from, to) -{ - // only supported for <table> lists - if (!this.thead || !this.thead.rows) - return; - - var len, cells = this.thead.rows[0].cells, - elem = cells[from], - before = cells[to], - td = document.createElement('td'); - - // replace header cells - if (before) - cells[0].parentNode.insertBefore(td, before); - else - cells[0].parentNode.appendChild(td); - cells[0].parentNode.replaceChild(elem, td); - - // replace list cells - for (r=0, len=this.tbody.rows.length; r<len; r++) { - row = this.tbody.rows[r]; - - elem = row.cells[from]; - before = row.cells[to]; - td = document.createElement('td'); - - if (before) - row.insertBefore(td, before); - else - row.appendChild(td); - row.replaceChild(elem, td); - } - - // update subject column position - if (this.subject_col == from) - this.subject_col = to > from ? to - 1 : to; - else if (this.subject_col < from && to <= this.subject_col) - this.subject_col++; - else if (this.subject_col > from && to >= this.subject_col) - this.subject_col--; - - if (this.fixed_header) - this.init_header(); - - this.triggerEvent('column_replace'); -} - -}; - -rcube_list_widget.prototype.addEventListener = rcube_event_engine.prototype.addEventListener; -rcube_list_widget.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener; -rcube_list_widget.prototype.triggerEvent = rcube_event_engine.prototype.triggerEvent; +function rcube_list_widget(a,b){this.ENTER_KEY=13;this.DELETE_KEY=46;this.BACKSPACE_KEY=8;this.list=a?a:null;this.frame=null;this.rows=[];this.selection=[];this.rowcount=0;this.colcount=0;this.subject_col=-1;this.modkey=0;this.multiselect=false;this.multiexpand=false;this.multi_selecting=false;this.draggable=false;this.column_movable=false;this.keyboard=false;this.toggleselect=false;this.dont_select=false;this.drag_active=false;this.col_drag_active=false;this.column_fixed=null;this.last_selected=0;this.shift_start=0;this.in_selection_before=false;this.focused=false;this.drag_mouse_start=null;this.dblclick_time=600;this.row_init=function(){};if(b&&typeof b==="object"){for(var c in b){this[c]=b[c]}}}rcube_list_widget.prototype={init:function(){if(this.list&&this.list.tBodies[0]){this.rows=[];this.rowcount=0;var b,a,c=this.list.tBodies[0].rows;for(b=0,a=c.length;b<a;b++){this.init_row(c[b]);this.rowcount++}this.init_header();this.frame=this.list.parentNode;if(this.keyboard){rcube_event.add_listener({event:"keydown",object:this,method:"key_press"})}}},init_row:function(c){if(c&&String(c.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)){var a=this,b=RegExp.$1;c.uid=b;this.rows[b]={uid:b,id:c.id,obj:c};c.onmousedown=function(d){return a.drag_row(d,this.uid)};c.onmouseup=function(d){return a.click_row(d,this.uid)};if(bw.touch){c.addEventListener("touchstart",function(d){if(d.touches.length==1){a.touchmoved=false;a.drag_row(rcube_event.touchevent(d.touches[0]),this.uid)}},false);c.addEventListener("touchend",function(d){if(d.changedTouches.length==1){if(!a.touchmoved&&!a.click_row(rcube_event.touchevent(d.changedTouches[0]),this.uid)){d.preventDefault()}}},false);c.addEventListener("touchmove",function(d){if(d.changedTouches.length==1){a.touchmoved=true;if(a.drag_active){d.preventDefault()}}},false)}if(document.all){c.onselectstart=function(){return false}}this.row_init(this.rows[b])}},init_header:function(){if(this.list&&this.list.tHead){this.colcount=0;var a,b,c=this;if(this.column_movable&&this.list.tHead&&this.list.tHead.rows){for(b=0;b<this.list.tHead.rows[0].cells.length;b++){if(this.column_fixed==b){continue}a=this.list.tHead.rows[0].cells[b];a.onmousedown=function(d){return c.drag_column(d,this)};this.colcount++}}}},clear:function(b){var a=document.createElement("tbody");this.list.insertBefore(a,this.list.tBodies[0]);this.list.removeChild(this.list.tBodies[1]);this.rows=[];this.rowcount=0;if(b){this.clear_selection()}if(this.frame){this.frame.scrollTop=0}},remove_row:function(a,b){var c=this.rows[a]?this.rows[a].obj:null;if(!c){return}c.style.display="none";if(b){this.select_next()}delete this.rows[a];this.rowcount--},insert_row:function(c,a){var b=this.list.tBodies[0];if(a&&b.rows.length){b.insertBefore(c,b.firstChild)}else{b.appendChild(c)}this.init_row(c);this.rowcount++},focus:function(a){var c,b;this.focused=true;for(c in this.selection){b=this.selection[c];if(this.rows[b]&&this.rows[b].obj){$(this.rows[b].obj).addClass("selected").removeClass("unfocused")}}$(":focus:not(body)").blur();window.focus();if(a||(a=window.event)){rcube_event.cancel(a)}},blur:function(){var b,a;this.focused=false;for(b in this.selection){a=this.selection[b];if(this.rows[a]&&this.rows[a].obj){$(this.rows[a].obj).removeClass("selected focused").addClass("unfocused")}}},drag_column:function(c,a){if(this.colcount>1){this.drag_start=true;this.drag_mouse_start=rcube_event.get_mouse_pos(c);rcube_event.add_listener({event:"mousemove",object:this,method:"column_drag_mouse_move"});rcube_event.add_listener({event:"mouseup",object:this,method:"column_drag_mouse_up"});this.add_dragfix();for(var b=0;b<this.list.tHead.rows[0].cells.length;b++){if(a==this.list.tHead.rows[0].cells[b]){this.selected_column=b;break}}}return false},drag_row:function(d,f){var c=rcube_event.get_target(d),b=c.tagName.toLowerCase();if(this.dont_select||(c&&(b=="input"||b=="img"))){return true}if(rcube_event.get_button(d)==2){return true}this.in_selection_before=d&&d.istouch||this.in_selection(f)?f:false;if(!this.in_selection_before){var a=rcube_event.get_modifier(d);this.select_row(f,a,false)}if(this.draggable&&this.selection.length&&this.in_selection(f)){this.drag_start=true;this.drag_mouse_start=rcube_event.get_mouse_pos(d);rcube_event.add_listener({event:"mousemove",object:this,method:"drag_mouse_move"});rcube_event.add_listener({event:"mouseup",object:this,method:"drag_mouse_up"});if(bw.touch){rcube_event.add_listener({event:"touchmove",object:this,method:"drag_mouse_move"});rcube_event.add_listener({event:"touchend",object:this,method:"drag_mouse_up"})}this.add_dragfix()}return false},click_row:function(g,h){var c=new Date().getTime(),b=rcube_event.get_modifier(g),f=rcube_event.get_target(g),d=f.tagName.toLowerCase();if((f&&(d=="input"||d=="img"))){return true}if(this.dont_select){this.dont_select=false;return false}var a=c-this.rows[h].clicked<this.dblclick_time;if(!this.drag_active&&this.in_selection_before==h&&!a){this.select_row(h,b,false)}this.drag_start=false;this.in_selection_before=false;if(this.rows&&a&&this.in_selection(h)){this.triggerEvent("dblclick");c=0}else{this.triggerEvent("click")}if(!this.drag_active){this.del_dragfix();rcube_event.cancel(g)}this.rows[h].clicked=c;return false},find_root:function(a){var b=this.rows[a];if(b&&b.parent_uid){return this.find_root(b.parent_uid)}else{return a}},expand_row:function(c,f){var d=this.rows[f],b=rcube_event.get_target(c),a=rcube_event.get_modifier(c);this.dont_select=true;d.clicked=0;if(d.expanded){b.className="collapsed";if(a==CONTROL_KEY||this.multiexpand){this.collapse_all(d)}else{this.collapse(d)}}else{b.className="expanded";if(a==CONTROL_KEY||this.multiexpand){this.expand_all(d)}else{this.expand(d)}}},collapse:function(d){d.expanded=false;this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded,obj:d.obj});var c=d.depth;var a=d?d.obj.nextSibling:null;var b;while(a){if(a.nodeType==1){var b=this.rows[a.uid];if(b&&b.depth<=c){break}$(a).css("display","none");if(b.expanded){b.expanded=false;this.triggerEvent("expandcollapse",{uid:b.uid,expanded:b.expanded,obj:a})}}a=a.nextSibling}return false},expand:function(g){var d,e,f,b,a;if(g){g.expanded=true;f=g.depth;b=g.obj.nextSibling;this.update_expando(g.uid,true);this.triggerEvent("expandcollapse",{uid:g.uid,expanded:g.expanded,obj:g.obj})}else{var c=this.list.tBodies[0];b=c.firstChild;f=0;a=0}while(b){if(b.nodeType==1){d=this.rows[b.uid];if(d){if(g&&(!d.depth||d.depth<=f)){break}if(d.parent_uid){e=this.rows[d.parent_uid];if(e&&e.expanded){if((g&&e==g)||a>=e.depth-1){a=e.depth;$(b).css("display","");d.expanded=true;this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded,obj:b})}}else{if(g&&(!e||e.depth<=f)){break}}}}}b=b.nextSibling}return false},collapse_all:function(d){var c,a,b;if(d){d.expanded=false;c=d.depth;a=d.obj.nextSibling;this.update_expando(d.uid);this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded,obj:d.obj});if(c&&this.multiexpand){return false}}else{a=this.list.tBodies[0].firstChild;c=0}while(a){if(a.nodeType==1){if(b=this.rows[a.uid]){if(d&&(!b.depth||b.depth<=c)){break}if(d||b.depth){$(a).css("display","none")}if(b.has_children&&b.expanded){b.expanded=false;this.update_expando(b.uid,false);this.triggerEvent("expandcollapse",{uid:b.uid,expanded:b.expanded,obj:a})}}}a=a.nextSibling}return false},expand_all:function(d){var c,a,b;if(d){d.expanded=true;c=d.depth;a=d.obj.nextSibling;this.update_expando(d.uid,true);this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded,obj:d.obj})}else{a=this.list.tBodies[0].firstChild;c=0}while(a){if(a.nodeType==1){if(b=this.rows[a.uid]){if(d&&b.depth<=c){break}$(a).css("display","");if(b.has_children&&!b.expanded){b.expanded=true;this.update_expando(b.uid,true);this.triggerEvent("expandcollapse",{uid:b.uid,expanded:b.expanded,obj:a})}}}a=a.nextSibling}return false},update_expando:function(b,a){var c=document.getElementById("rcmexpando"+b);if(c){c.className=a?"expanded":"collapsed"}},get_next_row:function(){if(!this.rows){return false}var b=this.rows[this.last_selected],a=b?b.obj.nextSibling:null;while(a&&(a.nodeType!=1||a.style.display=="none")){a=a.nextSibling}return a},get_prev_row:function(){if(!this.rows){return false}var b=this.rows[this.last_selected],a=b?b.obj.previousSibling:null;while(a&&(a.nodeType!=1||a.style.display=="none")){a=a.previousSibling}return a},get_first_row:function(){if(this.rowcount){var b,a,c=this.list.tBodies[0].rows;for(b=0,a=c.length-1;b<a;b++){if(c[b].id&&String(c[b].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)&&this.rows[RegExp.$1]!=null){return RegExp.$1}}}return null},get_last_row:function(){if(this.rowcount){var a,b=this.list.tBodies[0].rows;for(a=b.length-1;a>=0;a--){if(b[a].id&&String(b[a].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)&&this.rows[RegExp.$1]!=null){return RegExp.$1}}}return null},select_row:function(d,a,c){var b=this.selection.join(",");if(!this.multiselect){a=0}if(!this.shift_start){this.shift_start=d}if(!a){this.shift_start=d;this.highlight_row(d,false);this.multi_selecting=false}else{switch(a){case SHIFT_KEY:this.shift_select(d,false);break;case CONTROL_KEY:if(!c){this.highlight_row(d,true)}break;case CONTROL_SHIFT_KEY:this.shift_select(d,true);break;default:this.highlight_row(d,false);break}this.multi_selecting=true}if(this.selection.join(",")!=b){this.triggerEvent("select")}if(this.last_selected!=0&&this.rows[this.last_selected]){$(this.rows[this.last_selected].obj).removeClass("focused")}if(this.toggleselect&&this.last_selected==d){this.clear_selection();d=null}else{$(this.rows[d].obj).addClass("focused")}if(!this.selection.length){this.shift_start=null}this.last_selected=d},select:function(a){this.select_row(a,false);this.scrollto(a)},select_next:function(){var b=this.get_next_row(),c=this.get_prev_row(),a=(b)?b:c;if(a){this.select_row(a.uid,false,false)}},select_first:function(a){var b=this.get_first_row();if(b){if(a){this.shift_select(b,a);this.triggerEvent("select");this.scrollto(b)}else{this.select(b)}}},select_last:function(a){var b=this.get_last_row();if(b){if(a){this.shift_select(b,a);this.triggerEvent("select");this.scrollto(b)}else{this.select(b)}}},select_children:function(d){var c,b=this.row_children(d),a=b.length;for(c=0;c<a;c++){if(!this.in_selection(b[c])){this.select_row(b[c],CONTROL_KEY)}}},shift_select:function(h,f){if(!this.rows[this.shift_start]||!this.selection.length){this.shift_start=h}var g,d,c,a=this.rows[h],e=this.rows[this.shift_start].obj.rowIndex,b=a.obj.rowIndex;if(!a.expanded&&a.has_children){if(a=this.rows[(this.row_children(h)).pop()]){b=a.obj.rowIndex}}d=((e<b)?e:b),c=((e>b)?e:b);for(g in this.rows){if(this.rows[g].obj.rowIndex>=d&&this.rows[g].obj.rowIndex<=c){if(!this.in_selection(g)){this.highlight_row(g,true)}}else{if(this.in_selection(g)&&!f){this.highlight_row(g,true)}}}},in_selection:function(b){for(var a in this.selection){if(this.selection[a]==b){return true}}return false},select_all:function(b){if(!this.rows||!this.rows.length){return false}var c,a=this.selection.join(",");this.selection=[];for(c in this.rows){if(!b||this.rows[c][b]==true){this.last_selected=c;this.highlight_row(c,true,true)}else{$(this.rows[c].obj).removeClass("selected").removeClass("unfocused")}}if(this.selection.join(",")!=a){this.triggerEvent("select")}this.focus();return true},invert_selection:function(){if(!this.rows||!this.rows.length){return false}var b,a=this.selection.join(",");for(b in this.rows){this.highlight_row(b,true)}if(this.selection.join(",")!=a){this.triggerEvent("select")}this.focus();return true},clear_selection:function(c){var b,a=this.selection.length;if(c){for(b in this.selection){if(this.selection[b]==c){this.selection.splice(b,1);break}}}else{for(b in this.selection){if(this.rows[this.selection[b]]){$(this.rows[this.selection[b]].obj).removeClass("selected").removeClass("unfocused")}}this.selection=[]}if(a&&!this.selection.length){this.triggerEvent("select")}},get_selection:function(){return this.selection},get_single_selection:function(){if(this.selection.length==1){return this.selection[0]}else{return null}},highlight_row:function(f,a,e){if(!this.rows[f]){return}if(!a){if(this.selection.length>1||!this.in_selection(f)){this.clear_selection();this.selection[0]=f;$(this.rows[f].obj).addClass("selected")}}else{if(!this.in_selection(f)){this.selection.push(f);$(this.rows[f].obj).addClass("selected");if(!e&&!this.rows[f].expanded){this.highlight_children(f,true)}}else{var d=$.inArray(f,this.selection),c=this.selection.slice(0,d),b=this.selection.slice(d+1,this.selection.length);this.selection=c.concat(b);$(this.rows[f].obj).removeClass("selected").removeClass("unfocused");if(!e&&!this.rows[f].expanded){this.highlight_children(f,false)}}}},highlight_children:function(f,b){var d,e,c=this.row_children(f),a=c.length;for(d=0;d<a;d++){e=this.in_selection(c[d]);if((b&&!e)||(!b&&e)){this.highlight_row(c[d],true,true)}}},key_press:function(f){var d=f.target||{};if(this.focused!=true||d.nodeName=="INPUT"||d.nodeName=="TEXTAREA"||d.nodeName=="SELECT"){return true}var c=rcube_event.get_keycode(f),a=rcube_event.get_modifier(f);switch(c){case 40:case 38:case 63233:case 63232:rcube_event.cancel(f);return this.use_arrow_key(c,a);case 61:case 107:case 109:case 32:rcube_event.cancel(f);var b=this.use_plusminus_key(c,a);this.key_pressed=c;this.modkey=a;this.triggerEvent("keypress");this.modkey=0;return b;case 36:this.select_first(a);return rcube_event.cancel(f);case 35:this.select_last(a);return rcube_event.cancel(f);case 27:if(this.drag_active){return this.drag_mouse_up(f)}if(this.col_drag_active){this.selected_column=null;return this.column_drag_mouse_up(f)}return rcube_event.cancel(f);default:this.key_pressed=c;this.modkey=a;this.triggerEvent("keypress");this.modkey=0;if(this.key_pressed==this.BACKSPACE_KEY){return rcube_event.cancel(f)}}return true},use_arrow_key:function(c,b){var a;if(c==40||c==63233){a=this.get_next_row()}else{if(c==38||c==63232){a=this.get_prev_row()}}if(a){this.select_row(a.uid,b,false);this.scrollto(a.uid)}return false},use_plusminus_key:function(c,a){var b=this.rows[this.last_selected];if(!b){return}if(c==32){c=b.expanded?109:61}if(c==61||c==107){if(a==CONTROL_KEY||this.multiexpand){this.expand_all(b)}else{this.expand(b)}}else{if(a==CONTROL_KEY||this.multiexpand){this.collapse_all(b)}else{this.collapse(b)}}this.update_expando(b.uid,b.expanded);return false},scrollto:function(d){var c=this.rows[d].obj;if(c&&this.frame){var b=Number(c.offsetTop);if(!b&&this.rows[d].parent_uid){var a=this.find_root(this.rows[d].uid);this.expand_all(this.rows[a]);b=Number(c.offsetTop)}if(b<Number(this.frame.scrollTop)){this.frame.scrollTop=b}else{if(b+Number(c.offsetHeight)>Number(this.frame.scrollTop)+Number(this.frame.offsetHeight)){this.frame.scrollTop=(b+Number(c.offsetHeight))-Number(this.frame.offsetHeight)}}}},drag_mouse_move:function(l){if(l.type=="touchmove"){if(l.touches.length==1&&l.changedTouches.length==1){l=rcube_event.touchevent(l.changedTouches[0])}else{return rcube_event.cancel(l)}}if(this.drag_start){var f=rcube_event.get_mouse_pos(l);if(!this.drag_mouse_start||(Math.abs(f.x-this.drag_mouse_start.x)<3&&Math.abs(f.y-this.drag_mouse_start.y)<3)){return false}if(!this.draglayer){this.draglayer=$("<div>").attr("id","rcmdraglayer").css({position:"absolute",display:"none","z-index":2000}).appendTo(document.body)}var b,j,t=$.merge([],this.selection);for(b in t){j=t[b];if(!this.rows[j].expanded){this.select_children(j)}}this.draglayer.html("");var o,h,b,p,g;for(b=0;b<this.selection.length;b++){if(b>12){this.draglayer.append("...");break}if(g=this.rows[this.selection[b]].obj){p="";for(o=0,h=0;h<g.childNodes.length;h++){if(g.childNodes[h].nodeName=="TD"){if(b==0){this.drag_start_pos=$(g.childNodes[h]).offset()}if(this.subject_col<0||(this.subject_col>=0&&this.subject_col==o)){var s,d,k,a=g.childNodes[h].childNodes;for(f=0;f<a.length;f++){if((k=g.childNodes[h].childNodes[f])&&(k.nodeType==3||k.nodeName=="A")){d=k}}if(!d){break}p=$(d).text();p=$.trim(p);p=(p.length>50?p.substring(0,50)+"...":p);s=$("<div>").text(p);this.draglayer.append(s);break}o++}}}}this.draglayer.show();this.drag_active=true;this.triggerEvent("dragstart")}if(this.drag_active&&this.draglayer){var q=rcube_event.get_mouse_pos(l);this.draglayer.css({left:(q.x+20)+"px",top:(q.y-5+(bw.ie?document.documentElement.scrollTop:0))+"px"});this.triggerEvent("dragmove",l?l:window.event)}this.drag_start=false;return false},drag_mouse_up:function(a){document.onmousemove=null;if(a.type=="touchend"){if(a.changedTouches.length!=1){return rcube_event.cancel(a)}}if(this.draglayer&&this.draglayer.is(":visible")){if(this.drag_start_pos){this.draglayer.animate(this.drag_start_pos,300,"swing").hide(20)}else{this.draglayer.hide()}}if(this.drag_active){this.focus()}this.drag_active=false;rcube_event.remove_listener({event:"mousemove",object:this,method:"drag_mouse_move"});rcube_event.remove_listener({event:"mouseup",object:this,method:"drag_mouse_up"});if(bw.touch){rcube_event.remove_listener({event:"touchmove",object:this,method:"drag_mouse_move"});rcube_event.remove_listener({event:"touchend",object:this,method:"drag_mouse_up"})}this.del_dragfix();this.triggerEvent("dragend");return rcube_event.cancel(a)},column_drag_mouse_move:function(f){if(this.drag_start){var c,a=rcube_event.get_mouse_pos(f);if(!this.drag_mouse_start||(Math.abs(a.x-this.drag_mouse_start.x)<3&&Math.abs(a.y-this.drag_mouse_start.y)<3)){return false}if(!this.col_draglayer){var d=$(this.list).offset(),b=this.list.tHead.rows[0].cells;this.col_draglayer=$("<div>").attr("id","rcmcoldraglayer").css(d).css({position:"absolute","z-index":2001,"background-color":"white",opacity:0.75,height:(this.frame.offsetHeight-2)+"px",width:(this.frame.offsetWidth-2)+"px"}).appendTo(document.body).append($("<div>").attr("id","rcmcolumnindicator").css({position:"absolute","border-right":"2px dotted #555","z-index":2002,height:(this.frame.offsetHeight-2)+"px"}));this.cols=[];this.list_pos=this.list_min_pos=d.left;for(c=0;c<b.length;c++){this.cols[c]=b[c].offsetWidth;if(this.column_fixed!==null&&c<=this.column_fixed){this.list_min_pos+=this.cols[c]}}}this.col_draglayer.show();this.col_drag_active=true;this.triggerEvent("column_dragstart")}if(this.col_drag_active&&this.col_draglayer){var c,h=0,g=rcube_event.get_mouse_pos(f);for(c=0;c<this.cols.length;c++){if(g.x>=this.cols[c]/2+this.list_pos+h){h+=this.cols[c]}else{break}}if(c==0&&this.list_min_pos>g.x){h=this.list_min_pos-this.list_pos}else{if(!this.list.rowcount&&c==this.cols.length){h-=2}}$("#rcmcolumnindicator").css({width:h+"px"});this.triggerEvent("column_dragmove",f?f:window.event)}this.drag_start=false;return false},column_drag_mouse_up:function(b){document.onmousemove=null;if(this.col_draglayer){(this.col_draglayer).remove();this.col_draglayer=null}if(this.col_drag_active){this.focus()}this.col_drag_active=false;rcube_event.remove_listener({event:"mousemove",object:this,method:"column_drag_mouse_move"});rcube_event.remove_listener({event:"mouseup",object:this,method:"column_drag_mouse_up"});this.del_dragfix();if(this.selected_column!==null&&this.cols&&this.cols.length){var a,d=0,c=rcube_event.get_mouse_pos(b);for(a=0;a<this.cols.length;a++){if(c.x>=this.cols[a]/2+this.list_pos+d){d+=this.cols[a]}else{break}}if(a!=this.selected_column&&a!=this.selected_column+1){this.column_replace(this.selected_column,a)}}this.triggerEvent("column_dragend");return rcube_event.cancel(b)},row_children:function(b){if(!this.rows[b]||!this.rows[b].has_children){return[]}var a=[],d=this.rows[b].depth,c=this.rows[b].obj.nextSibling;while(c){if(c.nodeType==1){if((r=this.rows[c.uid])){if(!r.depth||r.depth<=d){break}a.push(r.uid)}}c=c.nextSibling}return a},add_dragfix:function(){$("iframe").each(function(){$('<div class="iframe-dragdrop-fix"></div>').css({background:"#fff",width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css($(this).offset()).appendTo(document.body)})},del_dragfix:function(){$("div.iframe-dragdrop-fix").each(function(){this.parentNode.removeChild(this)})},column_replace:function(g,f){var a,b=this.list.tHead.rows[0].cells,c=b[g],d=b[f],e=document.createElement("td");if(d){b[0].parentNode.insertBefore(e,d)}else{b[0].parentNode.appendChild(e)}b[0].parentNode.replaceChild(c,e);for(r=0,a=this.list.tBodies[0].rows.length;r<a;r++){row=this.list.tBodies[0].rows[r];c=row.cells[g];d=row.cells[f];e=document.createElement("td");if(d){row.insertBefore(e,d)}else{row.appendChild(e)}row.replaceChild(c,e)}if(this.subject_col==g){this.subject_col=f>g?f-1:f}else{if(this.subject_col<g&&f<=this.subject_col){this.subject_col++}else{if(this.subject_col>g&&f>=this.subject_col){this.subject_col--}}}this.triggerEvent("column_replace")}};rcube_list_widget.prototype.addEventListener=rcube_event_engine.prototype.addEventListener;rcube_list_widget.prototype.removeEventListener=rcube_event_engine.prototype.removeEventListener;rcube_list_widget.prototype.triggerEvent=rcube_event_engine.prototype.triggerEvent;
\ No newline at end of file diff --git a/program/lib/Crypt/GPG.php b/program/lib/Crypt/GPG.php new file mode 100644 index 000000000..6e8e717e8 --- /dev/null +++ b/program/lib/Crypt/GPG.php @@ -0,0 +1,2542 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Crypt_GPG is a package to use GPG from PHP + * + * This package provides an object oriented interface to GNU Privacy + * Guard (GPG). It requires the GPG executable to be on the system. + * + * Though GPG can support symmetric-key cryptography, this package is intended + * only to facilitate public-key cryptography. + * + * This file contains the main GPG class. The class in this file lets you + * encrypt, decrypt, sign and verify data; import and delete keys; and perform + * other useful GPG tasks. + * + * Example usage: + * <code> + * <?php + * // encrypt some data + * $gpg = new Crypt_GPG(); + * $gpg->addEncryptKey($mySecretKeyId); + * $encryptedData = $gpg->encrypt($data); + * ?> + * </code> + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: GPG.php 302814 2010-08-26 15:43:07Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php + * @link http://www.gnupg.org/ + */ + +/** + * Signature handler class + */ +require_once 'Crypt/GPG/VerifyStatusHandler.php'; + +/** + * Decryption handler class + */ +require_once 'Crypt/GPG/DecryptStatusHandler.php'; + +/** + * GPG key class + */ +require_once 'Crypt/GPG/Key.php'; + +/** + * GPG sub-key class + */ +require_once 'Crypt/GPG/SubKey.php'; + +/** + * GPG user id class + */ +require_once 'Crypt/GPG/UserId.php'; + +/** + * GPG process and I/O engine class + */ +require_once 'Crypt/GPG/Engine.php'; + +/** + * GPG exception classes + */ +require_once 'Crypt/GPG/Exceptions.php'; + +// {{{ class Crypt_GPG + +/** + * A class to use GPG from PHP + * + * This class provides an object oriented interface to GNU Privacy Guard (GPG). + * + * Though GPG can support symmetric-key cryptography, this class is intended + * only to facilitate public-key cryptography. + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ +class Crypt_GPG +{ + // {{{ class error constants + + /** + * Error code returned when there is no error. + */ + const ERROR_NONE = 0; + + /** + * Error code returned when an unknown or unhandled error occurs. + */ + const ERROR_UNKNOWN = 1; + + /** + * Error code returned when a bad passphrase is used. + */ + const ERROR_BAD_PASSPHRASE = 2; + + /** + * Error code returned when a required passphrase is missing. + */ + const ERROR_MISSING_PASSPHRASE = 3; + + /** + * Error code returned when a key that is already in the keyring is + * imported. + */ + const ERROR_DUPLICATE_KEY = 4; + + /** + * Error code returned the required data is missing for an operation. + * + * This could be missing key data, missing encrypted data or missing + * signature data. + */ + const ERROR_NO_DATA = 5; + + /** + * Error code returned when an unsigned key is used. + */ + const ERROR_UNSIGNED_KEY = 6; + + /** + * Error code returned when a key that is not self-signed is used. + */ + const ERROR_NOT_SELF_SIGNED = 7; + + /** + * Error code returned when a public or private key that is not in the + * keyring is used. + */ + const ERROR_KEY_NOT_FOUND = 8; + + /** + * Error code returned when an attempt to delete public key having a + * private key is made. + */ + const ERROR_DELETE_PRIVATE_KEY = 9; + + /** + * Error code returned when one or more bad signatures are detected. + */ + const ERROR_BAD_SIGNATURE = 10; + + /** + * Error code returned when there is a problem reading GnuPG data files. + */ + const ERROR_FILE_PERMISSIONS = 11; + + // }}} + // {{{ class constants for data signing modes + + /** + * Signing mode for normal signing of data. The signed message will not + * be readable without special software. + * + * This is the default signing mode. + * + * @see Crypt_GPG::sign() + * @see Crypt_GPG::signFile() + */ + const SIGN_MODE_NORMAL = 1; + + /** + * Signing mode for clearsigning data. Clearsigned signatures are ASCII + * armored data and are readable without special software. If the signed + * message is unencrypted, the message will still be readable. The message + * text will be in the original encoding. + * + * @see Crypt_GPG::sign() + * @see Crypt_GPG::signFile() + */ + const SIGN_MODE_CLEAR = 2; + + /** + * Signing mode for creating a detached signature. When using detached + * signatures, only the signature data is returned. The original message + * text may be distributed separately from the signature data. This is + * useful for miltipart/signed email messages as per + * {@link http://www.ietf.org/rfc/rfc3156.txt RFC 3156}. + * + * @see Crypt_GPG::sign() + * @see Crypt_GPG::signFile() + */ + const SIGN_MODE_DETACHED = 3; + + // }}} + // {{{ class constants for fingerprint formats + + /** + * No formatting is performed. + * + * Example: C3BC615AD9C766E5A85C1F2716D27458B1BBA1C4 + * + * @see Crypt_GPG::getFingerprint() + */ + const FORMAT_NONE = 1; + + /** + * Fingerprint is formatted in the format used by the GnuPG gpg command's + * default output. + * + * Example: C3BC 615A D9C7 66E5 A85C 1F27 16D2 7458 B1BB A1C4 + * + * @see Crypt_GPG::getFingerprint() + */ + const FORMAT_CANONICAL = 2; + + /** + * Fingerprint is formatted in the format used when displaying X.509 + * certificates + * + * Example: C3:BC:61:5A:D9:C7:66:E5:A8:5C:1F:27:16:D2:74:58:B1:BB:A1:C4 + * + * @see Crypt_GPG::getFingerprint() + */ + const FORMAT_X509 = 3; + + // }}} + // {{{ other class constants + + /** + * URI at which package bugs may be reported. + */ + const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'; + + // }}} + // {{{ protected class properties + + /** + * Engine used to control the GPG subprocess + * + * @var Crypt_GPG_Engine + * + * @see Crypt_GPG::setEngine() + */ + protected $engine = null; + + /** + * Keys used to encrypt + * + * The array is of the form: + * <code> + * array( + * $key_id => array( + * 'fingerprint' => $fingerprint, + * 'passphrase' => null + * ) + * ); + * </code> + * + * @var array + * @see Crypt_GPG::addEncryptKey() + * @see Crypt_GPG::clearEncryptKeys() + */ + protected $encryptKeys = array(); + + /** + * Keys used to decrypt + * + * The array is of the form: + * <code> + * array( + * $key_id => array( + * 'fingerprint' => $fingerprint, + * 'passphrase' => $passphrase + * ) + * ); + * </code> + * + * @var array + * @see Crypt_GPG::addSignKey() + * @see Crypt_GPG::clearSignKeys() + */ + protected $signKeys = array(); + + /** + * Keys used to sign + * + * The array is of the form: + * <code> + * array( + * $key_id => array( + * 'fingerprint' => $fingerprint, + * 'passphrase' => $passphrase + * ) + * ); + * </code> + * + * @var array + * @see Crypt_GPG::addDecryptKey() + * @see Crypt_GPG::clearDecryptKeys() + */ + protected $decryptKeys = array(); + + // }}} + // {{{ __construct() + + /** + * Creates a new GPG object + * + * Available options are: + * + * - <kbd>string homedir</kbd> - the directory where the GPG + * keyring files are stored. If not + * specified, Crypt_GPG uses the + * default of <kbd>~/.gnupg</kbd>. + * - <kbd>string publicKeyring</kbd> - the file path of the public + * keyring. Use this if the public + * keyring is not in the homedir, or + * if the keyring is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * keyring with this option + * (/foo/bar/pubring.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string privateKeyring</kbd> - the file path of the private + * keyring. Use this if the private + * keyring is not in the homedir, or + * if the keyring is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * keyring with this option + * (/foo/bar/secring.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string trustDb</kbd> - the file path of the web-of-trust + * database. Use this if the trust + * database is not in the homedir, or + * if the database is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * trust database with this option + * (/foo/bar/trustdb.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string binary</kbd> - the location of the GPG binary. If + * not specified, the driver attempts + * to auto-detect the GPG binary + * location using a list of known + * default locations for the current + * operating system. The option + * <kbd>gpgBinary</kbd> is a + * deprecated alias for this option. + * - <kbd>boolean debug</kbd> - whether or not to use debug mode. + * When debug mode is on, all + * communication to and from the GPG + * subprocess is logged. This can be + * + * @param array $options optional. An array of options used to create the + * GPG object. All options are optional and are + * represented as key-value pairs. + * + * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist + * and cannot be created. This can happen if <kbd>homedir</kbd> is + * not specified, Crypt_GPG is run as the web user, and the web + * user has no home directory. This exception is also thrown if any + * of the options <kbd>publicKeyring</kbd>, + * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are + * specified but the files do not exist or are are not readable. + * This can happen if the user running the Crypt_GPG process (for + * example, the Apache user) does not have permission to read the + * files. + * + * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or + * if no <kbd>binary</kbd> is provided and no suitable binary could + * be found. + */ + public function __construct(array $options = array()) + { + $this->setEngine(new Crypt_GPG_Engine($options)); + } + + // }}} + // {{{ importKey() + + /** + * Imports a public or private key into the keyring + * + * Keys may be removed from the keyring using + * {@link Crypt_GPG::deletePublicKey()} or + * {@link Crypt_GPG::deletePrivateKey()}. + * + * @param string $data the key data to be imported. + * + * @return array an associative array containing the following elements: + * - <kbd>fingerprint</kbd> - the fingerprint of the + * imported key, + * - <kbd>public_imported</kbd> - the number of public + * keys imported, + * - <kbd>public_unchanged</kbd> - the number of unchanged + * public keys, + * - <kbd>private_imported</kbd> - the number of private + * keys imported, + * - <kbd>private_unchanged</kbd> - the number of unchanged + * private keys. + * + * @throws Crypt_GPG_NoDataException if the key data is missing or if the + * data is is not valid key data. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function importKey($data) + { + return $this->_importKey($data, false); + } + + // }}} + // {{{ importKeyFile() + + /** + * Imports a public or private key file into the keyring + * + * Keys may be removed from the keyring using + * {@link Crypt_GPG::deletePublicKey()} or + * {@link Crypt_GPG::deletePrivateKey()}. + * + * @param string $filename the key file to be imported. + * + * @return array an associative array containing the following elements: + * - <kbd>fingerprint</kbd> - the fingerprint of the + * imported key, + * - <kbd>public_imported</kbd> - the number of public + * keys imported, + * - <kbd>public_unchanged</kbd> - the number of unchanged + * public keys, + * - <kbd>private_imported</kbd> - the number of private + * keys imported, + * - <kbd>private_unchanged</kbd> - the number of unchanged + * private keys. + * private keys. + * + * @throws Crypt_GPG_NoDataException if the key data is missing or if the + * data is is not valid key data. + * + * @throws Crypt_GPG_FileException if the key file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function importKeyFile($filename) + { + return $this->_importKey($filename, true); + } + + // }}} + // {{{ exportPublicKey() + + /** + * Exports a public key from the keyring + * + * The exported key remains on the keyring. To delete the public key, use + * {@link Crypt_GPG::deletePublicKey()}. + * + * If more than one key fingerprint is available for the specified + * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the + * first public key is exported. + * + * @param string $keyId either the full uid of the public key, the email + * part of the uid of the public key or the key id of + * the public key. For example, + * "Test User (example) <test@example.com>", + * "test@example.com" or a hexadecimal string. + * @param boolean $armor optional. If true, ASCII armored data is returned; + * otherwise, binary data is returned. Defaults to + * true. + * + * @return string the public key data. + * + * @throws Crypt_GPG_KeyNotFoundException if a public key with the given + * <kbd>$keyId</kbd> is not found. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function exportPublicKey($keyId, $armor = true) + { + $fingerprint = $this->getFingerprint($keyId); + + if ($fingerprint === null) { + throw new Crypt_GPG_KeyNotFoundException( + 'Public key not found: ' . $keyId, + Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); + } + + $keyData = ''; + $operation = '--export ' . escapeshellarg($fingerprint); + $arguments = ($armor) ? array('--armor') : array(); + + $this->engine->reset(); + $this->engine->setOutput($keyData); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + if ($code !== Crypt_GPG::ERROR_NONE) { + throw new Crypt_GPG_Exception( + 'Unknown error exporting public key. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + + return $keyData; + } + + // }}} + // {{{ deletePublicKey() + + /** + * Deletes a public key from the keyring + * + * If more than one key fingerprint is available for the specified + * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the + * first public key is deleted. + * + * The private key must be deleted first or an exception will be thrown. + * See {@link Crypt_GPG::deletePrivateKey()}. + * + * @param string $keyId either the full uid of the public key, the email + * part of the uid of the public key or the key id of + * the public key. For example, + * "Test User (example) <test@example.com>", + * "test@example.com" or a hexadecimal string. + * + * @return void + * + * @throws Crypt_GPG_KeyNotFoundException if a public key with the given + * <kbd>$keyId</kbd> is not found. + * + * @throws Crypt_GPG_DeletePrivateKeyException if the specified public key + * has an associated private key on the keyring. The private key + * must be deleted first. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function deletePublicKey($keyId) + { + $fingerprint = $this->getFingerprint($keyId); + + if ($fingerprint === null) { + throw new Crypt_GPG_KeyNotFoundException( + 'Public key not found: ' . $keyId, + Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); + } + + $operation = '--delete-key ' . escapeshellarg($fingerprint); + $arguments = array( + '--batch', + '--yes' + ); + + $this->engine->reset(); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + break; + case Crypt_GPG::ERROR_DELETE_PRIVATE_KEY: + throw new Crypt_GPG_DeletePrivateKeyException( + 'Private key must be deleted before public key can be ' . + 'deleted.', $code, $keyId); + default: + throw new Crypt_GPG_Exception( + 'Unknown error deleting public key. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + } + + // }}} + // {{{ deletePrivateKey() + + /** + * Deletes a private key from the keyring + * + * If more than one key fingerprint is available for the specified + * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the + * first private key is deleted. + * + * Calls GPG with the <kbd>--delete-secret-key</kbd> command. + * + * @param string $keyId either the full uid of the private key, the email + * part of the uid of the private key or the key id of + * the private key. For example, + * "Test User (example) <test@example.com>", + * "test@example.com" or a hexadecimal string. + * + * @return void + * + * @throws Crypt_GPG_KeyNotFoundException if a private key with the given + * <kbd>$keyId</kbd> is not found. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function deletePrivateKey($keyId) + { + $fingerprint = $this->getFingerprint($keyId); + + if ($fingerprint === null) { + throw new Crypt_GPG_KeyNotFoundException( + 'Private key not found: ' . $keyId, + Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); + } + + $operation = '--delete-secret-key ' . escapeshellarg($fingerprint); + $arguments = array( + '--batch', + '--yes' + ); + + $this->engine->reset(); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + break; + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + throw new Crypt_GPG_KeyNotFoundException( + 'Private key not found: ' . $keyId, + $code, $keyId); + default: + throw new Crypt_GPG_Exception( + 'Unknown error deleting private key. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + } + + // }}} + // {{{ getKeys() + + /** + * Gets the available keys in the keyring + * + * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See + * the first section of <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG package} for a detailed + * description of how the GPG command output is parsed. + * + * @param string $keyId optional. Only keys with that match the specified + * pattern are returned. The pattern may be part of + * a user id, a key id or a key fingerprint. If not + * specified, all keys are returned. + * + * @return array an array of {@link Crypt_GPG_Key} objects. If no keys + * match the specified <kbd>$keyId</kbd> an empty array is + * returned. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG_Key + */ + public function getKeys($keyId = '') + { + // get private key fingerprints + if ($keyId == '') { + $operation = '--list-secret-keys'; + } else { + $operation = '--list-secret-keys ' . escapeshellarg($keyId); + } + + // According to The file 'doc/DETAILS' in the GnuPG distribution, using + // double '--with-fingerprint' also prints the fingerprint for subkeys. + $arguments = array( + '--with-colons', + '--with-fingerprint', + '--with-fingerprint', + '--fixed-list-mode' + ); + + $output = ''; + + $this->engine->reset(); + $this->engine->setOutput($output); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + // ignore not found key errors + break; + case Crypt_GPG::ERROR_FILE_PERMISSIONS: + $filename = $this->engine->getErrorFilename(); + if ($filename) { + throw new Crypt_GPG_FileException(sprintf( + 'Error reading GnuPG data file \'%s\'. Check to make ' . + 'sure it is readable by the current user.', $filename), + $code, $filename); + } + throw new Crypt_GPG_FileException( + 'Error reading GnuPG data file. Check to make GnuPG data ' . + 'files are readable by the current user.', $code); + default: + throw new Crypt_GPG_Exception( + 'Unknown error getting keys. Please use the \'debug\' option ' . + 'when creating the Crypt_GPG object, and file a bug report ' . + 'at ' . self::BUG_URI, $code); + } + + $privateKeyFingerprints = array(); + + $lines = explode(PHP_EOL, $output); + foreach ($lines as $line) { + $lineExp = explode(':', $line); + if ($lineExp[0] == 'fpr') { + $privateKeyFingerprints[] = $lineExp[9]; + } + } + + // get public keys + if ($keyId == '') { + $operation = '--list-public-keys'; + } else { + $operation = '--list-public-keys ' . escapeshellarg($keyId); + } + + $output = ''; + + $this->engine->reset(); + $this->engine->setOutput($output); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + // ignore not found key errors + break; + case Crypt_GPG::ERROR_FILE_PERMISSIONS: + $filename = $this->engine->getErrorFilename(); + if ($filename) { + throw new Crypt_GPG_FileException(sprintf( + 'Error reading GnuPG data file \'%s\'. Check to make ' . + 'sure it is readable by the current user.', $filename), + $code, $filename); + } + throw new Crypt_GPG_FileException( + 'Error reading GnuPG data file. Check to make GnuPG data ' . + 'files are readable by the current user.', $code); + default: + throw new Crypt_GPG_Exception( + 'Unknown error getting keys. Please use the \'debug\' option ' . + 'when creating the Crypt_GPG object, and file a bug report ' . + 'at ' . self::BUG_URI, $code); + } + + $keys = array(); + + $key = null; // current key + $subKey = null; // current sub-key + + $lines = explode(PHP_EOL, $output); + foreach ($lines as $line) { + $lineExp = explode(':', $line); + + if ($lineExp[0] == 'pub') { + + // new primary key means last key should be added to the array + if ($key !== null) { + $keys[] = $key; + } + + $key = new Crypt_GPG_Key(); + + $subKey = Crypt_GPG_SubKey::parse($line); + $key->addSubKey($subKey); + + } elseif ($lineExp[0] == 'sub') { + + $subKey = Crypt_GPG_SubKey::parse($line); + $key->addSubKey($subKey); + + } elseif ($lineExp[0] == 'fpr') { + + $fingerprint = $lineExp[9]; + + // set current sub-key fingerprint + $subKey->setFingerprint($fingerprint); + + // if private key exists, set has private to true + if (in_array($fingerprint, $privateKeyFingerprints)) { + $subKey->setHasPrivate(true); + } + + } elseif ($lineExp[0] == 'uid') { + + $string = stripcslashes($lineExp[9]); // as per documentation + $userId = new Crypt_GPG_UserId($string); + + if ($lineExp[1] == 'r') { + $userId->setRevoked(true); + } + + $key->addUserId($userId); + + } + } + + // add last key + if ($key !== null) { + $keys[] = $key; + } + + return $keys; + } + + // }}} + // {{{ getFingerprint() + + /** + * Gets a key fingerprint from the keyring + * + * If more than one key fingerprint is available (for example, if you use + * a non-unique user id) only the first key fingerprint is returned. + * + * Calls the GPG <kbd>--list-keys</kbd> command with the + * <kbd>--with-fingerprint</kbd> option to retrieve a public key + * fingerprint. + * + * @param string $keyId either the full user id of the key, the email + * part of the user id of the key, or the key id of + * the key. For example, + * "Test User (example) <test@example.com>", + * "test@example.com" or a hexadecimal string. + * @param integer $format optional. How the fingerprint should be formatted. + * Use {@link Crypt_GPG::FORMAT_X509} for X.509 + * certificate format, + * {@link Crypt_GPG::FORMAT_CANONICAL} for the format + * used by GnuPG output and + * {@link Crypt_GPG::FORMAT_NONE} for no formatting. + * Defaults to <code>Crypt_GPG::FORMAT_NONE</code>. + * + * @return string the fingerprint of the key, or null if no fingerprint + * is found for the given <kbd>$keyId</kbd>. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function getFingerprint($keyId, $format = Crypt_GPG::FORMAT_NONE) + { + $output = ''; + $operation = '--list-keys ' . escapeshellarg($keyId); + $arguments = array( + '--with-colons', + '--with-fingerprint' + ); + + $this->engine->reset(); + $this->engine->setOutput($output); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + // ignore not found key errors + break; + default: + throw new Crypt_GPG_Exception( + 'Unknown error getting key fingerprint. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + + $fingerprint = null; + + $lines = explode(PHP_EOL, $output); + foreach ($lines as $line) { + if (substr($line, 0, 3) == 'fpr') { + $lineExp = explode(':', $line); + $fingerprint = $lineExp[9]; + + switch ($format) { + case Crypt_GPG::FORMAT_CANONICAL: + $fingerprintExp = str_split($fingerprint, 4); + $format = '%s %s %s %s %s %s %s %s %s %s'; + $fingerprint = vsprintf($format, $fingerprintExp); + break; + + case Crypt_GPG::FORMAT_X509: + $fingerprintExp = str_split($fingerprint, 2); + $fingerprint = implode(':', $fingerprintExp); + break; + } + + break; + } + } + + return $fingerprint; + } + + // }}} + // {{{ encrypt() + + /** + * Encrypts string data + * + * Data is ASCII armored by default but may optionally be returned as + * binary. + * + * @param string $data the data to be encrypted. + * @param boolean $armor optional. If true, ASCII armored data is returned; + * otherwise, binary data is returned. Defaults to + * true. + * + * @return string the encrypted data. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. + * See {@link Crypt_GPG::addEncryptKey()}. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @sensitive $data + */ + public function encrypt($data, $armor = true) + { + return $this->_encrypt($data, false, null, $armor); + } + + // }}} + // {{{ encryptFile() + + /** + * Encrypts a file + * + * Encrypted data is ASCII armored by default but may optionally be saved + * as binary. + * + * @param string $filename the filename of the file to encrypt. + * @param string $encryptedFile optional. The filename of the file in + * which to store the encrypted data. If null + * or unspecified, the encrypted data is + * returned as a string. + * @param boolean $armor optional. If true, ASCII armored data is + * returned; otherwise, binary data is + * returned. Defaults to true. + * + * @return void|string if the <kbd>$encryptedFile</kbd> parameter is null, + * a string containing the encrypted data is returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. + * See {@link Crypt_GPG::addEncryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function encryptFile($filename, $encryptedFile = null, $armor = true) + { + return $this->_encrypt($filename, true, $encryptedFile, $armor); + } + + // }}} + // {{{ encryptAndSign() + + /** + * Encrypts and signs data + * + * Data is encrypted and signed in a single pass. + * + * NOTE: Until GnuPG version 1.4.10, it was not possible to verify + * encrypted-signed data without decrypting it at the same time. If you try + * to use {@link Crypt_GPG::verify()} method on encrypted-signed data with + * earlier GnuPG versions, you will get an error. Please use + * {@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data. + * + * @param string $data the data to be encrypted and signed. + * @param boolean $armor optional. If true, ASCII armored data is returned; + * otherwise, binary data is returned. Defaults to + * true. + * + * @return string the encrypted signed data. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified + * or if no signing key is specified. See + * {@link Crypt_GPG::addEncryptKey()} and + * {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG::decryptAndVerify() + */ + public function encryptAndSign($data, $armor = true) + { + return $this->_encryptAndSign($data, false, null, $armor); + } + + // }}} + // {{{ encryptAndSignFile() + + /** + * Encrypts and signs a file + * + * The file is encrypted and signed in a single pass. + * + * NOTE: Until GnuPG version 1.4.10, it was not possible to verify + * encrypted-signed files without decrypting them at the same time. If you + * try to use {@link Crypt_GPG::verify()} method on encrypted-signed files + * with earlier GnuPG versions, you will get an error. Please use + * {@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed + * files. + * + * @param string $filename the name of the file containing the data to + * be encrypted and signed. + * @param string $signedFile optional. The name of the file in which the + * encrypted, signed data should be stored. If + * null or unspecified, the encrypted, signed + * data is returned as a string. + * @param boolean $armor optional. If true, ASCII armored data is + * returned; otherwise, binary data is returned. + * Defaults to true. + * + * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a + * string containing the encrypted, signed data is + * returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified + * or if no signing key is specified. See + * {@link Crypt_GPG::addEncryptKey()} and + * {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG::decryptAndVerifyFile() + */ + public function encryptAndSignFile($filename, $signedFile = null, + $armor = true + ) { + return $this->_encryptAndSign($filename, true, $signedFile, $armor); + } + + // }}} + // {{{ decrypt() + + /** + * Decrypts string data + * + * This method assumes the required private key is available in the keyring + * and throws an exception if the private key is not available. To add a + * private key to the keyring, use the {@link Crypt_GPG::importKey()} or + * {@link Crypt_GPG::importKeyFile()} methods. + * + * @param string $encryptedData the data to be decrypted. + * + * @return string the decrypted data. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function decrypt($encryptedData) + { + return $this->_decrypt($encryptedData, false, null); + } + + // }}} + // {{{ decryptFile() + + /** + * Decrypts a file + * + * This method assumes the required private key is available in the keyring + * and throws an exception if the private key is not available. To add a + * private key to the keyring, use the {@link Crypt_GPG::importKey()} or + * {@link Crypt_GPG::importKeyFile()} methods. + * + * @param string $encryptedFile the name of the encrypted file data to + * decrypt. + * @param string $decryptedFile optional. The name of the file to which the + * decrypted data should be written. If null + * or unspecified, the decrypted data is + * returned as a string. + * + * @return void|string if the <kbd>$decryptedFile</kbd> parameter is null, + * a string containing the decrypted data is returned. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function decryptFile($encryptedFile, $decryptedFile = null) + { + return $this->_decrypt($encryptedFile, true, $decryptedFile); + } + + // }}} + // {{{ decryptAndVerify() + + /** + * Decrypts and verifies string data + * + * This method assumes the required private key is available in the keyring + * and throws an exception if the private key is not available. To add a + * private key to the keyring, use the {@link Crypt_GPG::importKey()} or + * {@link Crypt_GPG::importKeyFile()} methods. + * + * @param string $encryptedData the encrypted, signed data to be decrypted + * and verified. + * + * @return array two element array. The array has an element 'data' + * containing the decrypted data and an element + * 'signatures' containing an array of + * {@link Crypt_GPG_Signature} objects for the signed data. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function decryptAndVerify($encryptedData) + { + return $this->_decryptAndVerify($encryptedData, false, null); + } + + // }}} + // {{{ decryptAndVerifyFile() + + /** + * Decrypts and verifies a signed, encrypted file + * + * This method assumes the required private key is available in the keyring + * and throws an exception if the private key is not available. To add a + * private key to the keyring, use the {@link Crypt_GPG::importKey()} or + * {@link Crypt_GPG::importKeyFile()} methods. + * + * @param string $encryptedFile the name of the signed, encrypted file to + * to decrypt and verify. + * @param string $decryptedFile optional. The name of the file to which the + * decrypted data should be written. If null + * or unspecified, the decrypted data is + * returned in the results array. + * + * @return array two element array. The array has an element 'data' + * containing the decrypted data and an element + * 'signatures' containing an array of + * {@link Crypt_GPG_Signature} objects for the signed data. + * If the decrypted data is written to a file, the 'data' + * element is null. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null) + { + return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile); + } + + // }}} + // {{{ sign() + + /** + * Signs data + * + * Data may be signed using any one of the three available signing modes: + * - {@link Crypt_GPG::SIGN_MODE_NORMAL} + * - {@link Crypt_GPG::SIGN_MODE_CLEAR} + * - {@link Crypt_GPG::SIGN_MODE_DETACHED} + * + * @param string $data the data to be signed. + * @param boolean $mode optional. The data signing mode to use. Should + * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, + * {@link Crypt_GPG::SIGN_MODE_CLEAR} or + * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not + * specified, defaults to + * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>. + * @param boolean $armor optional. If true, ASCII armored data is + * returned; otherwise, binary data is returned. + * Defaults to true. This has no effect if the + * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used. + * @param boolean $textmode optional. If true, line-breaks in signed data + * are normalized. Use this option when signing + * e-mail, or for greater compatibility between + * systems with different line-break formats. + * Defaults to false. This has no effect if the + * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used as clear-signing always uses textmode. + * + * @return string the signed data, or the signature data if a detached + * signature is requested. + * + * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. + * See {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function sign($data, $mode = Crypt_GPG::SIGN_MODE_NORMAL, + $armor = true, $textmode = false + ) { + return $this->_sign($data, false, null, $mode, $armor, $textmode); + } + + // }}} + // {{{ signFile() + + /** + * Signs a file + * + * The file may be signed using any one of the three available signing + * modes: + * - {@link Crypt_GPG::SIGN_MODE_NORMAL} + * - {@link Crypt_GPG::SIGN_MODE_CLEAR} + * - {@link Crypt_GPG::SIGN_MODE_DETACHED} + * + * @param string $filename the name of the file containing the data to + * be signed. + * @param string $signedFile optional. The name of the file in which the + * signed data should be stored. If null or + * unspecified, the signed data is returned as a + * string. + * @param boolean $mode optional. The data signing mode to use. Should + * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, + * {@link Crypt_GPG::SIGN_MODE_CLEAR} or + * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not + * specified, defaults to + * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>. + * @param boolean $armor optional. If true, ASCII armored data is + * returned; otherwise, binary data is returned. + * Defaults to true. This has no effect if the + * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used. + * @param boolean $textmode optional. If true, line-breaks in signed data + * are normalized. Use this option when signing + * e-mail, or for greater compatibility between + * systems with different line-break formats. + * Defaults to false. This has no effect if the + * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used as clear-signing always uses textmode. + * + * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a + * string containing the signed data (or the signature + * data if a detached signature is requested) is + * returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. + * See {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + public function signFile($filename, $signedFile = null, + $mode = Crypt_GPG::SIGN_MODE_NORMAL, $armor = true, $textmode = false + ) { + return $this->_sign( + $filename, + true, + $signedFile, + $mode, + $armor, + $textmode + ); + } + + // }}} + // {{{ verify() + + /** + * Verifies signed data + * + * The {@link Crypt_GPG::decrypt()} method may be used to get the original + * message if the signed data is not clearsigned and does not use a + * detached signature. + * + * @param string $signedData the signed data to be verified. + * @param string $signature optional. If verifying data signed using a + * detached signature, this must be the detached + * signature data. The data that was signed is + * specified in <kbd>$signedData</kbd>. + * + * @return array an array of {@link Crypt_GPG_Signature} objects for the + * signed data. For each signature that is valid, the + * {@link Crypt_GPG_Signature::isValid()} will return true. + * + * @throws Crypt_GPG_NoDataException if the provided data is not signed + * data. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG_Signature + */ + public function verify($signedData, $signature = '') + { + return $this->_verify($signedData, false, $signature); + } + + // }}} + // {{{ verifyFile() + + /** + * Verifies a signed file + * + * The {@link Crypt_GPG::decryptFile()} method may be used to get the + * original message if the signed data is not clearsigned and does not use + * a detached signature. + * + * @param string $filename the signed file to be verified. + * @param string $signature optional. If verifying a file signed using a + * detached signature, this must be the detached + * signature data. The file that was signed is + * specified in <kbd>$filename</kbd>. + * + * @return array an array of {@link Crypt_GPG_Signature} objects for the + * signed data. For each signature that is valid, the + * {@link Crypt_GPG_Signature::isValid()} will return true. + * + * @throws Crypt_GPG_NoDataException if the provided data is not signed + * data. + * + * @throws Crypt_GPG_FileException if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG_Signature + */ + public function verifyFile($filename, $signature = '') + { + return $this->_verify($filename, true, $signature); + } + + // }}} + // {{{ addDecryptKey() + + /** + * Adds a key to use for decryption + * + * @param mixed $key the key to use. This may be a key identifier, + * user id, fingerprint, {@link Crypt_GPG_Key} or + * {@link Crypt_GPG_SubKey}. The key must be able + * to encrypt. + * @param string $passphrase optional. The passphrase of the key required + * for decryption. + * + * @return void + * + * @see Crypt_GPG::decrypt() + * @see Crypt_GPG::decryptFile() + * @see Crypt_GPG::clearDecryptKeys() + * @see Crypt_GPG::_addKey() + * @see Crypt_GPG_DecryptStatusHandler + * + * @sensitive $passphrase + */ + public function addDecryptKey($key, $passphrase = null) + { + $this->_addKey($this->decryptKeys, true, false, $key, $passphrase); + } + + // }}} + // {{{ addEncryptKey() + + /** + * Adds a key to use for encryption + * + * @param mixed $key the key to use. This may be a key identifier, user id + * user id, fingerprint, {@link Crypt_GPG_Key} or + * {@link Crypt_GPG_SubKey}. The key must be able to + * encrypt. + * + * @return void + * + * @see Crypt_GPG::encrypt() + * @see Crypt_GPG::encryptFile() + * @see Crypt_GPG::clearEncryptKeys() + * @see Crypt_GPG::_addKey() + */ + public function addEncryptKey($key) + { + $this->_addKey($this->encryptKeys, true, false, $key); + } + + // }}} + // {{{ addSignKey() + + /** + * Adds a key to use for signing + * + * @param mixed $key the key to use. This may be a key identifier, + * user id, fingerprint, {@link Crypt_GPG_Key} or + * {@link Crypt_GPG_SubKey}. The key must be able + * to sign. + * @param string $passphrase optional. The passphrase of the key required + * for signing. + * + * @return void + * + * @see Crypt_GPG::sign() + * @see Crypt_GPG::signFile() + * @see Crypt_GPG::clearSignKeys() + * @see Crypt_GPG::handleSignStatus() + * @see Crypt_GPG::_addKey() + * + * @sensitive $passphrase + */ + public function addSignKey($key, $passphrase = null) + { + $this->_addKey($this->signKeys, false, true, $key, $passphrase); + } + + // }}} + // {{{ clearDecryptKeys() + + /** + * Clears all decryption keys + * + * @return void + * + * @see Crypt_GPG::decrypt() + * @see Crypt_GPG::addDecryptKey() + */ + public function clearDecryptKeys() + { + $this->decryptKeys = array(); + } + + // }}} + // {{{ clearEncryptKeys() + + /** + * Clears all encryption keys + * + * @return void + * + * @see Crypt_GPG::encrypt() + * @see Crypt_GPG::addEncryptKey() + */ + public function clearEncryptKeys() + { + $this->encryptKeys = array(); + } + + // }}} + // {{{ clearSignKeys() + + /** + * Clears all signing keys + * + * @return void + * + * @see Crypt_GPG::sign() + * @see Crypt_GPG::addSignKey() + */ + public function clearSignKeys() + { + $this->signKeys = array(); + } + + // }}} + // {{{ handleSignStatus() + + /** + * Handles the status output from GPG for the sign operation + * + * This method is responsible for sending the passphrase commands when + * required by the {@link Crypt_GPG::sign()} method. See <b>doc/DETAILS</b> + * in the {@link http://www.gnupg.org/download/ GPG distribution} for + * detailed information on GPG's status output. + * + * @param string $line the status line to handle. + * + * @return void + * + * @see Crypt_GPG::sign() + */ + public function handleSignStatus($line) + { + $tokens = explode(' ', $line); + switch ($tokens[0]) { + case 'NEED_PASSPHRASE': + $subKeyId = $tokens[1]; + if (array_key_exists($subKeyId, $this->signKeys)) { + $passphrase = $this->signKeys[$subKeyId]['passphrase']; + $this->engine->sendCommand($passphrase); + } else { + $this->engine->sendCommand(''); + } + break; + } + } + + // }}} + // {{{ handleImportKeyStatus() + + /** + * Handles the status output from GPG for the import operation + * + * This method is responsible for building the result array that is + * returned from the {@link Crypt_GPG::importKey()} method. See + * <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG distribution} for detailed + * information on GPG's status output. + * + * @param string $line the status line to handle. + * @param array &$result the current result array being processed. + * + * @return void + * + * @see Crypt_GPG::importKey() + * @see Crypt_GPG::importKeyFile() + * @see Crypt_GPG_Engine::addStatusHandler() + */ + public function handleImportKeyStatus($line, array &$result) + { + $tokens = explode(' ', $line); + switch ($tokens[0]) { + case 'IMPORT_OK': + $result['fingerprint'] = $tokens[2]; + break; + + case 'IMPORT_RES': + $result['public_imported'] = intval($tokens[3]); + $result['public_unchanged'] = intval($tokens[5]); + $result['private_imported'] = intval($tokens[11]); + $result['private_unchanged'] = intval($tokens[12]); + break; + } + } + + // }}} + // {{{ setEngine() + + /** + * Sets the I/O engine to use for GnuPG operations + * + * Normally this method does not need to be used. It provides a means for + * dependency injection. + * + * @param Crypt_GPG_Engine $engine the engine to use. + * + * @return void + */ + public function setEngine(Crypt_GPG_Engine $engine) + { + $this->engine = $engine; + } + + // }}} + // {{{ _addKey() + + /** + * Adds a key to one of the internal key arrays + * + * This handles resolving full key objects from the provided + * <kbd>$key</kbd> value. + * + * @param array &$array the array to which the key should be added. + * @param boolean $encrypt whether or not the key must be able to + * encrypt. + * @param boolean $sign whether or not the key must be able to sign. + * @param mixed $key the key to add. This may be a key identifier, + * user id, fingerprint, {@link Crypt_GPG_Key} or + * {@link Crypt_GPG_SubKey}. + * @param string $passphrase optional. The passphrase associated with the + * key. + * + * @return void + * + * @sensitive $passphrase + */ + private function _addKey(array &$array, $encrypt, $sign, $key, + $passphrase = null + ) { + $subKeys = array(); + + if (is_scalar($key)) { + $keys = $this->getKeys($key); + if (count($keys) == 0) { + throw new Crypt_GPG_KeyNotFoundException( + 'Key "' . $key . '" not found.', 0, $key); + } + $key = $keys[0]; + } + + if ($key instanceof Crypt_GPG_Key) { + if ($encrypt && !$key->canEncrypt()) { + throw new InvalidArgumentException( + 'Key "' . $key . '" cannot encrypt.'); + } + + if ($sign && !$key->canSign()) { + throw new InvalidArgumentException( + 'Key "' . $key . '" cannot sign.'); + } + + foreach ($key->getSubKeys() as $subKey) { + $canEncrypt = $subKey->canEncrypt(); + $canSign = $subKey->canSign(); + if ( ($encrypt && $sign && $canEncrypt && $canSign) + || ($encrypt && !$sign && $canEncrypt) + || (!$encrypt && $sign && $canSign) + ) { + // We add all subkeys that meet the requirements because we + // were not told which subkey is required. + $subKeys[] = $subKey; + } + } + } elseif ($key instanceof Crypt_GPG_SubKey) { + $subKeys[] = $key; + } + + if (count($subKeys) === 0) { + throw new InvalidArgumentException( + 'Key "' . $key . '" is not in a recognized format.'); + } + + foreach ($subKeys as $subKey) { + if ($encrypt && !$subKey->canEncrypt()) { + throw new InvalidArgumentException( + 'Key "' . $key . '" cannot encrypt.'); + } + + if ($sign && !$subKey->canSign()) { + throw new InvalidArgumentException( + 'Key "' . $key . '" cannot sign.'); + } + + $array[$subKey->getId()] = array( + 'fingerprint' => $subKey->getFingerprint(), + 'passphrase' => $passphrase + ); + } + } + + // }}} + // {{{ _importKey() + + /** + * Imports a public or private key into the keyring + * + * @param string $key the key to be imported. + * @param boolean $isFile whether or not the input is a filename. + * + * @return array an associative array containing the following elements: + * - <kbd>fingerprint</kbd> - the fingerprint of the + * imported key, + * - <kbd>public_imported</kbd> - the number of public + * keys imported, + * - <kbd>public_unchanged</kbd> - the number of unchanged + * public keys, + * - <kbd>private_imported</kbd> - the number of private + * keys imported, + * - <kbd>private_unchanged</kbd> - the number of unchanged + * private keys. + * + * @throws Crypt_GPG_NoDataException if the key data is missing or if the + * data is is not valid key data. + * + * @throws Crypt_GPG_FileException if the key file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + private function _importKey($key, $isFile) + { + $result = array(); + + if ($isFile) { + $input = @fopen($key, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open key file "' . + $key . '" for importing.', 0, $key); + } + } else { + $input = strval($key); + if ($input == '') { + throw new Crypt_GPG_NoDataException( + 'No valid GPG key data found.', Crypt_GPG::ERROR_NO_DATA); + } + } + + $arguments = array(); + $version = $this->engine->getVersion(); + + if ( version_compare($version, '1.0.5', 'ge') + && version_compare($version, '1.0.7', 'lt') + ) { + $arguments[] = '--allow-secret-key-import'; + } + + $this->engine->reset(); + $this->engine->addStatusHandler( + array($this, 'handleImportKeyStatus'), + array(&$result) + ); + + $this->engine->setOperation('--import', $arguments); + $this->engine->setInput($input); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_DUPLICATE_KEY: + case Crypt_GPG::ERROR_NONE: + // ignore duplicate key import errors + break; + case Crypt_GPG::ERROR_NO_DATA: + throw new Crypt_GPG_NoDataException( + 'No valid GPG key data found.', $code); + default: + throw new Crypt_GPG_Exception( + 'Unknown error importing GPG key. Please use the \'debug\' ' . + 'option when creating the Crypt_GPG object, and file a bug ' . + 'report at ' . self::BUG_URI, $code); + } + + return $result; + } + + // }}} + // {{{ _encrypt() + + /** + * Encrypts data + * + * @param string $data the data to encrypt. + * @param boolean $isFile whether or not the data is a filename. + * @param string $outputFile the filename of the file in which to store + * the encrypted data. If null, the encrypted + * data is returned as a string. + * @param boolean $armor if true, ASCII armored data is returned; + * otherwise, binary data is returned. + * + * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a + * string containing the encrypted data is returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. + * See {@link Crypt_GPG::addEncryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + private function _encrypt($data, $isFile, $outputFile, $armor) + { + if (count($this->encryptKeys) === 0) { + throw new Crypt_GPG_KeyNotFoundException( + 'No encryption keys specified.'); + } + + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input file "' . + $data . '" for encryption.', 0, $data); + } + } else { + $input = strval($data); + } + + if ($outputFile === null) { + $output = ''; + } else { + $output = @fopen($outputFile, 'wb'); + if ($output === false) { + if ($isFile) { + fclose($input); + } + throw new Crypt_GPG_FileException('Could not open output ' . + 'file "' . $outputFile . '" for storing encrypted data.', + 0, $outputFile); + } + } + + $arguments = ($armor) ? array('--armor') : array(); + foreach ($this->encryptKeys as $key) { + $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); + } + + $this->engine->reset(); + $this->engine->setInput($input); + $this->engine->setOutput($output); + $this->engine->setOperation('--encrypt', $arguments); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + if ($outputFile !== null) { + fclose($output); + } + + $code = $this->engine->getErrorCode(); + + if ($code !== Crypt_GPG::ERROR_NONE) { + throw new Crypt_GPG_Exception( + 'Unknown error encrypting data. Please use the \'debug\' ' . + 'option when creating the Crypt_GPG object, and file a bug ' . + 'report at ' . self::BUG_URI, $code); + } + + if ($outputFile === null) { + return $output; + } + } + + // }}} + // {{{ _decrypt() + + /** + * Decrypts data + * + * @param string $data the data to be decrypted. + * @param boolean $isFile whether or not the data is a filename. + * @param string $outputFile the name of the file to which the decrypted + * data should be written. If null, the decrypted + * data is returned as a string. + * + * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a + * string containing the decrypted data is returned. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + private function _decrypt($data, $isFile, $outputFile) + { + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input file "' . + $data . '" for decryption.', 0, $data); + } + } else { + $input = strval($data); + if ($input == '') { + throw new Crypt_GPG_NoDataException( + 'Cannot decrypt data. No PGP encrypted data was found in '. + 'the provided data.', Crypt_GPG::ERROR_NO_DATA); + } + } + + if ($outputFile === null) { + $output = ''; + } else { + $output = @fopen($outputFile, 'wb'); + if ($output === false) { + if ($isFile) { + fclose($input); + } + throw new Crypt_GPG_FileException('Could not open output ' . + 'file "' . $outputFile . '" for storing decrypted data.', + 0, $outputFile); + } + } + + $handler = new Crypt_GPG_DecryptStatusHandler($this->engine, + $this->decryptKeys); + + $this->engine->reset(); + $this->engine->addStatusHandler(array($handler, 'handle')); + $this->engine->setOperation('--decrypt'); + $this->engine->setInput($input); + $this->engine->setOutput($output); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + if ($outputFile !== null) { + fclose($output); + } + + // if there was any problem decrypting the data, the handler will + // deal with it here. + $handler->throwException(); + + if ($outputFile === null) { + return $output; + } + } + + // }}} + // {{{ _sign() + + /** + * Signs data + * + * @param string $data the data to be signed. + * @param boolean $isFile whether or not the data is a filename. + * @param string $outputFile the name of the file in which the signed data + * should be stored. If null, the signed data is + * returned as a string. + * @param boolean $mode the data signing mode to use. Should be one of + * {@link Crypt_GPG::SIGN_MODE_NORMAL}, + * {@link Crypt_GPG::SIGN_MODE_CLEAR} or + * {@link Crypt_GPG::SIGN_MODE_DETACHED}. + * @param boolean $armor if true, ASCII armored data is returned; + * otherwise, binary data is returned. This has + * no effect if the mode + * <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used. + * @param boolean $textmode if true, line-breaks in signed data be + * normalized. Use this option when signing + * e-mail, or for greater compatibility between + * systems with different line-break formats. + * Defaults to false. This has no effect if the + * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is + * used as clear-signing always uses textmode. + * + * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a + * string containing the signed data (or the signature + * data if a detached signature is requested) is + * returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. + * See {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + private function _sign($data, $isFile, $outputFile, $mode, $armor, + $textmode + ) { + if (count($this->signKeys) === 0) { + throw new Crypt_GPG_KeyNotFoundException( + 'No signing keys specified.'); + } + + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input ' . + 'file "' . $data . '" for signing.', 0, $data); + } + } else { + $input = strval($data); + } + + if ($outputFile === null) { + $output = ''; + } else { + $output = @fopen($outputFile, 'wb'); + if ($output === false) { + if ($isFile) { + fclose($input); + } + throw new Crypt_GPG_FileException('Could not open output ' . + 'file "' . $outputFile . '" for storing signed ' . + 'data.', 0, $outputFile); + } + } + + switch ($mode) { + case Crypt_GPG::SIGN_MODE_DETACHED: + $operation = '--detach-sign'; + break; + case Crypt_GPG::SIGN_MODE_CLEAR: + $operation = '--clearsign'; + break; + case Crypt_GPG::SIGN_MODE_NORMAL: + default: + $operation = '--sign'; + break; + } + + $arguments = array(); + + if ($armor) { + $arguments[] = '--armor'; + } + if ($textmode) { + $arguments[] = '--textmode'; + } + + foreach ($this->signKeys as $key) { + $arguments[] = '--local-user ' . + escapeshellarg($key['fingerprint']); + } + + $this->engine->reset(); + $this->engine->addStatusHandler(array($this, 'handleSignStatus')); + $this->engine->setInput($input); + $this->engine->setOutput($output); + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + if ($outputFile !== null) { + fclose($output); + } + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + break; + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + throw new Crypt_GPG_KeyNotFoundException( + 'Cannot sign data. Private key not found. Import the '. + 'private key before trying to sign data.', $code, + $this->engine->getErrorKeyId()); + case Crypt_GPG::ERROR_BAD_PASSPHRASE: + throw new Crypt_GPG_BadPassphraseException( + 'Cannot sign data. Incorrect passphrase provided.', $code); + case Crypt_GPG::ERROR_MISSING_PASSPHRASE: + throw new Crypt_GPG_BadPassphraseException( + 'Cannot sign data. No passphrase provided.', $code); + default: + throw new Crypt_GPG_Exception( + 'Unknown error signing data. Please use the \'debug\' option ' . + 'when creating the Crypt_GPG object, and file a bug report ' . + 'at ' . self::BUG_URI, $code); + } + + if ($outputFile === null) { + return $output; + } + } + + // }}} + // {{{ _encryptAndSign() + + /** + * Encrypts and signs data + * + * @param string $data the data to be encrypted and signed. + * @param boolean $isFile whether or not the data is a filename. + * @param string $outputFile the name of the file in which the encrypted, + * signed data should be stored. If null, the + * encrypted, signed data is returned as a + * string. + * @param boolean $armor if true, ASCII armored data is returned; + * otherwise, binary data is returned. + * + * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a + * string containing the encrypted, signed data is + * returned. + * + * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified + * or if no signing key is specified. See + * {@link Crypt_GPG::addEncryptKey()} and + * {@link Crypt_GPG::addSignKey()}. + * + * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is + * incorrect or if a required passphrase is not specified. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + */ + private function _encryptAndSign($data, $isFile, $outputFile, $armor) + { + if (count($this->signKeys) === 0) { + throw new Crypt_GPG_KeyNotFoundException( + 'No signing keys specified.'); + } + + if (count($this->encryptKeys) === 0) { + throw new Crypt_GPG_KeyNotFoundException( + 'No encryption keys specified.'); + } + + + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input ' . + 'file "' . $data . '" for encrypting and signing.', 0, + $data); + } + } else { + $input = strval($data); + } + + if ($outputFile === null) { + $output = ''; + } else { + $output = @fopen($outputFile, 'wb'); + if ($output === false) { + if ($isFile) { + fclose($input); + } + throw new Crypt_GPG_FileException('Could not open output ' . + 'file "' . $outputFile . '" for storing encrypted, ' . + 'signed data.', 0, $outputFile); + } + } + + $arguments = ($armor) ? array('--armor') : array(); + + foreach ($this->signKeys as $key) { + $arguments[] = '--local-user ' . + escapeshellarg($key['fingerprint']); + } + + foreach ($this->encryptKeys as $key) { + $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); + } + + $this->engine->reset(); + $this->engine->addStatusHandler(array($this, 'handleSignStatus')); + $this->engine->setInput($input); + $this->engine->setOutput($output); + $this->engine->setOperation('--encrypt --sign', $arguments); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + if ($outputFile !== null) { + fclose($output); + } + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + break; + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + throw new Crypt_GPG_KeyNotFoundException( + 'Cannot sign encrypted data. Private key not found. Import '. + 'the private key before trying to sign the encrypted data.', + $code, $this->engine->getErrorKeyId()); + case Crypt_GPG::ERROR_BAD_PASSPHRASE: + throw new Crypt_GPG_BadPassphraseException( + 'Cannot sign encrypted data. Incorrect passphrase provided.', + $code); + case Crypt_GPG::ERROR_MISSING_PASSPHRASE: + throw new Crypt_GPG_BadPassphraseException( + 'Cannot sign encrypted data. No passphrase provided.', $code); + default: + throw new Crypt_GPG_Exception( + 'Unknown error encrypting and signing data. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + + if ($outputFile === null) { + return $output; + } + } + + // }}} + // {{{ _verify() + + /** + * Verifies data + * + * @param string $data the signed data to be verified. + * @param boolean $isFile whether or not the data is a filename. + * @param string $signature if verifying a file signed using a detached + * signature, this must be the detached signature + * data. Otherwise, specify ''. + * + * @return array an array of {@link Crypt_GPG_Signature} objects for the + * signed data. + * + * @throws Crypt_GPG_NoDataException if the provided data is not signed + * data. + * + * @throws Crypt_GPG_FileException if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG_Signature + */ + private function _verify($data, $isFile, $signature) + { + if ($signature == '') { + $operation = '--verify'; + $arguments = array(); + } else { + // Signed data goes in FD_MESSAGE, detached signature data goes in + // FD_INPUT. + $operation = '--verify - "-&' . Crypt_GPG_Engine::FD_MESSAGE. '"'; + $arguments = array('--enable-special-filenames'); + } + + $handler = new Crypt_GPG_VerifyStatusHandler(); + + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input ' . + 'file "' . $data . '" for verifying.', 0, $data); + } + } else { + $input = strval($data); + if ($input == '') { + throw new Crypt_GPG_NoDataException( + 'No valid signature data found.', Crypt_GPG::ERROR_NO_DATA); + } + } + + $this->engine->reset(); + $this->engine->addStatusHandler(array($handler, 'handle')); + + if ($signature == '') { + // signed or clearsigned data + $this->engine->setInput($input); + } else { + // detached signature + $this->engine->setInput($signature); + $this->engine->setMessage($input); + } + + $this->engine->setOperation($operation, $arguments); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + $code = $this->engine->getErrorCode(); + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + case Crypt_GPG::ERROR_BAD_SIGNATURE: + break; + case Crypt_GPG::ERROR_NO_DATA: + throw new Crypt_GPG_NoDataException( + 'No valid signature data found.', $code); + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + throw new Crypt_GPG_KeyNotFoundException( + 'Public key required for data verification not in keyring.', + $code, $this->engine->getErrorKeyId()); + default: + throw new Crypt_GPG_Exception( + 'Unknown error validating signature details. Please use the ' . + '\'debug\' option when creating the Crypt_GPG object, and ' . + 'file a bug report at ' . self::BUG_URI, $code); + } + + return $handler->getSignatures(); + } + + // }}} + // {{{ _decryptAndVerify() + + /** + * Decrypts and verifies encrypted, signed data + * + * @param string $data the encrypted signed data to be decrypted and + * verified. + * @param boolean $isFile whether or not the data is a filename. + * @param string $outputFile the name of the file to which the decrypted + * data should be written. If null, the decrypted + * data is returned in the results array. + * + * @return array two element array. The array has an element 'data' + * containing the decrypted data and an element + * 'signatures' containing an array of + * {@link Crypt_GPG_Signature} objects for the signed data. + * If the decrypted data is written to a file, the 'data' + * element is null. + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring or it the public + * key needed for verification is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG signed, encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_FileException if the output file is not writeable or + * if the input file is not readable. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @see Crypt_GPG_Signature + */ + private function _decryptAndVerify($data, $isFile, $outputFile) + { + if ($isFile) { + $input = @fopen($data, 'rb'); + if ($input === false) { + throw new Crypt_GPG_FileException('Could not open input ' . + 'file "' . $data . '" for decrypting and verifying.', 0, + $data); + } + } else { + $input = strval($data); + if ($input == '') { + throw new Crypt_GPG_NoDataException( + 'No valid encrypted signed data found.', + Crypt_GPG::ERROR_NO_DATA); + } + } + + if ($outputFile === null) { + $output = ''; + } else { + $output = @fopen($outputFile, 'wb'); + if ($output === false) { + if ($isFile) { + fclose($input); + } + throw new Crypt_GPG_FileException('Could not open output ' . + 'file "' . $outputFile . '" for storing decrypted data.', + 0, $outputFile); + } + } + + $verifyHandler = new Crypt_GPG_VerifyStatusHandler(); + + $decryptHandler = new Crypt_GPG_DecryptStatusHandler($this->engine, + $this->decryptKeys); + + $this->engine->reset(); + $this->engine->addStatusHandler(array($verifyHandler, 'handle')); + $this->engine->addStatusHandler(array($decryptHandler, 'handle')); + $this->engine->setInput($input); + $this->engine->setOutput($output); + $this->engine->setOperation('--decrypt'); + $this->engine->run(); + + if ($isFile) { + fclose($input); + } + + if ($outputFile !== null) { + fclose($output); + } + + $return = array( + 'data' => null, + 'signatures' => $verifyHandler->getSignatures() + ); + + // if there was any problem decrypting the data, the handler will + // deal with it here. + try { + $decryptHandler->throwException(); + } catch (Exception $e) { + if ($e instanceof Crypt_GPG_KeyNotFoundException) { + throw new Crypt_GPG_KeyNotFoundException( + 'Public key required for data verification not in ', + 'the keyring. Either no suitable private decryption key ' . + 'is in the keyring or the public key required for data ' . + 'verification is not in the keyring. Import a suitable ' . + 'key before trying to decrypt and verify this data.', + self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId()); + } + + if ($e instanceof Crypt_GPG_NoDataException) { + throw new Crypt_GPG_NoDataException( + 'Cannot decrypt and verify data. No PGP encrypted data ' . + 'was found in the provided data.', self::ERROR_NO_DATA); + } + + throw $e; + } + + if ($outputFile === null) { + $return['data'] = $output; + } + + return $return; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/DecryptStatusHandler.php b/program/lib/Crypt/GPG/DecryptStatusHandler.php new file mode 100644 index 000000000..40e8d50ed --- /dev/null +++ b/program/lib/Crypt/GPG/DecryptStatusHandler.php @@ -0,0 +1,336 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Crypt_GPG is a package to use GPG from PHP + * + * This file contains an object that handles GPG's status output for the + * decrypt operation. + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008-2009 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: DecryptStatusHandler.php 302814 2010-08-26 15:43:07Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ + +/** + * Crypt_GPG base class + */ +require_once 'Crypt/GPG.php'; + +/** + * GPG exception classes + */ +require_once 'Crypt/GPG/Exceptions.php'; + + +/** + * Status line handler for the decrypt operation + * + * This class is used internally by Crypt_GPG and does not need be used + * directly. See the {@link Crypt_GPG} class for end-user API. + * + * This class is responsible for sending the passphrase commands when required + * by the {@link Crypt_GPG::decrypt()} method. See <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG distribution} for detailed + * information on GPG's status output for the decrypt operation. + * + * This class is also responsible for parsing error status and throwing a + * meaningful exception in the event that decryption fails. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ +class Crypt_GPG_DecryptStatusHandler +{ + // {{{ protected properties + + /** + * Keys used to decrypt + * + * The array is of the form: + * <code> + * array( + * $key_id => array( + * 'fingerprint' => $fingerprint, + * 'passphrase' => $passphrase + * ) + * ); + * </code> + * + * @var array + */ + protected $keys = array(); + + /** + * Engine used to which passphrases are passed + * + * @var Crypt_GPG_Engine + */ + protected $engine = null; + + /** + * The id of the current sub-key used for decryption + * + * @var string + */ + protected $currentSubKey = ''; + + /** + * Whether or not decryption succeeded + * + * If the message is only signed (compressed) and not encrypted, this is + * always true. If the message is encrypted, this flag is set to false + * until we know the decryption succeeded. + * + * @var boolean + */ + protected $decryptionOkay = true; + + /** + * Whether or not there was no data for decryption + * + * @var boolean + */ + protected $noData = false; + + /** + * Keys for which the passhprase is missing + * + * This contains primary user ids indexed by sub-key id and is used to + * create helpful exception messages. + * + * @var array + */ + protected $missingPassphrases = array(); + + /** + * Keys for which the passhprase is incorrect + * + * This contains primary user ids indexed by sub-key id and is used to + * create helpful exception messages. + * + * @var array + */ + protected $badPassphrases = array(); + + /** + * Keys that can be used to decrypt the data but are missing from the + * keychain + * + * This is an array with both the key and value being the sub-key id of + * the missing keys. + * + * @var array + */ + protected $missingKeys = array(); + + // }}} + // {{{ __construct() + + /** + * Creates a new decryption status handler + * + * @param Crypt_GPG_Engine $engine the GPG engine to which passphrases are + * passed. + * @param array $keys the decryption keys to use. + */ + public function __construct(Crypt_GPG_Engine $engine, array $keys) + { + $this->engine = $engine; + $this->keys = $keys; + } + + // }}} + // {{{ handle() + + /** + * Handles a status line + * + * @param string $line the status line to handle. + * + * @return void + */ + public function handle($line) + { + $tokens = explode(' ', $line); + switch ($tokens[0]) { + case 'ENC_TO': + // Now we know the message is encrypted. Set flag to check if + // decryption succeeded. + $this->decryptionOkay = false; + + // this is the new key message + $this->currentSubKeyId = $tokens[1]; + break; + + case 'NEED_PASSPHRASE': + // send passphrase to the GPG engine + $subKeyId = $tokens[1]; + if (array_key_exists($subKeyId, $this->keys)) { + $passphrase = $this->keys[$subKeyId]['passphrase']; + $this->engine->sendCommand($passphrase); + } else { + $this->engine->sendCommand(''); + } + break; + + case 'USERID_HINT': + // remember the user id for pretty exception messages + $this->badPassphrases[$tokens[1]] + = implode(' ', array_splice($tokens, 2)); + + break; + + case 'GOOD_PASSPHRASE': + // if we got a good passphrase, remove the key from the list of + // bad passphrases. + unset($this->badPassphrases[$this->currentSubKeyId]); + break; + + case 'MISSING_PASSPHRASE': + $this->missingPassphrases[$this->currentSubKeyId] + = $this->currentSubKeyId; + + break; + + case 'NO_SECKEY': + // note: this message is also received if there are multiple + // recipients and a previous key had a correct passphrase. + $this->missingKeys[$tokens[1]] = $tokens[1]; + break; + + case 'NODATA': + $this->noData = true; + break; + + case 'DECRYPTION_OKAY': + // If the message is encrypted, this is the all-clear signal. + $this->decryptionOkay = true; + break; + } + } + + // }}} + // {{{ throwException() + + /** + * Takes the final status of the decrypt operation and throws an + * appropriate exception + * + * If decryption was successful, no exception is thrown. + * + * @return void + * + * @throws Crypt_GPG_KeyNotFoundException if the private key needed to + * decrypt the data is not in the user's keyring. + * + * @throws Crypt_GPG_NoDataException if specified data does not contain + * GPG encrypted data. + * + * @throws Crypt_GPG_BadPassphraseException if a required passphrase is + * incorrect or if a required passphrase is not specified. See + * {@link Crypt_GPG::addDecryptKey()}. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <i>debug</i> option and file a bug report if these + * exceptions occur. + */ + public function throwException() + { + $code = Crypt_GPG::ERROR_NONE; + + if (!$this->decryptionOkay) { + if (count($this->badPassphrases) > 0) { + $code = Crypt_GPG::ERROR_BAD_PASSPHRASE; + } elseif (count($this->missingKeys) > 0) { + $code = Crypt_GPG::ERROR_KEY_NOT_FOUND; + } else { + $code = Crypt_GPG::ERROR_UNKNOWN; + } + } elseif ($this->noData) { + $code = Crypt_GPG::ERROR_NO_DATA; + } + + switch ($code) { + case Crypt_GPG::ERROR_NONE: + break; + + case Crypt_GPG::ERROR_KEY_NOT_FOUND: + if (count($this->missingKeys) > 0) { + $keyId = reset($this->missingKeys); + } else { + $keyId = ''; + } + throw new Crypt_GPG_KeyNotFoundException( + 'Cannot decrypt data. No suitable private key is in the ' . + 'keyring. Import a suitable private key before trying to ' . + 'decrypt this data.', $code, $keyId); + + case Crypt_GPG::ERROR_BAD_PASSPHRASE: + $badPassphrases = array_diff_key( + $this->badPassphrases, + $this->missingPassphrases + ); + + $missingPassphrases = array_intersect_key( + $this->badPassphrases, + $this->missingPassphrases + ); + + $message = 'Cannot decrypt data.'; + if (count($badPassphrases) > 0) { + $message = ' Incorrect passphrase provided for keys: "' . + implode('", "', $badPassphrases) . '".'; + } + if (count($missingPassphrases) > 0) { + $message = ' No passphrase provided for keys: "' . + implode('", "', $badPassphrases) . '".'; + } + + throw new Crypt_GPG_BadPassphraseException($message, $code, + $badPassphrases, $missingPassphrases); + + case Crypt_GPG::ERROR_NO_DATA: + throw new Crypt_GPG_NoDataException( + 'Cannot decrypt data. No PGP encrypted data was found in '. + 'the provided data.', $code); + + default: + throw new Crypt_GPG_Exception( + 'Unknown error decrypting data.', $code); + } + } + + // }}} +} + +?> diff --git a/program/lib/Crypt/GPG/Engine.php b/program/lib/Crypt/GPG/Engine.php new file mode 100644 index 000000000..081be8e21 --- /dev/null +++ b/program/lib/Crypt/GPG/Engine.php @@ -0,0 +1,1758 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Crypt_GPG is a package to use GPG from PHP + * + * This file contains an engine that handles GPG subprocess control and I/O. + * PHP's process manipulation functions are used to handle the GPG subprocess. + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Engine.php 302822 2010-08-26 17:30:57Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ + +/** + * Crypt_GPG base class. + */ +require_once 'Crypt/GPG.php'; + +/** + * GPG exception classes. + */ +require_once 'Crypt/GPG/Exceptions.php'; + +/** + * Standard PEAR exception is used if GPG binary is not found. + */ +require_once 'PEAR/Exception.php'; + +// {{{ class Crypt_GPG_Engine + +/** + * Native PHP Crypt_GPG I/O engine + * + * This class is used internally by Crypt_GPG and does not need be used + * directly. See the {@link Crypt_GPG} class for end-user API. + * + * This engine uses PHP's native process control functions to directly control + * the GPG process. The GPG executable is required to be on the system. + * + * All data is passed to the GPG subprocess using file descriptors. This is the + * most secure method of passing data to the GPG subprocess. + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ +class Crypt_GPG_Engine +{ + // {{{ constants + + /** + * Size of data chunks that are sent to and retrieved from the IPC pipes. + * + * PHP reads 8192 bytes. If this is set to less than 8192, PHP reads 8192 + * and buffers the rest so we might as well just read 8192. + * + * Using values other than 8192 also triggers PHP bugs. + * + * @see http://bugs.php.net/bug.php?id=35224 + */ + const CHUNK_SIZE = 8192; + + /** + * Standard input file descriptor. This is used to pass data to the GPG + * process. + */ + const FD_INPUT = 0; + + /** + * Standard output file descriptor. This is used to receive normal output + * from the GPG process. + */ + const FD_OUTPUT = 1; + + /** + * Standard output file descriptor. This is used to receive error output + * from the GPG process. + */ + const FD_ERROR = 2; + + /** + * GPG status output file descriptor. The status file descriptor outputs + * detailed information for many GPG commands. See the second section of + * the file <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG package} for a detailed + * description of GPG's status output. + */ + const FD_STATUS = 3; + + /** + * Command input file descriptor. This is used for methods requiring + * passphrases. + */ + const FD_COMMAND = 4; + + /** + * Extra message input file descriptor. This is used for passing signed + * data when verifying a detached signature. + */ + const FD_MESSAGE = 5; + + /** + * Minimum version of GnuPG that is supported. + */ + const MIN_VERSION = '1.0.2'; + + // }}} + // {{{ private class properties + + /** + * Whether or not to use debugging mode + * + * When set to true, every GPG command is echoed before it is run. Sensitive + * data is always handled using pipes and is not specified as part of the + * command. As a result, sensitive data is never displayed when debug is + * enabled. Sensitive data includes private key data and passphrases. + * + * Debugging is off by default. + * + * @var boolean + * @see Crypt_GPG_Engine::__construct() + */ + private $_debug = false; + + /** + * Location of GPG binary + * + * @var string + * @see Crypt_GPG_Engine::__construct() + * @see Crypt_GPG_Engine::_getBinary() + */ + private $_binary = ''; + + /** + * Directory containing the GPG key files + * + * This property only contains the path when the <i>homedir</i> option + * is specified in the constructor. + * + * @var string + * @see Crypt_GPG_Engine::__construct() + */ + private $_homedir = ''; + + /** + * File path of the public keyring + * + * This property only contains the file path when the <i>public_keyring</i> + * option is specified in the constructor. + * + * If the specified file path starts with <kbd>~/</kbd>, the path is + * relative to the <i>homedir</i> if specified, otherwise to + * <kbd>~/.gnupg</kbd>. + * + * @var string + * @see Crypt_GPG_Engine::__construct() + */ + private $_publicKeyring = ''; + + /** + * File path of the private (secret) keyring + * + * This property only contains the file path when the <i>private_keyring</i> + * option is specified in the constructor. + * + * If the specified file path starts with <kbd>~/</kbd>, the path is + * relative to the <i>homedir</i> if specified, otherwise to + * <kbd>~/.gnupg</kbd>. + * + * @var string + * @see Crypt_GPG_Engine::__construct() + */ + private $_privateKeyring = ''; + + /** + * File path of the trust database + * + * This property only contains the file path when the <i>trust_db</i> + * option is specified in the constructor. + * + * If the specified file path starts with <kbd>~/</kbd>, the path is + * relative to the <i>homedir</i> if specified, otherwise to + * <kbd>~/.gnupg</kbd>. + * + * @var string + * @see Crypt_GPG_Engine::__construct() + */ + private $_trustDb = ''; + + /** + * Array of pipes used for communication with the GPG binary + * + * This is an array of file descriptor resources. + * + * @var array + */ + private $_pipes = array(); + + /** + * Array of currently opened pipes + * + * This array is used to keep track of remaining opened pipes so they can + * be closed when the GPG subprocess is finished. This array is a subset of + * the {@link Crypt_GPG_Engine::$_pipes} array and contains opened file + * descriptor resources. + * + * @var array + * @see Crypt_GPG_Engine::_closePipe() + */ + private $_openPipes = array(); + + /** + * A handle for the GPG process + * + * @var resource + */ + private $_process = null; + + /** + * Whether or not the operating system is Darwin (OS X) + * + * @var boolean + */ + private $_isDarwin = false; + + /** + * Commands to be sent to GPG's command input stream + * + * @var string + * @see Crypt_GPG_Engine::sendCommand() + */ + private $_commandBuffer = ''; + + /** + * Array of status line handlers + * + * @var array + * @see Crypt_GPG_Engine::addStatusHandler() + */ + private $_statusHandlers = array(); + + /** + * Array of error line handlers + * + * @var array + * @see Crypt_GPG_Engine::addErrorHandler() + */ + private $_errorHandlers = array(); + + /** + * The error code of the current operation + * + * @var integer + * @see Crypt_GPG_Engine::getErrorCode() + */ + private $_errorCode = Crypt_GPG::ERROR_NONE; + + /** + * File related to the error code of the current operation + * + * @var string + * @see Crypt_GPG_Engine::getErrorFilename() + */ + private $_errorFilename = ''; + + /** + * Key id related to the error code of the current operation + * + * @var string + * @see Crypt_GPG_Engine::getErrorKeyId() + */ + private $_errorkeyId = ''; + + /** + * The number of currently needed passphrases + * + * If this is not zero when the GPG command is completed, the error code is + * set to {@link Crypt_GPG::ERROR_MISSING_PASSPHRASE}. + * + * @var integer + */ + private $_needPassphrase = 0; + + /** + * The input source + * + * This is data to send to GPG. Either a string or a stream resource. + * + * @var string|resource + * @see Crypt_GPG_Engine::setInput() + */ + private $_input = null; + + /** + * The extra message input source + * + * Either a string or a stream resource. + * + * @var string|resource + * @see Crypt_GPG_Engine::setMessage() + */ + private $_message = null; + + /** + * The output location + * + * This is where the output from GPG is sent. Either a string or a stream + * resource. + * + * @var string|resource + * @see Crypt_GPG_Engine::setOutput() + */ + private $_output = ''; + + /** + * The GPG operation to execute + * + * @var string + * @see Crypt_GPG_Engine::setOperation() + */ + private $_operation; + + /** + * Arguments for the current operation + * + * @var array + * @see Crypt_GPG_Engine::setOperation() + */ + private $_arguments = array(); + + /** + * The version number of the GPG binary + * + * @var string + * @see Crypt_GPG_Engine::getVersion() + */ + private $_version = ''; + + /** + * Cached value indicating whether or not mbstring function overloading is + * on for strlen + * + * This is cached for optimal performance inside the I/O loop. + * + * @var boolean + * @see Crypt_GPG_Engine::_byteLength() + * @see Crypt_GPG_Engine::_byteSubstring() + */ + private static $_mbStringOverload = null; + + // }}} + // {{{ __construct() + + /** + * Creates a new GPG engine + * + * Available options are: + * + * - <kbd>string homedir</kbd> - the directory where the GPG + * keyring files are stored. If not + * specified, Crypt_GPG uses the + * default of <kbd>~/.gnupg</kbd>. + * - <kbd>string publicKeyring</kbd> - the file path of the public + * keyring. Use this if the public + * keyring is not in the homedir, or + * if the keyring is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * keyring with this option + * (/foo/bar/pubring.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string privateKeyring</kbd> - the file path of the private + * keyring. Use this if the private + * keyring is not in the homedir, or + * if the keyring is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * keyring with this option + * (/foo/bar/secring.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string trustDb</kbd> - the file path of the web-of-trust + * database. Use this if the trust + * database is not in the homedir, or + * if the database is in a directory + * not writable by the process + * invoking GPG (like Apache). Then + * you can specify the path to the + * trust database with this option + * (/foo/bar/trustdb.gpg), and specify + * a writable directory (like /tmp) + * using the <i>homedir</i> option. + * - <kbd>string binary</kbd> - the location of the GPG binary. If + * not specified, the driver attempts + * to auto-detect the GPG binary + * location using a list of known + * default locations for the current + * operating system. The option + * <kbd>gpgBinary</kbd> is a + * deprecated alias for this option. + * - <kbd>boolean debug</kbd> - whether or not to use debug mode. + * When debug mode is on, all + * communication to and from the GPG + * subprocess is logged. This can be + * useful to diagnose errors when + * using Crypt_GPG. + * + * @param array $options optional. An array of options used to create the + * GPG object. All options are optional and are + * represented as key-value pairs. + * + * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist + * and cannot be created. This can happen if <kbd>homedir</kbd> is + * not specified, Crypt_GPG is run as the web user, and the web + * user has no home directory. This exception is also thrown if any + * of the options <kbd>publicKeyring</kbd>, + * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are + * specified but the files do not exist or are are not readable. + * This can happen if the user running the Crypt_GPG process (for + * example, the Apache user) does not have permission to read the + * files. + * + * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or + * if no <kbd>binary</kbd> is provided and no suitable binary could + * be found. + */ + public function __construct(array $options = array()) + { + $this->_isDarwin = (strncmp(strtoupper(PHP_OS), 'DARWIN', 6) === 0); + + // populate mbstring overloading cache if not set + if (self::$_mbStringOverload === null) { + self::$_mbStringOverload = (extension_loaded('mbstring') + && (ini_get('mbstring.func_overload') & 0x02) === 0x02); + } + + // get homedir + if (array_key_exists('homedir', $options)) { + $this->_homedir = (string)$options['homedir']; + } else { + // note: this requires the package OS dep exclude 'windows' + $info = posix_getpwuid(posix_getuid()); + $this->_homedir = $info['dir'].'/.gnupg'; + } + + // attempt to create homedir if it does not exist + if (!is_dir($this->_homedir)) { + if (@mkdir($this->_homedir, 0777, true)) { + // Set permissions on homedir. Parent directories are created + // with 0777, homedir is set to 0700. + chmod($this->_homedir, 0700); + } else { + throw new Crypt_GPG_FileException('The \'homedir\' "' . + $this->_homedir . '" is not readable or does not exist '. + 'and cannot be created. This can happen if \'homedir\' '. + 'is not specified in the Crypt_GPG options, Crypt_GPG is '. + 'run as the web user, and the web user has no home '. + 'directory.', + 0, $this->_homedir); + } + } + + // get binary + if (array_key_exists('binary', $options)) { + $this->_binary = (string)$options['binary']; + } elseif (array_key_exists('gpgBinary', $options)) { + // deprecated alias + $this->_binary = (string)$options['gpgBinary']; + } else { + $this->_binary = $this->_getBinary(); + } + + if ($this->_binary == '' || !is_executable($this->_binary)) { + throw new PEAR_Exception('GPG binary not found. If you are sure '. + 'the GPG binary is installed, please specify the location of '. + 'the GPG binary using the \'binary\' driver option.'); + } + + /* + * Note: + * + * Normally, GnuPG expects keyrings to be in the homedir and expects + * to be able to write temporary files in the homedir. Sometimes, + * keyrings are not in the homedir, or location of the keyrings does + * not allow writing temporary files. In this case, the <i>homedir</i> + * option by itself is not enough to specify the keyrings because GnuPG + * can not write required temporary files. Additional options are + * provided so you can specify the location of the keyrings separately + * from the homedir. + */ + + // get public keyring + if (array_key_exists('publicKeyring', $options)) { + $this->_publicKeyring = (string)$options['publicKeyring']; + if (!is_readable($this->_publicKeyring)) { + throw new Crypt_GPG_FileException('The \'publicKeyring\' "' . + $this->_publicKeyring . '" does not exist or is ' . + 'not readable. Check the location and ensure the file ' . + 'permissions are correct.', 0, $this->_publicKeyring); + } + } + + // get private keyring + if (array_key_exists('privateKeyring', $options)) { + $this->_privateKeyring = (string)$options['privateKeyring']; + if (!is_readable($this->_privateKeyring)) { + throw new Crypt_GPG_FileException('The \'privateKeyring\' "' . + $this->_privateKeyring . '" does not exist or is ' . + 'not readable. Check the location and ensure the file ' . + 'permissions are correct.', 0, $this->_privateKeyring); + } + } + + // get trust database + if (array_key_exists('trustDb', $options)) { + $this->_trustDb = (string)$options['trustDb']; + if (!is_readable($this->_trustDb)) { + throw new Crypt_GPG_FileException('The \'trustDb\' "' . + $this->_trustDb . '" does not exist or is not readable. ' . + 'Check the location and ensure the file permissions are ' . + 'correct.', 0, $this->_trustDb); + } + } + + if (array_key_exists('debug', $options)) { + $this->_debug = (boolean)$options['debug']; + } + } + + // }}} + // {{{ __destruct() + + /** + * Closes open GPG subprocesses when this object is destroyed + * + * Subprocesses should never be left open by this class unless there is + * an unknown error and unexpected script termination occurs. + */ + public function __destruct() + { + $this->_closeSubprocess(); + } + + // }}} + // {{{ addErrorHandler() + + /** + * Adds an error handler method + * + * The method is run every time a new error line is received from the GPG + * subprocess. The handler method must accept the error line to be handled + * as its first parameter. + * + * @param callback $callback the callback method to use. + * @param array $args optional. Additional arguments to pass as + * parameters to the callback method. + * + * @return void + */ + public function addErrorHandler($callback, array $args = array()) + { + $this->_errorHandlers[] = array( + 'callback' => $callback, + 'args' => $args + ); + } + + // }}} + // {{{ addStatusHandler() + + /** + * Adds a status handler method + * + * The method is run every time a new status line is received from the + * GPG subprocess. The handler method must accept the status line to be + * handled as its first parameter. + * + * @param callback $callback the callback method to use. + * @param array $args optional. Additional arguments to pass as + * parameters to the callback method. + * + * @return void + */ + public function addStatusHandler($callback, array $args = array()) + { + $this->_statusHandlers[] = array( + 'callback' => $callback, + 'args' => $args + ); + } + + // }}} + // {{{ sendCommand() + + /** + * Sends a command to the GPG subprocess over the command file-descriptor + * pipe + * + * @param string $command the command to send. + * + * @return void + * + * @sensitive $command + */ + public function sendCommand($command) + { + if (array_key_exists(self::FD_COMMAND, $this->_openPipes)) { + $this->_commandBuffer .= $command . PHP_EOL; + } + } + + // }}} + // {{{ reset() + + /** + * Resets the GPG engine, preparing it for a new operation + * + * @return void + * + * @see Crypt_GPG_Engine::run() + * @see Crypt_GPG_Engine::setOperation() + */ + public function reset() + { + $this->_operation = ''; + $this->_arguments = array(); + $this->_input = null; + $this->_message = null; + $this->_output = ''; + $this->_errorCode = Crypt_GPG::ERROR_NONE; + $this->_needPassphrase = 0; + $this->_commandBuffer = ''; + + $this->_statusHandlers = array(); + $this->_errorHandlers = array(); + + $this->addStatusHandler(array($this, '_handleErrorStatus')); + $this->addErrorHandler(array($this, '_handleErrorError')); + + if ($this->_debug) { + $this->addStatusHandler(array($this, '_handleDebugStatus')); + $this->addErrorHandler(array($this, '_handleDebugError')); + } + } + + // }}} + // {{{ run() + + /** + * Runs the current GPG operation + * + * This creates and manages the GPG subprocess. + * + * The operation must be set with {@link Crypt_GPG_Engine::setOperation()} + * before this method is called. + * + * @return void + * + * @throws Crypt_GPG_InvalidOperationException if no operation is specified. + * + * @see Crypt_GPG_Engine::reset() + * @see Crypt_GPG_Engine::setOperation() + */ + public function run() + { + if ($this->_operation === '') { + throw new Crypt_GPG_InvalidOperationException('No GPG operation ' . + 'specified. Use Crypt_GPG_Engine::setOperation() before ' . + 'calling Crypt_GPG_Engine::run().'); + } + + $this->_openSubprocess(); + $this->_process(); + $this->_closeSubprocess(); + } + + // }}} + // {{{ getErrorCode() + + /** + * Gets the error code of the last executed operation + * + * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has + * been executed. + * + * @return integer the error code of the last executed operation. + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + // }}} + // {{{ getErrorFilename() + + /** + * Gets the file related to the error code of the last executed operation + * + * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has + * been executed. If there is no file related to the error, an empty string + * is returned. + * + * @return string the file related to the error code of the last executed + * operation. + */ + public function getErrorFilename() + { + return $this->_errorFilename; + } + + // }}} + // {{{ getErrorKeyId() + + /** + * Gets the key id related to the error code of the last executed operation + * + * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has + * been executed. If there is no key id related to the error, an empty + * string is returned. + * + * @return string the key id related to the error code of the last executed + * operation. + */ + public function getErrorKeyId() + { + return $this->_errorKeyId; + } + + // }}} + // {{{ setInput() + + /** + * Sets the input source for the current GPG operation + * + * @param string|resource &$input either a reference to the string + * containing the input data or an open + * stream resource containing the input + * data. + * + * @return void + */ + public function setInput(&$input) + { + $this->_input =& $input; + } + + // }}} + // {{{ setMessage() + + /** + * Sets the message source for the current GPG operation + * + * Detached signature data should be specified here. + * + * @param string|resource &$message either a reference to the string + * containing the message data or an open + * stream resource containing the message + * data. + * + * @return void + */ + public function setMessage(&$message) + { + $this->_message =& $message; + } + + // }}} + // {{{ setOutput() + + /** + * Sets the output destination for the current GPG operation + * + * @param string|resource &$output either a reference to the string in + * which to store GPG output or an open + * stream resource to which the output data + * should be written. + * + * @return void + */ + public function setOutput(&$output) + { + $this->_output =& $output; + } + + // }}} + // {{{ setOperation() + + /** + * Sets the operation to perform + * + * @param string $operation the operation to perform. This should be one + * of GPG's operations. For example, + * <kbd>--encrypt</kbd>, <kbd>--decrypt</kbd>, + * <kbd>--sign</kbd>, etc. + * @param array $arguments optional. Additional arguments for the GPG + * subprocess. See the GPG manual for specific + * values. + * + * @return void + * + * @see Crypt_GPG_Engine::reset() + * @see Crypt_GPG_Engine::run() + */ + public function setOperation($operation, array $arguments = array()) + { + $this->_operation = $operation; + $this->_arguments = $arguments; + } + + // }}} + // {{{ getVersion() + + /** + * Gets the version of the GnuPG binary + * + * @return string a version number string containing the version of GnuPG + * being used. This value is suitable to use with PHP's + * version_compare() function. + * + * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. + * Use the <kbd>debug</kbd> option and file a bug report if these + * exceptions occur. + * + * @throws Crypt_GPG_UnsupportedException if the provided binary is not + * GnuPG or if the GnuPG version is less than 1.0.2. + */ + public function getVersion() + { + if ($this->_version == '') { + + $options = array( + 'homedir' => $this->_homedir, + 'binary' => $this->_binary, + 'debug' => $this->_debug + ); + + $engine = new self($options); + $info = ''; + + // Set a garbage version so we do not end up looking up the version + // recursively. + $engine->_version = '1.0.0'; + + $engine->reset(); + $engine->setOutput($info); + $engine->setOperation('--version'); + $engine->run(); + + $code = $this->getErrorCode(); + + if ($code !== Crypt_GPG::ERROR_NONE) { + throw new Crypt_GPG_Exception( + 'Unknown error getting GnuPG version information. Please ' . + 'use the \'debug\' option when creating the Crypt_GPG ' . + 'object, and file a bug report at ' . Crypt_GPG::BUG_URI, + $code); + } + + $matches = array(); + $expression = '/gpg \(GnuPG\) (\S+)/'; + + if (preg_match($expression, $info, $matches) === 1) { + $this->_version = $matches[1]; + } else { + throw new Crypt_GPG_Exception( + 'No GnuPG version information provided by the binary "' . + $this->_binary . '". Are you sure it is GnuPG?'); + } + + if (version_compare($this->_version, self::MIN_VERSION, 'lt')) { + throw new Crypt_GPG_Exception( + 'The version of GnuPG being used (' . $this->_version . + ') is not supported by Crypt_GPG. The minimum version ' . + 'required by Crypt_GPG is ' . self::MIN_VERSION); + } + } + + + return $this->_version; + } + + // }}} + // {{{ _handleErrorStatus() + + /** + * Handles error values in the status output from GPG + * + * This method is responsible for setting the + * {@link Crypt_GPG_Engine::$_errorCode}. See <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG distribution} for detailed + * information on GPG's status output. + * + * @param string $line the status line to handle. + * + * @return void + */ + private function _handleErrorStatus($line) + { + $tokens = explode(' ', $line); + switch ($tokens[0]) { + case 'BAD_PASSPHRASE': + $this->_errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE; + break; + + case 'MISSING_PASSPHRASE': + $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; + break; + + case 'NODATA': + $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; + break; + + case 'DELETE_PROBLEM': + if ($tokens[1] == '1') { + $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; + break; + } elseif ($tokens[1] == '2') { + $this->_errorCode = Crypt_GPG::ERROR_DELETE_PRIVATE_KEY; + break; + } + break; + + case 'IMPORT_RES': + if ($tokens[12] > 0) { + $this->_errorCode = Crypt_GPG::ERROR_DUPLICATE_KEY; + } + break; + + case 'NO_PUBKEY': + case 'NO_SECKEY': + $this->_errorKeyId = $tokens[1]; + $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; + break; + + case 'NEED_PASSPHRASE': + $this->_needPassphrase++; + break; + + case 'GOOD_PASSPHRASE': + $this->_needPassphrase--; + break; + + case 'EXPSIG': + case 'EXPKEYSIG': + case 'REVKEYSIG': + case 'BADSIG': + $this->_errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE; + break; + + } + } + + // }}} + // {{{ _handleErrorError() + + /** + * Handles error values in the error output from GPG + * + * This method is responsible for setting the + * {@link Crypt_GPG_Engine::$_errorCode}. + * + * @param string $line the error line to handle. + * + * @return void + */ + private function _handleErrorError($line) + { + if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { + $pattern = '/no valid OpenPGP data found/'; + if (preg_match($pattern, $line) === 1) { + $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; + } + } + + if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { + $pattern = '/No secret key|secret key not available/'; + if (preg_match($pattern, $line) === 1) { + $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; + } + } + + if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { + $pattern = '/No public key|public key not found/'; + if (preg_match($pattern, $line) === 1) { + $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; + } + } + + if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { + $matches = array(); + $pattern = '/can\'t (?:access|open) `(.*?)\'/'; + if (preg_match($pattern, $line, $matches) === 1) { + $this->_errorFilename = $matches[1]; + $this->_errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS; + } + } + } + + // }}} + // {{{ _handleDebugStatus() + + /** + * Displays debug output for status lines + * + * @param string $line the status line to handle. + * + * @return void + */ + private function _handleDebugStatus($line) + { + $this->_debug('STATUS: ' . $line); + } + + // }}} + // {{{ _handleDebugError() + + /** + * Displays debug output for error lines + * + * @param string $line the error line to handle. + * + * @return void + */ + private function _handleDebugError($line) + { + $this->_debug('ERROR: ' . $line); + } + + // }}} + // {{{ _process() + + /** + * Performs internal streaming operations for the subprocess using either + * strings or streams as input / output points + * + * This is the main I/O loop for streaming to and from the GPG subprocess. + * + * The implementation of this method is verbose mainly for performance + * reasons. Adding streams to a lookup array and looping the array inside + * the main I/O loop would be siginficantly slower for large streams. + * + * @return void + * + * @throws Crypt_GPG_Exception if there is an error selecting streams for + * reading or writing. If this occurs, please file a bug report at + * http://pear.php.net/bugs/report.php?package=Crypt_GPG. + */ + private function _process() + { + $this->_debug('BEGIN PROCESSING'); + + $this->_commandBuffer = ''; // buffers input to GPG + $messageBuffer = ''; // buffers input to GPG + $inputBuffer = ''; // buffers input to GPG + $outputBuffer = ''; // buffers output from GPG + $statusBuffer = ''; // buffers output from GPG + $errorBuffer = ''; // buffers output from GPG + $inputComplete = false; // input stream is completely buffered + $messageComplete = false; // message stream is completely buffered + + if (is_string($this->_input)) { + $inputBuffer = $this->_input; + $inputComplete = true; + } + + if (is_string($this->_message)) { + $messageBuffer = $this->_message; + $messageComplete = true; + } + + if (is_string($this->_output)) { + $outputBuffer =& $this->_output; + } + + // convenience variables + $fdInput = $this->_pipes[self::FD_INPUT]; + $fdOutput = $this->_pipes[self::FD_OUTPUT]; + $fdError = $this->_pipes[self::FD_ERROR]; + $fdStatus = $this->_pipes[self::FD_STATUS]; + $fdCommand = $this->_pipes[self::FD_COMMAND]; + $fdMessage = $this->_pipes[self::FD_MESSAGE]; + + while (true) { + + $inputStreams = array(); + $outputStreams = array(); + $exceptionStreams = array(); + + // set up input streams + if (is_resource($this->_input) && !$inputComplete) { + if (feof($this->_input)) { + $inputComplete = true; + } else { + $inputStreams[] = $this->_input; + } + } + + // close GPG input pipe if there is no more data + if ($inputBuffer == '' && $inputComplete) { + $this->_debug('=> closing GPG input pipe'); + $this->_closePipe(self::FD_INPUT); + } + + if (is_resource($this->_message) && !$messageComplete) { + if (feof($this->_message)) { + $messageComplete = true; + } else { + $inputStreams[] = $this->_message; + } + } + + // close GPG message pipe if there is no more data + if ($messageBuffer == '' && $messageComplete) { + $this->_debug('=> closing GPG message pipe'); + $this->_closePipe(self::FD_MESSAGE); + } + + if (!feof($fdOutput)) { + $inputStreams[] = $fdOutput; + } + + if (!feof($fdStatus)) { + $inputStreams[] = $fdStatus; + } + + if (!feof($fdError)) { + $inputStreams[] = $fdError; + } + + // set up output streams + if ($outputBuffer != '' && is_resource($this->_output)) { + $outputStreams[] = $this->_output; + } + + if ($this->_commandBuffer != '') { + $outputStreams[] = $fdCommand; + } + + if ($messageBuffer != '') { + $outputStreams[] = $fdMessage; + } + + if ($inputBuffer != '') { + $outputStreams[] = $fdInput; + } + + // no streams left to read or write, we're all done + if (count($inputStreams) === 0 && count($outputStreams) === 0) { + break; + } + + $this->_debug('selecting streams'); + + $ready = stream_select( + $inputStreams, + $outputStreams, + $exceptionStreams, + null + ); + + $this->_debug('=> got ' . $ready); + + if ($ready === false) { + throw new Crypt_GPG_Exception( + 'Error selecting stream for communication with GPG ' . + 'subprocess. Please file a bug report at: ' . + 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); + } + + if ($ready === 0) { + throw new Crypt_GPG_Exception( + 'stream_select() returned 0. This can not happen! Please ' . + 'file a bug report at: ' . + 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); + } + + // write input (to GPG) + if (in_array($fdInput, $outputStreams)) { + $this->_debug('GPG is ready for input'); + + $chunk = self::_byteSubstring( + $inputBuffer, + 0, + self::CHUNK_SIZE + ); + + $length = self::_byteLength($chunk); + + $this->_debug( + '=> about to write ' . $length . ' bytes to GPG input' + ); + + $length = fwrite($fdInput, $chunk, $length); + + $this->_debug('=> wrote ' . $length . ' bytes'); + + $inputBuffer = self::_byteSubstring( + $inputBuffer, + $length + ); + } + + // read input (from PHP stream) + if (in_array($this->_input, $inputStreams)) { + $this->_debug('input stream is ready for reading'); + $this->_debug( + '=> about to read ' . self::CHUNK_SIZE . + ' bytes from input stream' + ); + + $chunk = fread($this->_input, self::CHUNK_SIZE); + $length = self::_byteLength($chunk); + $inputBuffer .= $chunk; + + $this->_debug('=> read ' . $length . ' bytes'); + } + + // write message (to GPG) + if (in_array($fdMessage, $outputStreams)) { + $this->_debug('GPG is ready for message data'); + + $chunk = self::_byteSubstring( + $messageBuffer, + 0, + self::CHUNK_SIZE + ); + + $length = self::_byteLength($chunk); + + $this->_debug( + '=> about to write ' . $length . ' bytes to GPG message' + ); + + $length = fwrite($fdMessage, $chunk, $length); + $this->_debug('=> wrote ' . $length . ' bytes'); + + $messageBuffer = self::_byteSubstring($messageBuffer, $length); + } + + // read message (from PHP stream) + if (in_array($this->_message, $inputStreams)) { + $this->_debug('message stream is ready for reading'); + $this->_debug( + '=> about to read ' . self::CHUNK_SIZE . + ' bytes from message stream' + ); + + $chunk = fread($this->_message, self::CHUNK_SIZE); + $length = self::_byteLength($chunk); + $messageBuffer .= $chunk; + + $this->_debug('=> read ' . $length . ' bytes'); + } + + // read output (from GPG) + if (in_array($fdOutput, $inputStreams)) { + $this->_debug('GPG output stream ready for reading'); + $this->_debug( + '=> about to read ' . self::CHUNK_SIZE . + ' bytes from GPG output' + ); + + $chunk = fread($fdOutput, self::CHUNK_SIZE); + $length = self::_byteLength($chunk); + $outputBuffer .= $chunk; + + $this->_debug('=> read ' . $length . ' bytes'); + } + + // write output (to PHP stream) + if (in_array($this->_output, $outputStreams)) { + $this->_debug('output stream is ready for data'); + + $chunk = self::_byteSubstring( + $outputBuffer, + 0, + self::CHUNK_SIZE + ); + + $length = self::_byteLength($chunk); + + $this->_debug( + '=> about to write ' . $length . ' bytes to output stream' + ); + + $length = fwrite($this->_output, $chunk, $length); + + $this->_debug('=> wrote ' . $length . ' bytes'); + + $outputBuffer = self::_byteSubstring($outputBuffer, $length); + } + + // read error (from GPG) + if (in_array($fdError, $inputStreams)) { + $this->_debug('GPG error stream ready for reading'); + $this->_debug( + '=> about to read ' . self::CHUNK_SIZE . + ' bytes from GPG error' + ); + + $chunk = fread($fdError, self::CHUNK_SIZE); + $length = self::_byteLength($chunk); + $errorBuffer .= $chunk; + + $this->_debug('=> read ' . $length . ' bytes'); + + // pass lines to error handlers + while (($pos = strpos($errorBuffer, PHP_EOL)) !== false) { + $line = self::_byteSubstring($errorBuffer, 0, $pos); + foreach ($this->_errorHandlers as $handler) { + array_unshift($handler['args'], $line); + call_user_func_array( + $handler['callback'], + $handler['args'] + ); + + array_shift($handler['args']); + } + $errorBuffer = self::_byteSubString( + $errorBuffer, + $pos + self::_byteLength(PHP_EOL) + ); + } + } + + // read status (from GPG) + if (in_array($fdStatus, $inputStreams)) { + $this->_debug('GPG status stream ready for reading'); + $this->_debug( + '=> about to read ' . self::CHUNK_SIZE . + ' bytes from GPG status' + ); + + $chunk = fread($fdStatus, self::CHUNK_SIZE); + $length = self::_byteLength($chunk); + $statusBuffer .= $chunk; + + $this->_debug('=> read ' . $length . ' bytes'); + + // pass lines to status handlers + while (($pos = strpos($statusBuffer, PHP_EOL)) !== false) { + $line = self::_byteSubstring($statusBuffer, 0, $pos); + // only pass lines beginning with magic prefix + if (self::_byteSubstring($line, 0, 9) == '[GNUPG:] ') { + $line = self::_byteSubstring($line, 9); + foreach ($this->_statusHandlers as $handler) { + array_unshift($handler['args'], $line); + call_user_func_array( + $handler['callback'], + $handler['args'] + ); + + array_shift($handler['args']); + } + } + $statusBuffer = self::_byteSubString( + $statusBuffer, + $pos + self::_byteLength(PHP_EOL) + ); + } + } + + // write command (to GPG) + if (in_array($fdCommand, $outputStreams)) { + $this->_debug('GPG is ready for command data'); + + // send commands + $chunk = self::_byteSubstring( + $this->_commandBuffer, + 0, + self::CHUNK_SIZE + ); + + $length = self::_byteLength($chunk); + + $this->_debug( + '=> about to write ' . $length . ' bytes to GPG command' + ); + + $length = fwrite($fdCommand, $chunk, $length); + + $this->_debug('=> wrote ' . $length); + + $this->_commandBuffer = self::_byteSubstring( + $this->_commandBuffer, + $length + ); + } + + } // end loop while streams are open + + $this->_debug('END PROCESSING'); + } + + // }}} + // {{{ _openSubprocess() + + /** + * Opens an internal GPG subprocess for the current operation + * + * Opens a GPG subprocess, then connects the subprocess to some pipes. Sets + * the private class property {@link Crypt_GPG_Engine::$_process} to + * the new subprocess. + * + * @return void + * + * @throws Crypt_GPG_OpenSubprocessException if the subprocess could not be + * opened. + * + * @see Crypt_GPG_Engine::setOperation() + * @see Crypt_GPG_Engine::_closeSubprocess() + * @see Crypt_GPG_Engine::$_process + */ + private function _openSubprocess() + { + $version = $this->getVersion(); + + $env = $_ENV; + + // Newer versions of GnuPG return localized results. Crypt_GPG only + // works with English, so set the locale to 'C' for the subprocess. + $env['LC_ALL'] = 'C'; + + $commandLine = $this->_binary; + + $defaultArguments = array( + '--status-fd ' . escapeshellarg(self::FD_STATUS), + '--command-fd ' . escapeshellarg(self::FD_COMMAND), + '--no-secmem-warning', + '--no-tty', + '--no-default-keyring', // ignored if keying files are not specified + '--no-options' // prevent creation of ~/.gnupg directory + ); + + if (version_compare($version, '1.0.7', 'ge')) { + if (version_compare($version, '2.0.0', 'lt')) { + $defaultArguments[] = '--no-use-agent'; + } + $defaultArguments[] = '--no-permission-warning'; + } + + if (version_compare($version, '1.4.2', 'ge')) { + $defaultArguments[] = '--exit-on-status-write-error'; + } + + if (version_compare($version, '1.3.2', 'ge')) { + $defaultArguments[] = '--trust-model always'; + } else { + $defaultArguments[] = '--always-trust'; + } + + $arguments = array_merge($defaultArguments, $this->_arguments); + + if ($this->_homedir) { + $arguments[] = '--homedir ' . escapeshellarg($this->_homedir); + + // the random seed file makes subsequent actions faster so only + // disable it if we have to. + if (!is_writeable($this->_homedir)) { + $arguments[] = '--no-random-seed-file'; + } + } + + if ($this->_publicKeyring) { + $arguments[] = '--keyring ' . escapeshellarg($this->_publicKeyring); + } + + if ($this->_privateKeyring) { + $arguments[] = '--secret-keyring ' . + escapeshellarg($this->_privateKeyring); + } + + if ($this->_trustDb) { + $arguments[] = '--trustdb-name ' . escapeshellarg($this->_trustDb); + } + + $commandLine .= ' ' . implode(' ', $arguments) . ' ' . + $this->_operation; + + // Binary operations will not work on Windows with PHP < 5.2.6. This is + // in case stream_select() ever works on Windows. + $rb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'r' : 'rb'; + $wb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'w' : 'wb'; + + $descriptorSpec = array( + self::FD_INPUT => array('pipe', $rb), // stdin + self::FD_OUTPUT => array('pipe', $wb), // stdout + self::FD_ERROR => array('pipe', $wb), // stderr + self::FD_STATUS => array('pipe', $wb), // status + self::FD_COMMAND => array('pipe', $rb), // command + self::FD_MESSAGE => array('pipe', $rb) // message + ); + + $this->_debug('OPENING SUBPROCESS WITH THE FOLLOWING COMMAND:'); + $this->_debug($commandLine); + + $this->_process = proc_open( + $commandLine, + $descriptorSpec, + $this->_pipes, + null, + $env, + array('binary_pipes' => true) + ); + + if (!is_resource($this->_process)) { + throw new Crypt_GPG_OpenSubprocessException( + 'Unable to open GPG subprocess.', 0, $commandLine); + } + + $this->_openPipes = $this->_pipes; + $this->_errorCode = Crypt_GPG::ERROR_NONE; + } + + // }}} + // {{{ _closeSubprocess() + + /** + * Closes a the internal GPG subprocess + * + * Closes the internal GPG subprocess. Sets the private class property + * {@link Crypt_GPG_Engine::$_process} to null. + * + * @return void + * + * @see Crypt_GPG_Engine::_openSubprocess() + * @see Crypt_GPG_Engine::$_process + */ + private function _closeSubprocess() + { + if (is_resource($this->_process)) { + $this->_debug('CLOSING SUBPROCESS'); + + // close remaining open pipes + foreach (array_keys($this->_openPipes) as $pipeNumber) { + $this->_closePipe($pipeNumber); + } + + $exitCode = proc_close($this->_process); + + if ($exitCode != 0) { + $this->_debug( + '=> subprocess returned an unexpected exit code: ' . + $exitCode + ); + + if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { + if ($this->_needPassphrase > 0) { + $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; + } else { + $this->_errorCode = Crypt_GPG::ERROR_UNKNOWN; + } + } + } + + $this->_process = null; + $this->_pipes = array(); + } + } + + // }}} + // {{{ _closePipe() + + /** + * Closes an opened pipe used to communicate with the GPG subprocess + * + * If the pipe is already closed, it is ignored. If the pipe is open, it + * is flushed and then closed. + * + * @param integer $pipeNumber the file descriptor number of the pipe to + * close. + * + * @return void + */ + private function _closePipe($pipeNumber) + { + $pipeNumber = intval($pipeNumber); + if (array_key_exists($pipeNumber, $this->_openPipes)) { + fflush($this->_openPipes[$pipeNumber]); + fclose($this->_openPipes[$pipeNumber]); + unset($this->_openPipes[$pipeNumber]); + } + } + + // }}} + // {{{ _getBinary() + + /** + * Gets the name of the GPG binary for the current operating system + * + * This method is called if the '<kbd>binary</kbd>' option is <i>not</i> + * specified when creating this driver. + * + * @return string the name of the GPG binary for the current operating + * system. If no suitable binary could be found, an empty + * string is returned. + */ + private function _getBinary() + { + $binary = ''; + + if ($this->_isDarwin) { + $binaryFiles = array( + '/opt/local/bin/gpg', // MacPorts + '/usr/local/bin/gpg', // Mac GPG + '/sw/bin/gpg', // Fink + '/usr/bin/gpg' + ); + } else { + $binaryFiles = array( + '/usr/bin/gpg', + '/usr/local/bin/gpg' + ); + } + + foreach ($binaryFiles as $binaryFile) { + if (is_executable($binaryFile)) { + $binary = $binaryFile; + break; + } + } + + return $binary; + } + + // }}} + // {{{ _debug() + + /** + * Displays debug text if debugging is turned on + * + * Debugging text is prepended with a debug identifier and echoed to stdout. + * + * @param string $text the debugging text to display. + * + * @return void + */ + private function _debug($text) + { + if ($this->_debug) { + if (array_key_exists('SHELL', $_ENV)) { + foreach (explode(PHP_EOL, $text) as $line) { + echo "Crypt_GPG DEBUG: ", $line, PHP_EOL; + } + } else { + // running on a web server, format debug output nicely + foreach (explode(PHP_EOL, $text) as $line) { + echo "Crypt_GPG DEBUG: <strong>", $line, + '</strong><br />', PHP_EOL; + } + } + } + } + + // }}} + // {{{ _byteLength() + + /** + * Gets the length of a string in bytes even if mbstring function + * overloading is turned on + * + * This is used for stream-based communication with the GPG subprocess. + * + * @param string $string the string for which to get the length. + * + * @return integer the length of the string in bytes. + * + * @see Crypt_GPG_Engine::$_mbStringOverload + */ + private static function _byteLength($string) + { + if (self::$_mbStringOverload) { + return mb_strlen($string, '8bit'); + } + + return strlen((binary)$string); + } + + // }}} + // {{{ _byteSubstring() + + /** + * Gets the substring of a string in bytes even if mbstring function + * overloading is turned on + * + * This is used for stream-based communication with the GPG subprocess. + * + * @param string $string the input string. + * @param integer $start the starting point at which to get the substring. + * @param integer $length optional. The length of the substring. + * + * @return string the extracted part of the string. Unlike the default PHP + * <kbd>substr()</kbd> function, the returned value is + * always a string and never false. + * + * @see Crypt_GPG_Engine::$_mbStringOverload + */ + private static function _byteSubstring($string, $start, $length = null) + { + if (self::$_mbStringOverload) { + if ($length === null) { + return mb_substr( + $string, + $start, + self::_byteLength($string) - $start, '8bit' + ); + } + + return mb_substr($string, $start, $length, '8bit'); + } + + if ($length === null) { + return (string)substr((binary)$string, $start); + } + + return (string)substr((binary)$string, $start, $length); + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/Exceptions.php b/program/lib/Crypt/GPG/Exceptions.php new file mode 100644 index 000000000..744acf5d4 --- /dev/null +++ b/program/lib/Crypt/GPG/Exceptions.php @@ -0,0 +1,473 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Various exception handling classes for Crypt_GPG + * + * Crypt_GPG provides an object oriented interface to GNU Privacy + * Guard (GPG). It requires the GPG executable to be on the system. + * + * This file contains various exception classes used by the Crypt_GPG package. + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Exceptions.php 273745 2009-01-18 05:24:25Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + */ + +/** + * PEAR Exception handler and base class + */ +require_once 'PEAR/Exception.php'; + +// {{{ class Crypt_GPG_Exception + +/** + * An exception thrown by the Crypt_GPG package + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_Exception extends PEAR_Exception +{ +} + +// }}} +// {{{ class Crypt_GPG_FileException + +/** + * An exception thrown when a file is used in ways it cannot be used + * + * For example, if an output file is specified and the file is not writeable, or + * if an input file is specified and the file is not readable, this exception + * is thrown. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2007-2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_FileException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * The name of the file that caused this exception + * + * @var string + */ + private $_filename = ''; + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_FileException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $filename the name of the file that caused this exception. + */ + public function __construct($message, $code = 0, $filename = '') + { + $this->_filename = $filename; + parent::__construct($message, $code); + } + + // }}} + // {{{ getFilename() + + /** + * Returns the filename of the file that caused this exception + * + * @return string the filename of the file that caused this exception. + * + * @see Crypt_GPG_FileException::$_filename + */ + public function getFilename() + { + return $this->_filename; + } + + // }}} +} + +// }}} +// {{{ class Crypt_GPG_OpenSubprocessException + +/** + * An exception thrown when the GPG subprocess cannot be opened + * + * This exception is thrown when the {@link Crypt_GPG_Engine} tries to open a + * new subprocess and fails. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_OpenSubprocessException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * The command used to try to open the subprocess + * + * @var string + */ + private $_command = ''; + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_OpenSubprocessException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $command the command that was called to open the + * new subprocess. + * + * @see Crypt_GPG::_openSubprocess() + */ + public function __construct($message, $code = 0, $command = '') + { + $this->_command = $command; + parent::__construct($message, $code); + } + + // }}} + // {{{ getCommand() + + /** + * Returns the contents of the internal _command property + * + * @return string the command used to open the subprocess. + * + * @see Crypt_GPG_OpenSubprocessException::$_command + */ + public function getCommand() + { + return $this->_command; + } + + // }}} +} + +// }}} +// {{{ class Crypt_GPG_InvalidOperationException + +/** + * An exception thrown when an invalid GPG operation is attempted + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_InvalidOperationException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * The attempted operation + * + * @var string + */ + private $_operation = ''; + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_OpenSubprocessException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $operation the operation. + */ + public function __construct($message, $code = 0, $operation = '') + { + $this->_operation = $operation; + parent::__construct($message, $code); + } + + // }}} + // {{{ getOperation() + + /** + * Returns the contents of the internal _operation property + * + * @return string the attempted operation. + * + * @see Crypt_GPG_InvalidOperationException::$_operation + */ + public function getOperation() + { + return $this->_operation; + } + + // }}} +} + +// }}} +// {{{ class Crypt_GPG_KeyNotFoundException + +/** + * An exception thrown when Crypt_GPG fails to find the key for various + * operations + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_KeyNotFoundException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * The key identifier that was searched for + * + * @var string + */ + private $_keyId = ''; + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_KeyNotFoundException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $keyId the key identifier of the key. + */ + public function __construct($message, $code = 0, $keyId= '') + { + $this->_keyId = $keyId; + parent::__construct($message, $code); + } + + // }}} + // {{{ getKeyId() + + /** + * Gets the key identifier of the key that was not found + * + * @return string the key identifier of the key that was not found. + */ + public function getKeyId() + { + return $this->_keyId; + } + + // }}} +} + +// }}} +// {{{ class Crypt_GPG_NoDataException + +/** + * An exception thrown when Crypt_GPG cannot find valid data for various + * operations + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2006 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_NoDataException extends Crypt_GPG_Exception +{ +} + +// }}} +// {{{ class Crypt_GPG_BadPassphraseException + +/** + * An exception thrown when a required passphrase is incorrect or missing + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2006-2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_BadPassphraseException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * Keys for which the passhprase is missing + * + * This contains primary user ids indexed by sub-key id. + * + * @var array + */ + private $_missingPassphrases = array(); + + /** + * Keys for which the passhprase is incorrect + * + * This contains primary user ids indexed by sub-key id. + * + * @var array + */ + private $_badPassphrases = array(); + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_BadPassphraseException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $badPassphrases an array containing user ids of keys + * for which the passphrase is incorrect. + * @param string $missingPassphrases an array containing user ids of keys + * for which the passphrase is missing. + */ + public function __construct($message, $code = 0, + array $badPassphrases = array(), array $missingPassphrases = array() + ) { + $this->_badPassphrases = $badPassphrases; + $this->_missingPassphrases = $missingPassphrases; + + parent::__construct($message, $code); + } + + // }}} + // {{{ getBadPassphrases() + + /** + * Gets keys for which the passhprase is incorrect + * + * @return array an array of keys for which the passphrase is incorrect. + * The array contains primary user ids indexed by the sub-key + * id. + */ + public function getBadPassphrases() + { + return $this->_badPassphrases; + } + + // }}} + // {{{ getMissingPassphrases() + + /** + * Gets keys for which the passhprase is missing + * + * @return array an array of keys for which the passphrase is missing. + * The array contains primary user ids indexed by the sub-key + * id. + */ + public function getMissingPassphrases() + { + return $this->_missingPassphrases; + } + + // }}} +} + +// }}} +// {{{ class Crypt_GPG_DeletePrivateKeyException + +/** + * An exception thrown when an attempt is made to delete public key that has an + * associated private key on the keyring + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + */ +class Crypt_GPG_DeletePrivateKeyException extends Crypt_GPG_Exception +{ + // {{{ private class properties + + /** + * The key identifier the deletion attempt was made upon + * + * @var string + */ + private $_keyId = ''; + + // }}} + // {{{ __construct() + + /** + * Creates a new Crypt_GPG_DeletePrivateKeyException + * + * @param string $message an error message. + * @param integer $code a user defined error code. + * @param string $keyId the key identifier of the public key that was + * attempted to delete. + * + * @see Crypt_GPG::deletePublicKey() + */ + public function __construct($message, $code = 0, $keyId = '') + { + $this->_keyId = $keyId; + parent::__construct($message, $code); + } + + // }}} + // {{{ getKeyId() + + /** + * Gets the key identifier of the key that was not found + * + * @return string the key identifier of the key that was not found. + */ + public function getKeyId() + { + return $this->_keyId; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/Key.php b/program/lib/Crypt/GPG/Key.php new file mode 100644 index 000000000..67a4b9c7d --- /dev/null +++ b/program/lib/Crypt/GPG/Key.php @@ -0,0 +1,223 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Contains a class representing GPG keys + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Key.php 295621 2010-03-01 04:18:54Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + */ + +/** + * Sub-key class definition + */ +require_once 'Crypt/GPG/SubKey.php'; + +/** + * User id class definition + */ +require_once 'Crypt/GPG/UserId.php'; + +// {{{ class Crypt_GPG_Key + +/** + * A data class for GPG key information + * + * This class is used to store the results of the {@link Crypt_GPG::getKeys()} + * method. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @see Crypt_GPG::getKeys() + */ +class Crypt_GPG_Key +{ + // {{{ class properties + + /** + * The user ids associated with this key + * + * This is an array of {@link Crypt_GPG_UserId} objects. + * + * @var array + * + * @see Crypt_GPG_Key::addUserId() + * @see Crypt_GPG_Key::getUserIds() + */ + private $_userIds = array(); + + /** + * The subkeys of this key + * + * This is an array of {@link Crypt_GPG_SubKey} objects. + * + * @var array + * + * @see Crypt_GPG_Key::addSubKey() + * @see Crypt_GPG_Key::getSubKeys() + */ + private $_subKeys = array(); + + // }}} + // {{{ getSubKeys() + + /** + * Gets the sub-keys of this key + * + * @return array the sub-keys of this key. + * + * @see Crypt_GPG_Key::addSubKey() + */ + public function getSubKeys() + { + return $this->_subKeys; + } + + // }}} + // {{{ getUserIds() + + /** + * Gets the user ids of this key + * + * @return array the user ids of this key. + * + * @see Crypt_GPG_Key::addUserId() + */ + public function getUserIds() + { + return $this->_userIds; + } + + // }}} + // {{{ getPrimaryKey() + + /** + * Gets the primary sub-key of this key + * + * The primary key is the first added sub-key. + * + * @return Crypt_GPG_SubKey the primary sub-key of this key. + */ + public function getPrimaryKey() + { + $primary_key = null; + if (count($this->_subKeys) > 0) { + $primary_key = $this->_subKeys[0]; + } + return $primary_key; + } + + // }}} + // {{{ canSign() + + /** + * Gets whether or not this key can sign data + * + * This key can sign data if any sub-key of this key can sign data. + * + * @return boolean true if this key can sign data and false if this key + * cannot sign data. + */ + public function canSign() + { + $canSign = false; + foreach ($this->_subKeys as $subKey) { + if ($subKey->canSign()) { + $canSign = true; + break; + } + } + return $canSign; + } + + // }}} + // {{{ canEncrypt() + + /** + * Gets whether or not this key can encrypt data + * + * This key can encrypt data if any sub-key of this key can encrypt data. + * + * @return boolean true if this key can encrypt data and false if this + * key cannot encrypt data. + */ + public function canEncrypt() + { + $canEncrypt = false; + foreach ($this->_subKeys as $subKey) { + if ($subKey->canEncrypt()) { + $canEncrypt = true; + break; + } + } + return $canEncrypt; + } + + // }}} + // {{{ addSubKey() + + /** + * Adds a sub-key to this key + * + * The first added sub-key will be the primary key of this key. + * + * @param Crypt_GPG_SubKey $subKey the sub-key to add. + * + * @return Crypt_GPG_Key the current object, for fluent interface. + */ + public function addSubKey(Crypt_GPG_SubKey $subKey) + { + $this->_subKeys[] = $subKey; + return $this; + } + + // }}} + // {{{ addUserId() + + /** + * Adds a user id to this key + * + * @param Crypt_GPG_UserId $userId the user id to add. + * + * @return Crypt_GPG_Key the current object, for fluent interface. + */ + public function addUserId(Crypt_GPG_UserId $userId) + { + $this->_userIds[] = $userId; + return $this; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/Signature.php b/program/lib/Crypt/GPG/Signature.php new file mode 100644 index 000000000..03ab44c53 --- /dev/null +++ b/program/lib/Crypt/GPG/Signature.php @@ -0,0 +1,428 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * A class representing GPG signatures + * + * This file contains a data class representing a GPG signature. + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Signature.php 302773 2010-08-25 14:16:28Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + */ + +/** + * User id class definition + */ +require_once 'Crypt/GPG/UserId.php'; + +// {{{ class Crypt_GPG_Signature + +/** + * A class for GPG signature information + * + * This class is used to store the results of the Crypt_GPG::verify() method. + * + * @category Encryption + * @package Crypt_GPG + * @author Nathan Fredrickson <nathan@silverorange.com> + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @see Crypt_GPG::verify() + */ +class Crypt_GPG_Signature +{ + // {{{ class properties + + /** + * A base64-encoded string containing a unique id for this signature if + * this signature has been verified as ok + * + * This id is used to prevent replay attacks and is not present for all + * types of signatures. + * + * @var string + */ + private $_id = ''; + + /** + * The fingerprint of the key used to create the signature + * + * @var string + */ + private $_keyFingerprint = ''; + + /** + * The id of the key used to create the signature + * + * @var string + */ + private $_keyId = ''; + + /** + * The creation date of this signature + * + * This is a Unix timestamp. + * + * @var integer + */ + private $_creationDate = 0; + + /** + * The expiration date of the signature + * + * This is a Unix timestamp. If this signature does not expire, this will + * be zero. + * + * @var integer + */ + private $_expirationDate = 0; + + /** + * The user id associated with this signature + * + * @var Crypt_GPG_UserId + */ + private $_userId = null; + + /** + * Whether or not this signature is valid + * + * @var boolean + */ + private $_isValid = false; + + // }}} + // {{{ __construct() + + /** + * Creates a new signature + * + * Signatures can be initialized from an array of named values. Available + * names are: + * + * - <kbd>string id</kbd> - the unique id of this signature. + * - <kbd>string fingerprint</kbd> - the fingerprint of the key used to + * create the signature. The fingerprint + * should not contain formatting + * characters. + * - <kbd>string keyId</kbd> - the id of the key used to create the + * the signature. + * - <kbd>integer creation</kbd> - the date the signature was created. + * This is a UNIX timestamp. + * - <kbd>integer expiration</kbd> - the date the signature expired. This + * is a UNIX timestamp. If the signature + * does not expire, use 0. + * - <kbd>boolean valid</kbd> - whether or not the signature is valid. + * - <kbd>string userId</kbd> - the user id associated with the + * signature. This may also be a + * {@link Crypt_GPG_UserId} object. + * + * @param Crypt_GPG_Signature|array $signature optional. Either an existing + * signature object, which is copied; or an array of initial values. + */ + public function __construct($signature = null) + { + // copy from object + if ($signature instanceof Crypt_GPG_Signature) { + $this->_id = $signature->_id; + $this->_keyFingerprint = $signature->_keyFingerprint; + $this->_keyId = $signature->_keyId; + $this->_creationDate = $signature->_creationDate; + $this->_expirationDate = $signature->_expirationDate; + $this->_isValid = $signature->_isValid; + + if ($signature->_userId instanceof Crypt_GPG_UserId) { + $this->_userId = clone $signature->_userId; + } else { + $this->_userId = $signature->_userId; + } + } + + // initialize from array + if (is_array($signature)) { + if (array_key_exists('id', $signature)) { + $this->setId($signature['id']); + } + + if (array_key_exists('fingerprint', $signature)) { + $this->setKeyFingerprint($signature['fingerprint']); + } + + if (array_key_exists('keyId', $signature)) { + $this->setKeyId($signature['keyId']); + } + + if (array_key_exists('creation', $signature)) { + $this->setCreationDate($signature['creation']); + } + + if (array_key_exists('expiration', $signature)) { + $this->setExpirationDate($signature['expiration']); + } + + if (array_key_exists('valid', $signature)) { + $this->setValid($signature['valid']); + } + + if (array_key_exists('userId', $signature)) { + $userId = new Crypt_GPG_UserId($signature['userId']); + $this->setUserId($userId); + } + } + } + + // }}} + // {{{ getId() + + /** + * Gets the id of this signature + * + * @return string a base64-encoded string containing a unique id for this + * signature. This id is used to prevent replay attacks and + * is not present for all types of signatures. + */ + public function getId() + { + return $this->_id; + } + + // }}} + // {{{ getKeyFingerprint() + + /** + * Gets the fingerprint of the key used to create this signature + * + * @return string the fingerprint of the key used to create this signature. + */ + public function getKeyFingerprint() + { + return $this->_keyFingerprint; + } + + // }}} + // {{{ getKeyId() + + /** + * Gets the id of the key used to create this signature + * + * Whereas the fingerprint of the signing key may not always be available + * (for example if the signature is bad), the id should always be + * available. + * + * @return string the id of the key used to create this signature. + */ + public function getKeyId() + { + return $this->_keyId; + } + + // }}} + // {{{ getCreationDate() + + /** + * Gets the creation date of this signature + * + * @return integer the creation date of this signature. This is a Unix + * timestamp. + */ + public function getCreationDate() + { + return $this->_creationDate; + } + + // }}} + // {{{ getExpirationDate() + + /** + * Gets the expiration date of the signature + * + * @return integer the expiration date of this signature. This is a Unix + * timestamp. If this signature does not expire, this will + * be zero. + */ + public function getExpirationDate() + { + return $this->_expirationDate; + } + + // }}} + // {{{ getUserId() + + /** + * Gets the user id associated with this signature + * + * @return Crypt_GPG_UserId the user id associated with this signature. + */ + public function getUserId() + { + return $this->_userId; + } + + // }}} + // {{{ isValid() + + /** + * Gets whether or no this signature is valid + * + * @return boolean true if this signature is valid and false if it is not. + */ + public function isValid() + { + return $this->_isValid; + } + + // }}} + // {{{ setId() + + /** + * Sets the id of this signature + * + * @param string $id a base64-encoded string containing a unique id for + * this signature. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + * + * @see Crypt_GPG_Signature::getId() + */ + public function setId($id) + { + $this->_id = strval($id); + return $this; + } + + // }}} + // {{{ setKeyFingerprint() + + /** + * Sets the key fingerprint of this signature + * + * @param string $fingerprint the key fingerprint of this signature. This + * is the fingerprint of the primary key used to + * create this signature. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setKeyFingerprint($fingerprint) + { + $this->_keyFingerprint = strval($fingerprint); + return $this; + } + + // }}} + // {{{ setKeyId() + + /** + * Sets the key id of this signature + * + * @param string $id the key id of this signature. This is the id of the + * primary key used to create this signature. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setKeyId($id) + { + $this->_keyId = strval($id); + return $this; + } + + // }}} + // {{{ setCreationDate() + + /** + * Sets the creation date of this signature + * + * @param integer $creationDate the creation date of this signature. This + * is a Unix timestamp. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setCreationDate($creationDate) + { + $this->_creationDate = intval($creationDate); + return $this; + } + + // }}} + // {{{ setExpirationDate() + + /** + * Sets the expiration date of this signature + * + * @param integer $expirationDate the expiration date of this signature. + * This is a Unix timestamp. Specify zero if + * this signature does not expire. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setExpirationDate($expirationDate) + { + $this->_expirationDate = intval($expirationDate); + return $this; + } + + // }}} + // {{{ setUserId() + + /** + * Sets the user id associated with this signature + * + * @param Crypt_GPG_UserId $userId the user id associated with this + * signature. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setUserId(Crypt_GPG_UserId $userId) + { + $this->_userId = $userId; + return $this; + } + + // }}} + // {{{ setValid() + + /** + * Sets whether or not this signature is valid + * + * @param boolean $isValid true if this signature is valid and false if it + * is not. + * + * @return Crypt_GPG_Signature the current object, for fluent interface. + */ + public function setValid($isValid) + { + $this->_isValid = ($isValid) ? true : false; + return $this; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/SubKey.php b/program/lib/Crypt/GPG/SubKey.php new file mode 100644 index 000000000..b6316e99f --- /dev/null +++ b/program/lib/Crypt/GPG/SubKey.php @@ -0,0 +1,649 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Contains a class representing GPG sub-keys and constants for GPG algorithms + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @author Nathan Fredrickson <nathan@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: SubKey.php 302768 2010-08-25 13:45:52Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + */ + +// {{{ class Crypt_GPG_SubKey + +/** + * A class for GPG sub-key information + * + * This class is used to store the results of the {@link Crypt_GPG::getKeys()} + * method. Sub-key objects are members of a {@link Crypt_GPG_Key} object. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @author Nathan Fredrickson <nathan@silverorange.com> + * @copyright 2005-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @see Crypt_GPG::getKeys() + * @see Crypt_GPG_Key::getSubKeys() + */ +class Crypt_GPG_SubKey +{ + // {{{ class constants + + /** + * RSA encryption algorithm. + */ + const ALGORITHM_RSA = 1; + + /** + * Elgamal encryption algorithm (encryption only). + */ + const ALGORITHM_ELGAMAL_ENC = 16; + + /** + * DSA encryption algorithm (sometimes called DH, sign only). + */ + const ALGORITHM_DSA = 17; + + /** + * Elgamal encryption algorithm (signage and encryption - should not be + * used). + */ + const ALGORITHM_ELGAMAL_ENC_SGN = 20; + + // }}} + // {{{ class properties + + /** + * The id of this sub-key + * + * @var string + */ + private $_id = ''; + + /** + * The algorithm used to create this sub-key + * + * The value is one of the Crypt_GPG_SubKey::ALGORITHM_* constants. + * + * @var integer + */ + private $_algorithm = 0; + + /** + * The fingerprint of this sub-key + * + * @var string + */ + private $_fingerprint = ''; + + /** + * Length of this sub-key in bits + * + * @var integer + */ + private $_length = 0; + + /** + * Date this sub-key was created + * + * This is a Unix timestamp. + * + * @var integer + */ + private $_creationDate = 0; + + /** + * Date this sub-key expires + * + * This is a Unix timestamp. If this sub-key does not expire, this will be + * zero. + * + * @var integer + */ + private $_expirationDate = 0; + + /** + * Whether or not this sub-key can sign data + * + * @var boolean + */ + private $_canSign = false; + + /** + * Whether or not this sub-key can encrypt data + * + * @var boolean + */ + private $_canEncrypt = false; + + /** + * Whether or not the private key for this sub-key exists in the keyring + * + * @var boolean + */ + private $_hasPrivate = false; + + /** + * Whether or not this sub-key is revoked + * + * @var boolean + */ + private $_isRevoked = false; + + // }}} + // {{{ __construct() + + /** + * Creates a new sub-key object + * + * Sub-keys can be initialized from an array of named values. Available + * names are: + * + * - <kbd>string id</kbd> - the key id of the sub-key. + * - <kbd>integer algorithm</kbd> - the encryption algorithm of the + * sub-key. + * - <kbd>string fingerprint</kbd> - the fingerprint of the sub-key. The + * fingerprint should not contain + * formatting characters. + * - <kbd>integer length</kbd> - the length of the sub-key in bits. + * - <kbd>integer creation</kbd> - the date the sub-key was created. + * This is a UNIX timestamp. + * - <kbd>integer expiration</kbd> - the date the sub-key expires. This + * is a UNIX timestamp. If the sub-key + * does not expire, use 0. + * - <kbd>boolean canSign</kbd> - whether or not the sub-key can be + * used to sign data. + * - <kbd>boolean canEncrypt</kbd> - whether or not the sub-key can be + * used to encrypt data. + * - <kbd>boolean hasPrivate</kbd> - whether or not the private key for + * the sub-key exists in the keyring. + * - <kbd>boolean isRevoked</kbd> - whether or not this sub-key is + * revoked. + * + * @param Crypt_GPG_SubKey|string|array $key optional. Either an existing + * sub-key object, which is copied; a sub-key string, which is + * parsed; or an array of initial values. + */ + public function __construct($key = null) + { + // parse from string + if (is_string($key)) { + $key = self::parse($key); + } + + // copy from object + if ($key instanceof Crypt_GPG_SubKey) { + $this->_id = $key->_id; + $this->_algorithm = $key->_algorithm; + $this->_fingerprint = $key->_fingerprint; + $this->_length = $key->_length; + $this->_creationDate = $key->_creationDate; + $this->_expirationDate = $key->_expirationDate; + $this->_canSign = $key->_canSign; + $this->_canEncrypt = $key->_canEncrypt; + $this->_hasPrivate = $key->_hasPrivate; + $this->_isRevoked = $key->_isRevoked; + } + + // initialize from array + if (is_array($key)) { + if (array_key_exists('id', $key)) { + $this->setId($key['id']); + } + + if (array_key_exists('algorithm', $key)) { + $this->setAlgorithm($key['algorithm']); + } + + if (array_key_exists('fingerprint', $key)) { + $this->setFingerprint($key['fingerprint']); + } + + if (array_key_exists('length', $key)) { + $this->setLength($key['length']); + } + + if (array_key_exists('creation', $key)) { + $this->setCreationDate($key['creation']); + } + + if (array_key_exists('expiration', $key)) { + $this->setExpirationDate($key['expiration']); + } + + if (array_key_exists('canSign', $key)) { + $this->setCanSign($key['canSign']); + } + + if (array_key_exists('canEncrypt', $key)) { + $this->setCanEncrypt($key['canEncrypt']); + } + + if (array_key_exists('hasPrivate', $key)) { + $this->setHasPrivate($key['hasPrivate']); + } + + if (array_key_exists('isRevoked', $key)) { + $this->setRevoked($key['isRevoked']); + } + } + } + + // }}} + // {{{ getId() + + /** + * Gets the id of this sub-key + * + * @return string the id of this sub-key. + */ + public function getId() + { + return $this->_id; + } + + // }}} + // {{{ getAlgorithm() + + /** + * Gets the algorithm used by this sub-key + * + * The algorithm should be one of the Crypt_GPG_SubKey::ALGORITHM_* + * constants. + * + * @return integer the algorithm used by this sub-key. + */ + public function getAlgorithm() + { + return $this->_algorithm; + } + + // }}} + // {{{ getCreationDate() + + /** + * Gets the creation date of this sub-key + * + * This is a Unix timestamp. + * + * @return integer the creation date of this sub-key. + */ + public function getCreationDate() + { + return $this->_creationDate; + } + + // }}} + // {{{ getExpirationDate() + + /** + * Gets the date this sub-key expires + * + * This is a Unix timestamp. If this sub-key does not expire, this will be + * zero. + * + * @return integer the date this sub-key expires. + */ + public function getExpirationDate() + { + return $this->_expirationDate; + } + + // }}} + // {{{ getFingerprint() + + /** + * Gets the fingerprint of this sub-key + * + * @return string the fingerprint of this sub-key. + */ + public function getFingerprint() + { + return $this->_fingerprint; + } + + // }}} + // {{{ getLength() + + /** + * Gets the length of this sub-key in bits + * + * @return integer the length of this sub-key in bits. + */ + public function getLength() + { + return $this->_length; + } + + // }}} + // {{{ canSign() + + /** + * Gets whether or not this sub-key can sign data + * + * @return boolean true if this sub-key can sign data and false if this + * sub-key can not sign data. + */ + public function canSign() + { + return $this->_canSign; + } + + // }}} + // {{{ canEncrypt() + + /** + * Gets whether or not this sub-key can encrypt data + * + * @return boolean true if this sub-key can encrypt data and false if this + * sub-key can not encrypt data. + */ + public function canEncrypt() + { + return $this->_canEncrypt; + } + + // }}} + // {{{ hasPrivate() + + /** + * Gets whether or not the private key for this sub-key exists in the + * keyring + * + * @return boolean true the private key for this sub-key exists in the + * keyring and false if it does not. + */ + public function hasPrivate() + { + return $this->_hasPrivate; + } + + // }}} + // {{{ isRevoked() + + /** + * Gets whether or not this sub-key is revoked + * + * @return boolean true if this sub-key is revoked and false if it is not. + */ + public function isRevoked() + { + return $this->_isRevoked; + } + + // }}} + // {{{ setCreationDate() + + /** + * Sets the creation date of this sub-key + * + * The creation date is a Unix timestamp. + * + * @param integer $creationDate the creation date of this sub-key. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setCreationDate($creationDate) + { + $this->_creationDate = intval($creationDate); + return $this; + } + + // }}} + // {{{ setExpirationDate() + + /** + * Sets the expiration date of this sub-key + * + * The expiration date is a Unix timestamp. Specify zero if this sub-key + * does not expire. + * + * @param integer $expirationDate the expiration date of this sub-key. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setExpirationDate($expirationDate) + { + $this->_expirationDate = intval($expirationDate); + return $this; + } + + // }}} + // {{{ setId() + + /** + * Sets the id of this sub-key + * + * @param string $id the id of this sub-key. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setId($id) + { + $this->_id = strval($id); + return $this; + } + + // }}} + // {{{ setAlgorithm() + + /** + * Sets the algorithm used by this sub-key + * + * @param integer $algorithm the algorithm used by this sub-key. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setAlgorithm($algorithm) + { + $this->_algorithm = intval($algorithm); + return $this; + } + + // }}} + // {{{ setFingerprint() + + /** + * Sets the fingerprint of this sub-key + * + * @param string $fingerprint the fingerprint of this sub-key. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setFingerprint($fingerprint) + { + $this->_fingerprint = strval($fingerprint); + return $this; + } + + // }}} + // {{{ setLength() + + /** + * Sets the length of this sub-key in bits + * + * @param integer $length the length of this sub-key in bits. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setLength($length) + { + $this->_length = intval($length); + return $this; + } + + // }}} + // {{{ setCanSign() + + /** + * Sets whether of not this sub-key can sign data + * + * @param boolean $canSign true if this sub-key can sign data and false if + * it can not. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setCanSign($canSign) + { + $this->_canSign = ($canSign) ? true : false; + return $this; + } + + // }}} + // {{{ setCanEncrypt() + + /** + * Sets whether of not this sub-key can encrypt data + * + * @param boolean $canEncrypt true if this sub-key can encrypt data and + * false if it can not. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setCanEncrypt($canEncrypt) + { + $this->_canEncrypt = ($canEncrypt) ? true : false; + return $this; + } + + // }}} + // {{{ setHasPrivate() + + /** + * Sets whether of not the private key for this sub-key exists in the + * keyring + * + * @param boolean $hasPrivate true if the private key for this sub-key + * exists in the keyring and false if it does + * not. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setHasPrivate($hasPrivate) + { + $this->_hasPrivate = ($hasPrivate) ? true : false; + return $this; + } + + // }}} + // {{{ setRevoked() + + /** + * Sets whether or not this sub-key is revoked + * + * @param boolean $isRevoked whether or not this sub-key is revoked. + * + * @return Crypt_GPG_SubKey the current object, for fluent interface. + */ + public function setRevoked($isRevoked) + { + $this->_isRevoked = ($isRevoked) ? true : false; + return $this; + } + + // }}} + // {{{ parse() + + /** + * Parses a sub-key object from a sub-key string + * + * See <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG distribution} for information + * on how the sub-key string is parsed. + * + * @param string $string the string containing the sub-key. + * + * @return Crypt_GPG_SubKey the sub-key object parsed from the string. + */ + public static function parse($string) + { + $tokens = explode(':', $string); + + $subKey = new Crypt_GPG_SubKey(); + + $subKey->setId($tokens[4]); + $subKey->setLength($tokens[2]); + $subKey->setAlgorithm($tokens[3]); + $subKey->setCreationDate(self::_parseDate($tokens[5])); + $subKey->setExpirationDate(self::_parseDate($tokens[6])); + + if ($tokens[1] == 'r') { + $subKey->setRevoked(true); + } + + if (strpos($tokens[11], 's') !== false) { + $subKey->setCanSign(true); + } + + if (strpos($tokens[11], 'e') !== false) { + $subKey->setCanEncrypt(true); + } + + return $subKey; + } + + // }}} + // {{{ _parseDate() + + /** + * Parses a date string as provided by GPG into a UNIX timestamp + * + * @param string $string the date string. + * + * @return integer the UNIX timestamp corresponding to the provided date + * string. + */ + private static function _parseDate($string) + { + if ($string == '') { + $timestamp = 0; + } else { + // all times are in UTC according to GPG documentation + $timeZone = new DateTimeZone('UTC'); + + if (strpos($string, 'T') === false) { + // interpret as UNIX timestamp + $string = '@' . $string; + } + + $date = new DateTime($string, $timeZone); + + // convert to UNIX timestamp + $timestamp = intval($date->format('U')); + } + + return $timestamp; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/UserId.php b/program/lib/Crypt/GPG/UserId.php new file mode 100644 index 000000000..04435708c --- /dev/null +++ b/program/lib/Crypt/GPG/UserId.php @@ -0,0 +1,373 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Contains a data class representing a GPG user id + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: UserId.php 295621 2010-03-01 04:18:54Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + */ + +// {{{ class Crypt_GPG_UserId + +/** + * A class for GPG user id information + * + * This class is used to store the results of the {@link Crypt_GPG::getKeys()} + * method. User id objects are members of a {@link Crypt_GPG_Key} object. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008-2010 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @see Crypt_GPG::getKeys() + * @see Crypt_GPG_Key::getUserIds() + */ +class Crypt_GPG_UserId +{ + // {{{ class properties + + /** + * The name field of this user id + * + * @var string + */ + private $_name = ''; + + /** + * The comment field of this user id + * + * @var string + */ + private $_comment = ''; + + /** + * The email field of this user id + * + * @var string + */ + private $_email = ''; + + /** + * Whether or not this user id is revoked + * + * @var boolean + */ + private $_isRevoked = false; + + /** + * Whether or not this user id is valid + * + * @var boolean + */ + private $_isValid = true; + + // }}} + // {{{ __construct() + + /** + * Creates a new user id + * + * User ids can be initialized from an array of named values. Available + * names are: + * + * - <kbd>string name</kbd> - the name field of the user id. + * - <kbd>string comment</kbd> - the comment field of the user id. + * - <kbd>string email</kbd> - the email field of the user id. + * - <kbd>boolean valid</kbd> - whether or not the user id is valid. + * - <kbd>boolean revoked</kbd> - whether or not the user id is revoked. + * + * @param Crypt_GPG_UserId|string|array $userId optional. Either an + * existing user id object, which is copied; a user id string, which + * is parsed; or an array of initial values. + */ + public function __construct($userId = null) + { + // parse from string + if (is_string($userId)) { + $userId = self::parse($userId); + } + + // copy from object + if ($userId instanceof Crypt_GPG_UserId) { + $this->_name = $userId->_name; + $this->_comment = $userId->_comment; + $this->_email = $userId->_email; + $this->_isRevoked = $userId->_isRevoked; + $this->_isValid = $userId->_isValid; + } + + // initialize from array + if (is_array($userId)) { + if (array_key_exists('name', $userId)) { + $this->setName($userId['name']); + } + + if (array_key_exists('comment', $userId)) { + $this->setComment($userId['comment']); + } + + if (array_key_exists('email', $userId)) { + $this->setEmail($userId['email']); + } + + if (array_key_exists('revoked', $userId)) { + $this->setRevoked($userId['revoked']); + } + + if (array_key_exists('valid', $userId)) { + $this->setValid($userId['valid']); + } + } + } + + // }}} + // {{{ getName() + + /** + * Gets the name field of this user id + * + * @return string the name field of this user id. + */ + public function getName() + { + return $this->_name; + } + + // }}} + // {{{ getComment() + + /** + * Gets the comments field of this user id + * + * @return string the comments field of this user id. + */ + public function getComment() + { + return $this->_comment; + } + + // }}} + // {{{ getEmail() + + /** + * Gets the email field of this user id + * + * @return string the email field of this user id. + */ + public function getEmail() + { + return $this->_email; + } + + // }}} + // {{{ isRevoked() + + /** + * Gets whether or not this user id is revoked + * + * @return boolean true if this user id is revoked and false if it is not. + */ + public function isRevoked() + { + return $this->_isRevoked; + } + + // }}} + // {{{ isValid() + + /** + * Gets whether or not this user id is valid + * + * @return boolean true if this user id is valid and false if it is not. + */ + public function isValid() + { + return $this->_isValid; + } + + // }}} + // {{{ __toString() + + /** + * Gets a string representation of this user id + * + * The string is formatted as: + * <b><kbd>name (comment) <email-address></kbd></b>. + * + * @return string a string representation of this user id. + */ + public function __toString() + { + $components = array(); + + if (strlen($this->_name) > 0) { + $components[] = $this->_name; + } + + if (strlen($this->_comment) > 0) { + $components[] = '(' . $this->_comment . ')'; + } + + if (strlen($this->_email) > 0) { + $components[] = '<' . $this->_email. '>'; + } + + return implode(' ', $components); + } + + // }}} + // {{{ setName() + + /** + * Sets the name field of this user id + * + * @param string $name the name field of this user id. + * + * @return Crypt_GPG_UserId the current object, for fluent interface. + */ + public function setName($name) + { + $this->_name = strval($name); + return $this; + } + + // }}} + // {{{ setComment() + + /** + * Sets the comment field of this user id + * + * @param string $comment the comment field of this user id. + * + * @return Crypt_GPG_UserId the current object, for fluent interface. + */ + public function setComment($comment) + { + $this->_comment = strval($comment); + return $this; + } + + // }}} + // {{{ setEmail() + + /** + * Sets the email field of this user id + * + * @param string $email the email field of this user id. + * + * @return Crypt_GPG_UserId the current object, for fluent interface. + */ + public function setEmail($email) + { + $this->_email = strval($email); + return $this; + } + + // }}} + // {{{ setRevoked() + + /** + * Sets whether or not this user id is revoked + * + * @param boolean $isRevoked whether or not this user id is revoked. + * + * @return Crypt_GPG_UserId the current object, for fluent interface. + */ + public function setRevoked($isRevoked) + { + $this->_isRevoked = ($isRevoked) ? true : false; + return $this; + } + + // }}} + // {{{ setValid() + + /** + * Sets whether or not this user id is valid + * + * @param boolean $isValid whether or not this user id is valid. + * + * @return Crypt_GPG_UserId the current object, for fluent interface. + */ + public function setValid($isValid) + { + $this->_isValid = ($isValid) ? true : false; + return $this; + } + + // }}} + // {{{ parse() + + /** + * Parses a user id object from a user id string + * + * A user id string is of the form: + * <b><kbd>name (comment) <email-address></kbd></b> with the <i>comment</i> + * and <i>email-address</i> fields being optional. + * + * @param string $string the user id string to parse. + * + * @return Crypt_GPG_UserId the user id object parsed from the string. + */ + public static function parse($string) + { + $userId = new Crypt_GPG_UserId(); + $email = ''; + $comment = ''; + + // get email address from end of string if it exists + $matches = array(); + if (preg_match('/^(.+?) <([^>]+)>$/', $string, $matches) === 1) { + $string = $matches[1]; + $email = $matches[2]; + } + + // get comment from end of string if it exists + $matches = array(); + if (preg_match('/^(.+?) \(([^\)]+)\)$/', $string, $matches) === 1) { + $string = $matches[1]; + $comment = $matches[2]; + } + + $name = $string; + + $userId->setName($name); + $userId->setComment($comment); + $userId->setEmail($email); + + return $userId; + } + + // }}} +} + +// }}} + +?> diff --git a/program/lib/Crypt/GPG/VerifyStatusHandler.php b/program/lib/Crypt/GPG/VerifyStatusHandler.php new file mode 100644 index 000000000..083bd3012 --- /dev/null +++ b/program/lib/Crypt/GPG/VerifyStatusHandler.php @@ -0,0 +1,216 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Crypt_GPG is a package to use GPG from PHP + * + * This file contains an object that handles GPG's status output for the verify + * operation. + * + * PHP version 5 + * + * LICENSE: + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: VerifyStatusHandler.php 302908 2010-08-31 03:56:54Z gauthierm $ + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ + +/** + * Signature object class definition + */ +require_once 'Crypt/GPG/Signature.php'; + +/** + * Status line handler for the verify operation + * + * This class is used internally by Crypt_GPG and does not need be used + * directly. See the {@link Crypt_GPG} class for end-user API. + * + * This class is responsible for building signature objects that are returned + * by the {@link Crypt_GPG::verify()} method. See <b>doc/DETAILS</b> in the + * {@link http://www.gnupg.org/download/ GPG distribution} for detailed + * information on GPG's status output for the verify operation. + * + * @category Encryption + * @package Crypt_GPG + * @author Michael Gauthier <mike@silverorange.com> + * @copyright 2008 silverorange + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @link http://pear.php.net/package/Crypt_GPG + * @link http://www.gnupg.org/ + */ +class Crypt_GPG_VerifyStatusHandler +{ + // {{{ protected properties + + /** + * The current signature id + * + * Ths signature id is emitted by GPG before the new signature line so we + * must remember it temporarily. + * + * @var string + */ + protected $signatureId = ''; + + /** + * List of parsed {@link Crypt_GPG_Signature} objects + * + * @var array + */ + protected $signatures = array(); + + /** + * Array index of the current signature + * + * @var integer + */ + protected $index = -1; + + // }}} + // {{{ handle() + + /** + * Handles a status line + * + * @param string $line the status line to handle. + * + * @return void + */ + public function handle($line) + { + $tokens = explode(' ', $line); + switch ($tokens[0]) { + case 'GOODSIG': + case 'EXPSIG': + case 'EXPKEYSIG': + case 'REVKEYSIG': + case 'BADSIG': + $signature = new Crypt_GPG_Signature(); + + // if there was a signature id, set it on the new signature + if ($this->signatureId != '') { + $signature->setId($this->signatureId); + $this->signatureId = ''; + } + + // Detect whether fingerprint or key id was returned and set + // signature values appropriately. Key ids are strings of either + // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 + // hexadecimal characters. The key id is the last 16 characters of + // the key fingerprint. + if (strlen($tokens[1]) > 16) { + $signature->setKeyFingerprint($tokens[1]); + $signature->setKeyId(substr($tokens[1], -16)); + } else { + $signature->setKeyId($tokens[1]); + } + + // get user id string + $string = implode(' ', array_splice($tokens, 2)); + $string = rawurldecode($string); + + $signature->setUserId(Crypt_GPG_UserId::parse($string)); + + $this->index++; + $this->signatures[$this->index] = $signature; + break; + + case 'ERRSIG': + $signature = new Crypt_GPG_Signature(); + + // if there was a signature id, set it on the new signature + if ($this->signatureId != '') { + $signature->setId($this->signatureId); + $this->signatureId = ''; + } + + // Detect whether fingerprint or key id was returned and set + // signature values appropriately. Key ids are strings of either + // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 + // hexadecimal characters. The key id is the last 16 characters of + // the key fingerprint. + if (strlen($tokens[1]) > 16) { + $signature->setKeyFingerprint($tokens[1]); + $signature->setKeyId(substr($tokens[1], -16)); + } else { + $signature->setKeyId($tokens[1]); + } + + $this->index++; + $this->signatures[$this->index] = $signature; + + break; + + case 'VALIDSIG': + if (!array_key_exists($this->index, $this->signatures)) { + break; + } + + $signature = $this->signatures[$this->index]; + + $signature->setValid(true); + $signature->setKeyFingerprint($tokens[1]); + + if (strpos($tokens[3], 'T') === false) { + $signature->setCreationDate($tokens[3]); + } else { + $signature->setCreationDate(strtotime($tokens[3])); + } + + if (array_key_exists(4, $tokens)) { + if (strpos($tokens[4], 'T') === false) { + $signature->setExpirationDate($tokens[4]); + } else { + $signature->setExpirationDate(strtotime($tokens[4])); + } + } + + break; + + case 'SIG_ID': + // note: signature id comes before new signature line and may not + // exist for some signature types + $this->signatureId = $tokens[1]; + break; + } + } + + // }}} + // {{{ getSignatures() + + /** + * Gets the {@link Crypt_GPG_Signature} objects parsed by this handler + * + * @return array the signature objects parsed by this handler. + */ + public function getSignatures() + { + return $this->signatures; + } + + // }}} +} + +?> diff --git a/program/lib/Net/Sieve.php b/program/lib/Net/Sieve.php new file mode 100644 index 000000000..8ebdf0958 --- /dev/null +++ b/program/lib/Net/Sieve.php @@ -0,0 +1,1274 @@ +<?php +/** + * This file contains the Net_Sieve class. + * + * PHP version 4 + * + * +-----------------------------------------------------------------------+ + * | All rights reserved. | + * | | + * | Redistribution and use in source and binary forms, with or without | + * | modification, are permitted provided that the following conditions | + * | are met: | + * | | + * | o Redistributions of source code must retain the above copyright | + * | notice, this list of conditions and the following disclaimer. | + * | o Redistributions in binary form must reproduce the above copyright | + * | notice, this list of conditions and the following disclaimer in the | + * | documentation and/or other materials provided with the distribution.| + * | | + * | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | + * | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | + * | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | + * | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | + * | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | + * | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | + * | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | + * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | + * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | + * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | + * | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | + * +-----------------------------------------------------------------------+ + * + * @category Networking + * @package Net_Sieve + * @author Richard Heyes <richard@phpguru.org> + * @author Damian Fernandez Sosa <damlists@cnba.uba.ar> + * @author Anish Mistry <amistry@am-productions.biz> + * @author Jan Schneider <jan@horde.org> + * @copyright 2002-2003 Richard Heyes + * @copyright 2006-2008 Anish Mistry + * @license http://www.opensource.org/licenses/bsd-license.php BSD + * @version SVN: $Id$ + * @link http://pear.php.net/package/Net_Sieve + */ + +require_once 'PEAR.php'; +require_once 'Net/Socket.php'; + +/** + * TODO + * + * o supportsAuthMech() + */ + +/** + * Disconnected state + * @const NET_SIEVE_STATE_DISCONNECTED + */ +define('NET_SIEVE_STATE_DISCONNECTED', 1, true); + +/** + * Authorisation state + * @const NET_SIEVE_STATE_AUTHORISATION + */ +define('NET_SIEVE_STATE_AUTHORISATION', 2, true); + +/** + * Transaction state + * @const NET_SIEVE_STATE_TRANSACTION + */ +define('NET_SIEVE_STATE_TRANSACTION', 3, true); + + +/** + * A class for talking to the timsieved server which comes with Cyrus IMAP. + * + * @category Networking + * @package Net_Sieve + * @author Richard Heyes <richard@phpguru.org> + * @author Damian Fernandez Sosa <damlists@cnba.uba.ar> + * @author Anish Mistry <amistry@am-productions.biz> + * @author Jan Schneider <jan@horde.org> + * @copyright 2002-2003 Richard Heyes + * @copyright 2006-2008 Anish Mistry + * @license http://www.opensource.org/licenses/bsd-license.php BSD + * @version Release: 1.3.2 + * @link http://pear.php.net/package/Net_Sieve + * @link http://tools.ietf.org/html/rfc5228 RFC 5228 (Sieve: An Email + * Filtering Language) + * @link http://tools.ietf.org/html/rfc5804 RFC 5804 A Protocol for + * Remotely Managing Sieve Scripts + */ +class Net_Sieve +{ + /** + * The authentication methods this class supports. + * + * Can be overwritten if having problems with certain methods. + * + * @var array + */ + var $supportedAuthMethods = array('DIGEST-MD5', 'CRAM-MD5', 'EXTERNAL', + 'PLAIN' , 'LOGIN'); + + /** + * SASL authentication methods that require Auth_SASL. + * + * @var array + */ + var $supportedSASLAuthMethods = array('DIGEST-MD5', 'CRAM-MD5'); + + /** + * The socket handle. + * + * @var resource + */ + var $_sock; + + /** + * Parameters and connection information. + * + * @var array + */ + var $_data; + + /** + * Current state of the connection. + * + * One of the NET_SIEVE_STATE_* constants. + * + * @var integer + */ + var $_state; + + /** + * Constructor error. + * + * @var PEAR_Error + */ + var $_error; + + /** + * Whether to enable debugging. + * + * @var boolean + */ + var $_debug = false; + + /** + * Debug output handler. + * + * This has to be a valid callback. + * + * @var string|array + */ + var $_debug_handler = null; + + /** + * Whether to pick up an already established connection. + * + * @var boolean + */ + var $_bypassAuth = false; + + /** + * Whether to use TLS if available. + * + * @var boolean + */ + var $_useTLS = true; + + /** + * Additional options for stream_context_create(). + * + * @var array + */ + var $_options = null; + + /** + * Maximum number of referral loops + * + * @var array + */ + var $_maxReferralCount = 15; + + /** + * Constructor. + * + * Sets up the object, connects to the server and logs in. Stores any + * generated error in $this->_error, which can be retrieved using the + * getError() method. + * + * @param string $user Login username. + * @param string $pass Login password. + * @param string $host Hostname of server. + * @param string $port Port of server. + * @param string $logintype Type of login to perform (see + * $supportedAuthMethods). + * @param string $euser Effective user. If authenticating as an + * administrator, login as this user. + * @param boolean $debug Whether to enable debugging (@see setDebug()). + * @param string $bypassAuth Skip the authentication phase. Useful if the + * socket is already open. + * @param boolean $useTLS Use TLS if available. + * @param array $options Additional options for + * stream_context_create(). + * @param mixed $handler A callback handler for the debug output. + */ + function Net_Sieve($user = null, $pass = null, $host = 'localhost', + $port = 2000, $logintype = '', $euser = '', + $debug = false, $bypassAuth = false, $useTLS = true, + $options = null, $handler = null) + { + $this->_state = NET_SIEVE_STATE_DISCONNECTED; + $this->_data['user'] = $user; + $this->_data['pass'] = $pass; + $this->_data['host'] = $host; + $this->_data['port'] = $port; + $this->_data['logintype'] = $logintype; + $this->_data['euser'] = $euser; + $this->_sock = new Net_Socket(); + $this->_bypassAuth = $bypassAuth; + $this->_useTLS = $useTLS; + $this->_options = $options; + $this->setDebug($debug, $handler); + + /* Try to include the Auth_SASL package. If the package is not + * available, we disable the authentication methods that depend upon + * it. */ + if ((@include_once 'Auth/SASL.php') === false) { + $this->_debug('Auth_SASL not present'); + foreach ($this->supportedSASLAuthMethods as $SASLMethod) { + $pos = array_search($SASLMethod, $this->supportedAuthMethods); + $this->_debug('Disabling method ' . $SASLMethod); + unset($this->supportedAuthMethods[$pos]); + } + } + + if (strlen($user) && strlen($pass)) { + $this->_error = $this->_handleConnectAndLogin(); + } + } + + /** + * Returns any error that may have been generated in the constructor. + * + * @return boolean|PEAR_Error False if no error, PEAR_Error otherwise. + */ + function getError() + { + return PEAR::isError($this->_error) ? $this->_error : false; + } + + /** + * Sets the debug state and handler function. + * + * @param boolean $debug Whether to enable debugging. + * @param string $handler A custom debug handler. Must be a valid callback. + * + * @return void + */ + function setDebug($debug = true, $handler = null) + { + $this->_debug = $debug; + $this->_debug_handler = $handler; + } + + /** + * Connects to the server and logs in. + * + * @return boolean True on success, PEAR_Error on failure. + */ + function _handleConnectAndLogin() + { + if (PEAR::isError($res = $this->connect($this->_data['host'], $this->_data['port'], $this->_options, $this->_useTLS))) { + return $res; + } + if ($this->_bypassAuth === false) { + if (PEAR::isError($res = $this->login($this->_data['user'], $this->_data['pass'], $this->_data['logintype'], $this->_data['euser'], $this->_bypassAuth))) { + return $res; + } + } + return true; + } + + /** + * Handles connecting to the server and checks the response validity. + * + * @param string $host Hostname of server. + * @param string $port Port of server. + * @param array $options List of options to pass to + * stream_context_create(). + * @param boolean $useTLS Use TLS if available. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function connect($host, $port, $options = null, $useTLS = true) + { + $this->_data['host'] = $host; + $this->_data['port'] = $port; + $this->_useTLS = $useTLS; + if (is_array($options)) { + $this->_options = array_merge($this->_options, $options); + } + + if (NET_SIEVE_STATE_DISCONNECTED != $this->_state) { + return PEAR::raiseError('Not currently in DISCONNECTED state', 1); + } + + if (PEAR::isError($res = $this->_sock->connect($host, $port, false, 5, $options))) { + return $res; + } + + if ($this->_bypassAuth) { + $this->_state = NET_SIEVE_STATE_TRANSACTION; + } else { + $this->_state = NET_SIEVE_STATE_AUTHORISATION; + if (PEAR::isError($res = $this->_doCmd())) { + return $res; + } + } + + // Explicitly ask for the capabilities in case the connection is + // picked up from an existing connection. + if (PEAR::isError($res = $this->_cmdCapability())) { + return PEAR::raiseError( + 'Failed to connect, server said: ' . $res->getMessage(), 2 + ); + } + + // Check if we can enable TLS via STARTTLS. + if ($useTLS && !empty($this->_capability['starttls']) + && function_exists('stream_socket_enable_crypto') + ) { + if (PEAR::isError($res = $this->_startTLS())) { + return $res; + } + } + + return true; + } + + /** + * Disconnect from the Sieve server. + * + * @param boolean $sendLogoutCMD Whether to send LOGOUT command before + * disconnecting. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function disconnect($sendLogoutCMD = true) + { + return $this->_cmdLogout($sendLogoutCMD); + } + + /** + * Logs into server. + * + * @param string $user Login username. + * @param string $pass Login password. + * @param string $logintype Type of login method to use. + * @param string $euser Effective UID (perform on behalf of $euser). + * @param boolean $bypassAuth Do not perform authentication. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function login($user, $pass, $logintype = null, $euser = '', $bypassAuth = false) + { + $this->_data['user'] = $user; + $this->_data['pass'] = $pass; + $this->_data['logintype'] = $logintype; + $this->_data['euser'] = $euser; + $this->_bypassAuth = $bypassAuth; + + if (NET_SIEVE_STATE_AUTHORISATION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + if (!$bypassAuth ) { + if (PEAR::isError($res = $this->_cmdAuthenticate($user, $pass, $logintype, $euser))) { + return $res; + } + } + $this->_state = NET_SIEVE_STATE_TRANSACTION; + + return true; + } + + /** + * Returns an indexed array of scripts currently on the server. + * + * @return array Indexed array of scriptnames. + */ + function listScripts() + { + if (is_array($scripts = $this->_cmdListScripts())) { + $this->_active = $scripts[1]; + return $scripts[0]; + } else { + return $scripts; + } + } + + /** + * Returns the active script. + * + * @return string The active scriptname. + */ + function getActive() + { + if (!empty($this->_active)) { + return $this->_active; + } + if (is_array($scripts = $this->_cmdListScripts())) { + $this->_active = $scripts[1]; + return $scripts[1]; + } + } + + /** + * Sets the active script. + * + * @param string $scriptname The name of the script to be set as active. + * + * @return boolean True on success, PEAR_Error on failure. + */ + function setActive($scriptname) + { + return $this->_cmdSetActive($scriptname); + } + + /** + * Retrieves a script. + * + * @param string $scriptname The name of the script to be retrieved. + * + * @return string The script on success, PEAR_Error on failure. + */ + function getScript($scriptname) + { + return $this->_cmdGetScript($scriptname); + } + + /** + * Adds a script to the server. + * + * @param string $scriptname Name of the script. + * @param string $script The script content. + * @param boolean $makeactive Whether to make this the active script. + * + * @return boolean True on success, PEAR_Error on failure. + */ + function installScript($scriptname, $script, $makeactive = false) + { + if (PEAR::isError($res = $this->_cmdPutScript($scriptname, $script))) { + return $res; + } + if ($makeactive) { + return $this->_cmdSetActive($scriptname); + } + return true; + } + + /** + * Removes a script from the server. + * + * @param string $scriptname Name of the script. + * + * @return boolean True on success, PEAR_Error on failure. + */ + function removeScript($scriptname) + { + return $this->_cmdDeleteScript($scriptname); + } + + /** + * Checks if the server has space to store the script by the server. + * + * @param string $scriptname The name of the script to mark as active. + * @param integer $size The size of the script. + * + * @return boolean|PEAR_Error True if there is space, PEAR_Error otherwise. + * + * @todo Rename to hasSpace() + */ + function haveSpace($scriptname, $size) + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in TRANSACTION state', 1); + } + + if (PEAR::isError($res = $this->_doCmd(sprintf('HAVESPACE %s %d', $this->_escape($scriptname), $size)))) { + return $res; + } + return true; + } + + /** + * Returns the list of extensions the server supports. + * + * @return array List of extensions or PEAR_Error on failure. + */ + function getExtensions() + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 7); + } + return $this->_capability['extensions']; + } + + /** + * Returns whether the server supports an extension. + * + * @param string $extension The extension to check. + * + * @return boolean Whether the extension is supported or PEAR_Error on + * failure. + */ + function hasExtension($extension) + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 7); + } + + $extension = trim($this->_toUpper($extension)); + if (is_array($this->_capability['extensions'])) { + foreach ($this->_capability['extensions'] as $ext) { + if ($ext == $extension) { + return true; + } + } + } + + return false; + } + + /** + * Returns the list of authentication methods the server supports. + * + * @return array List of authentication methods or PEAR_Error on failure. + */ + function getAuthMechs() + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 7); + } + return $this->_capability['sasl']; + } + + /** + * Returns whether the server supports an authentication method. + * + * @param string $method The method to check. + * + * @return boolean Whether the method is supported or PEAR_Error on + * failure. + */ + function hasAuthMech($method) + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 7); + } + + $method = trim($this->_toUpper($method)); + if (is_array($this->_capability['sasl'])) { + foreach ($this->_capability['sasl'] as $sasl) { + if ($sasl == $method) { + return true; + } + } + } + + return false; + } + + /** + * Handles the authentication using any known method. + * + * @param string $uid The userid to authenticate as. + * @param string $pwd The password to authenticate with. + * @param string $userMethod The method to use. If empty, the class chooses + * the best (strongest) available method. + * @param string $euser The effective uid to authenticate as. + * + * @return void + */ + function _cmdAuthenticate($uid, $pwd, $userMethod = null, $euser = '') + { + if (PEAR::isError($method = $this->_getBestAuthMethod($userMethod))) { + return $method; + } + switch ($method) { + case 'DIGEST-MD5': + return $this->_authDigestMD5($uid, $pwd, $euser); + case 'CRAM-MD5': + $result = $this->_authCRAMMD5($uid, $pwd, $euser); + break; + case 'LOGIN': + $result = $this->_authLOGIN($uid, $pwd, $euser); + break; + case 'PLAIN': + $result = $this->_authPLAIN($uid, $pwd, $euser); + break; + case 'EXTERNAL': + $result = $this->_authEXTERNAL($uid, $pwd, $euser); + break; + default : + $result = PEAR::raiseError( + $method . ' is not a supported authentication method' + ); + break; + } + + if (PEAR::isError($res = $this->_doCmd())) { + return $res; + } + + // Query the server capabilities again now that we are authenticated. + if (PEAR::isError($res = $this->_cmdCapability())) { + return PEAR::raiseError( + 'Failed to connect, server said: ' . $res->getMessage(), 2 + ); + } + + return $result; + } + + /** + * Authenticates the user using the PLAIN method. + * + * @param string $user The userid to authenticate as. + * @param string $pass The password to authenticate with. + * @param string $euser The effective uid to authenticate as. + * + * @return void + */ + function _authPLAIN($user, $pass, $euser) + { + return $this->_sendCmd( + sprintf( + 'AUTHENTICATE "PLAIN" "%s"', + base64_encode($euser . chr(0) . $user . chr(0) . $pass) + ) + ); + } + + /** + * Authenticates the user using the LOGIN method. + * + * @param string $user The userid to authenticate as. + * @param string $pass The password to authenticate with. + * @param string $euser The effective uid to authenticate as. + * + * @return void + */ + function _authLOGIN($user, $pass, $euser) + { + if (PEAR::isError($result = $this->_sendCmd('AUTHENTICATE "LOGIN"'))) { + return $result; + } + if (PEAR::isError($result = $this->_doCmd('"' . base64_encode($user) . '"', true))) { + return $result; + } + return $this->_doCmd('"' . base64_encode($pass) . '"', true); + } + + /** + * Authenticates the user using the CRAM-MD5 method. + * + * @param string $user The userid to authenticate as. + * @param string $pass The password to authenticate with. + * @param string $euser The effective uid to authenticate as. + * + * @return void + */ + function _authCRAMMD5($user, $pass, $euser) + { + if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "CRAM-MD5"', true))) { + return $challenge; + } + + $challenge = base64_decode(trim($challenge)); + $cram = Auth_SASL::factory('crammd5'); + if (PEAR::isError($response = $cram->getResponse($user, $pass, $challenge))) { + return $response; + } + + return $this->_sendStringResponse(base64_encode($response)); + } + + /** + * Authenticates the user using the DIGEST-MD5 method. + * + * @param string $user The userid to authenticate as. + * @param string $pass The password to authenticate with. + * @param string $euser The effective uid to authenticate as. + * + * @return void + */ + function _authDigestMD5($user, $pass, $euser) + { + if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "DIGEST-MD5"', true))) { + return $challenge; + } + + $challenge = base64_decode(trim($challenge)); + $digest = Auth_SASL::factory('digestmd5'); + // @todo Really 'localhost'? + if (PEAR::isError($response = $digest->getResponse($user, $pass, $challenge, 'localhost', 'sieve', $euser))) { + return $response; + } + + if (PEAR::isError($result = $this->_sendStringResponse(base64_encode($response)))) { + return $result; + } + if (PEAR::isError($result = $this->_doCmd('', true))) { + return $result; + } + if ($this->_toUpper(substr($result, 0, 2)) == 'OK') { + return; + } + + /* We don't use the protocol's third step because SIEVE doesn't allow + * subsequent authentication, so we just silently ignore it. */ + if (PEAR::isError($result = $this->_sendStringResponse(''))) { + return $result; + } + + return $this->_doCmd(); + } + + /** + * Authenticates the user using the EXTERNAL method. + * + * @param string $user The userid to authenticate as. + * @param string $pass The password to authenticate with. + * @param string $euser The effective uid to authenticate as. + * + * @return void + * + * @since 1.1.7 + */ + function _authEXTERNAL($user, $pass, $euser) + { + $cmd = sprintf( + 'AUTHENTICATE "EXTERNAL" "%s"', + base64_encode(strlen($euser) ? $euser : $user) + ); + return $this->_sendCmd($cmd); + } + + /** + * Removes a script from the server. + * + * @param string $scriptname Name of the script to delete. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function _cmdDeleteScript($scriptname) + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + if (PEAR::isError($res = $this->_doCmd(sprintf('DELETESCRIPT %s', $this->_escape($scriptname))))) { + return $res; + } + return true; + } + + /** + * Retrieves the contents of the named script. + * + * @param string $scriptname Name of the script to retrieve. + * + * @return string The script if successful, PEAR_Error otherwise. + */ + function _cmdGetScript($scriptname) + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + if (PEAR::isError($res = $this->_doCmd(sprintf('GETSCRIPT %s', $this->_escape($scriptname))))) { + return $res; + } + + return preg_replace('/^{[0-9]+}\r\n/', '', $res); + } + + /** + * Sets the active script, i.e. the one that gets run on new mail by the + * server. + * + * @param string $scriptname The name of the script to mark as active. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function _cmdSetActive($scriptname) + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + if (PEAR::isError($res = $this->_doCmd(sprintf('SETACTIVE %s', $this->_escape($scriptname))))) { + return $res; + } + + $this->_activeScript = $scriptname; + return true; + } + + /** + * Returns the list of scripts on the server. + * + * @return array An array with the list of scripts in the first element + * and the active script in the second element on success, + * PEAR_Error otherwise. + */ + function _cmdListScripts() + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + if (PEAR::isError($res = $this->_doCmd('LISTSCRIPTS'))) { + return $res; + } + + $scripts = array(); + $activescript = null; + $res = explode("\r\n", $res); + foreach ($res as $value) { + if (preg_match('/^"(.*)"( ACTIVE)?$/i', $value, $matches)) { + $script_name = stripslashes($matches[1]); + $scripts[] = $script_name; + if (!empty($matches[2])) { + $activescript = $script_name; + } + } + } + + return array($scripts, $activescript); + } + + /** + * Adds a script to the server. + * + * @param string $scriptname Name of the new script. + * @param string $scriptdata The new script. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function _cmdPutScript($scriptname, $scriptdata) + { + if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { + return PEAR::raiseError('Not currently in AUTHORISATION state', 1); + } + + $stringLength = $this->_getLineLength($scriptdata); + $command = sprintf("PUTSCRIPT %s {%d+}\r\n%s", + $this->_escape($scriptname), + $stringLength, + $scriptdata); + if (PEAR::isError($res = $this->_doCmd($command))) { + return $res; + } + + return true; + } + + /** + * Logs out of the server and terminates the connection. + * + * @param boolean $sendLogoutCMD Whether to send LOGOUT command before + * disconnecting. + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function _cmdLogout($sendLogoutCMD = true) + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 1); + } + + if ($sendLogoutCMD) { + if (PEAR::isError($res = $this->_doCmd('LOGOUT'))) { + return $res; + } + } + + $this->_sock->disconnect(); + $this->_state = NET_SIEVE_STATE_DISCONNECTED; + + return true; + } + + /** + * Sends the CAPABILITY command + * + * @return boolean True on success, PEAR_Error otherwise. + */ + function _cmdCapability() + { + if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { + return PEAR::raiseError('Not currently connected', 1); + } + if (PEAR::isError($res = $this->_doCmd('CAPABILITY'))) { + return $res; + } + $this->_parseCapability($res); + return true; + } + + /** + * Parses the response from the CAPABILITY command and stores the result + * in $_capability. + * + * @param string $data The response from the capability command. + * + * @return void + */ + function _parseCapability($data) + { + // Clear the cached capabilities. + $this->_capability = array('sasl' => array(), + 'extensions' => array()); + + $data = preg_split('/\r?\n/', $this->_toUpper($data), -1, PREG_SPLIT_NO_EMPTY); + + for ($i = 0; $i < count($data); $i++) { + if (!preg_match('/^"([A-Z]+)"( "(.*)")?$/', $data[$i], $matches)) { + continue; + } + switch ($matches[1]) { + case 'IMPLEMENTATION': + $this->_capability['implementation'] = $matches[3]; + break; + + case 'SASL': + $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]); + break; + + case 'SIEVE': + $this->_capability['extensions'] = preg_split('/\s+/', $matches[3]); + break; + + case 'STARTTLS': + $this->_capability['starttls'] = true; + break; + } + } + } + + /** + * Sends a command to the server + * + * @param string $cmd The command to send. + * + * @return void + */ + function _sendCmd($cmd) + { + $status = $this->_sock->getStatus(); + if (PEAR::isError($status) || $status['eof']) { + return PEAR::raiseError('Failed to write to socket: connection lost'); + } + if (PEAR::isError($error = $this->_sock->write($cmd . "\r\n"))) { + return PEAR::raiseError( + 'Failed to write to socket: ' . $error->getMessage() + ); + } + $this->_debug("C: $cmd"); + } + + /** + * Sends a string response to the server. + * + * @param string $str The string to send. + * + * @return void + */ + function _sendStringResponse($str) + { + return $this->_sendCmd('{' . $this->_getLineLength($str) . "+}\r\n" . $str); + } + + /** + * Receives a single line from the server. + * + * @return string The server response line. + */ + function _recvLn() + { + if (PEAR::isError($lastline = $this->_sock->gets(8192))) { + return PEAR::raiseError( + 'Failed to read from socket: ' . $lastline->getMessage() + ); + } + + $lastline = rtrim($lastline); + $this->_debug("S: $lastline"); + + if ($lastline === '') { + return PEAR::raiseError('Failed to read from socket'); + } + + return $lastline; + } + + /** + * Receives a number of bytes from the server. + * + * @param integer $length Number of bytes to read. + * + * @return string The server response. + */ + function _recvBytes($length) + { + $response = ''; + $response_length = 0; + while ($response_length < $length) { + $response .= $this->_sock->read($length - $response_length); + $response_length = $this->_getLineLength($response); + } + $this->_debug('S: ' . rtrim($response)); + return $response; + } + + /** + * Send a command and retrieves a response from the server. + * + * @param string $cmd The command to send. + * @param boolean $auth Whether this is an authentication command. + * + * @return string|PEAR_Error Reponse string if an OK response, PEAR_Error + * if a NO response. + */ + function _doCmd($cmd = '', $auth = false) + { + $referralCount = 0; + while ($referralCount < $this->_maxReferralCount) { + if (strlen($cmd)) { + if (PEAR::isError($error = $this->_sendCmd($cmd))) { + return $error; + } + } + + $response = ''; + while (true) { + if (PEAR::isError($line = $this->_recvLn())) { + return $line; + } + $uc_line = $this->_toUpper($line); + + if ('OK' == substr($uc_line, 0, 2)) { + $response .= $line; + return rtrim($response); + } + + if ('NO' == substr($uc_line, 0, 2)) { + // Check for string literal error message. + if (preg_match('/{([0-9]+)}$/', $line, $matches)) { + $line = substr($line, 0, -(strlen($matches[1])+2)) + . str_replace( + "\r\n", ' ', $this->_recvBytes($matches[1] + 2) + ); + } + return PEAR::raiseError(trim($response . substr($line, 2)), 3); + } + + if ('BYE' == substr($uc_line, 0, 3)) { + if (PEAR::isError($error = $this->disconnect(false))) { + return PEAR::raiseError( + 'Cannot handle BYE, the error was: ' + . $error->getMessage(), + 4 + ); + } + // Check for referral, then follow it. Otherwise, carp an + // error. + if (preg_match('/^bye \(referral "(sieve:\/\/)?([^"]+)/i', $line, $matches)) { + // Replace the old host with the referral host + // preserving any protocol prefix. + $this->_data['host'] = preg_replace( + '/\w+(?!(\w|\:\/\/)).*/', $matches[2], + $this->_data['host'] + ); + if (PEAR::isError($error = $this->_handleConnectAndLogin())) { + return PEAR::raiseError( + 'Cannot follow referral to ' + . $this->_data['host'] . ', the error was: ' + . $error->getMessage(), + 5 + ); + } + break; + } + return PEAR::raiseError(trim($response . $line), 6); + } + + if (preg_match('/^{([0-9]+)}/', $line, $matches)) { + // Matches literal string responses. + $line = $this->_recvBytes($matches[1] + 2); + if (!$auth) { + // Receive the pending OK only if we aren't + // authenticating since string responses during + // authentication don't need an OK. + $this->_recvLn(); + } + return $line; + } + + if ($auth) { + // String responses during authentication don't need an + // OK. + $response .= $line; + return rtrim($response); + } + + $response .= $line . "\r\n"; + $referralCount++; + } + } + + return PEAR::raiseError('Max referral count (' . $referralCount . ') reached. Cyrus murder loop error?', 7); + } + + /** + * Returns the name of the best authentication method that the server + * has advertised. + * + * @param string $userMethod Only consider this method as available. + * + * @return string The name of the best supported authentication method or + * a PEAR_Error object on failure. + */ + function _getBestAuthMethod($userMethod = null) + { + if (!isset($this->_capability['sasl'])) { + return PEAR::raiseError('This server doesn\'t support any authentication methods. SASL problem?'); + } + if (!$this->_capability['sasl']) { + return PEAR::raiseError('This server doesn\'t support any authentication methods.'); + } + + if ($userMethod) { + if (in_array($userMethod, $this->_capability['sasl'])) { + return $userMethod; + } + return PEAR::raiseError( + sprintf('No supported authentication method found. The server supports these methods: %s, but we want to use: %s', + implode(', ', $this->_capability['sasl']), + $userMethod)); + } + + foreach ($this->supportedAuthMethods as $method) { + if (in_array($method, $this->_capability['sasl'])) { + return $method; + } + } + + return PEAR::raiseError( + sprintf('No supported authentication method found. The server supports these methods: %s, but we only support: %s', + implode(', ', $this->_capability['sasl']), + implode(', ', $this->supportedAuthMethods))); + } + + /** + * Starts a TLS connection. + * + * @return boolean True on success, PEAR_Error on failure. + */ + function _startTLS() + { + if (PEAR::isError($res = $this->_doCmd('STARTTLS'))) { + return $res; + } + + if (!stream_socket_enable_crypto($this->_sock->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + return PEAR::raiseError('Failed to establish TLS connection', 2); + } + + $this->_debug('STARTTLS negotiation successful'); + + // The server should be sending a CAPABILITY response after + // negotiating TLS. Read it, and ignore if it doesn't. + // Unfortunately old Cyrus versions are broken and don't send a + // CAPABILITY response, thus we would wait here forever. Parse the + // Cyrus version and work around this broken behavior. + if (!preg_match('/^CYRUS TIMSIEVED V([0-9.]+)/', $this->_capability['implementation'], $matches) || + version_compare($matches[1], '2.3.10', '>=')) { + $this->_doCmd(); + } + + // Query the server capabilities again now that we are under + // encryption. + if (PEAR::isError($res = $this->_cmdCapability())) { + return PEAR::raiseError( + 'Failed to connect, server said: ' . $res->getMessage(), 2 + ); + } + + return true; + } + + /** + * Returns the length of a string. + * + * @param string $string A string. + * + * @return integer The length of the string. + */ + function _getLineLength($string) + { + if (extension_loaded('mbstring')) { + return mb_strlen($string, 'latin1'); + } else { + return strlen($string); + } + } + + /** + * Locale independant strtoupper() implementation. + * + * @param string $string The string to convert to lowercase. + * + * @return string The lowercased string, based on ASCII encoding. + */ + function _toUpper($string) + { + $language = setlocale(LC_CTYPE, 0); + setlocale(LC_CTYPE, 'C'); + $string = strtoupper($string); + setlocale(LC_CTYPE, $language); + return $string; + } + + /** + * Converts strings into RFC's quoted-string or literal-c2s form. + * + * @param string $string The string to convert. + * + * @return string Result string. + */ + function _escape($string) + { + // Some implementations don't allow UTF-8 characters in quoted-string, + // use literal-c2s. + if (preg_match('/[^\x01-\x09\x0B-\x0C\x0E-\x7F]/', $string)) { + return sprintf("{%d+}\r\n%s", $this->_getLineLength($string), $string); + } + + return '"' . addcslashes($string, '\\"') . '"'; + } + + /** + * Write debug text to the current debug output handler. + * + * @param string $message Debug message text. + * + * @return void + */ + function _debug($message) + { + if ($this->_debug) { + if ($this->_debug_handler) { + call_user_func_array($this->_debug_handler, array(&$this, $message)); + } else { + echo "$message\n"; + } + } + } +} diff --git a/program/lib/Roundcube/bootstrap.php b/program/lib/Roundcube/bootstrap.php index 6e5143382..c3fac1f4d 100644 --- a/program/lib/Roundcube/bootstrap.php +++ b/program/lib/Roundcube/bootstrap.php @@ -54,11 +54,11 @@ foreach ($config as $optname => $optval) { } // framework constants -define('RCUBE_VERSION', '1.0-git'); +define('RCUBE_VERSION', '0.9.5'); define('RCUBE_CHARSET', 'UTF-8'); if (!defined('RCUBE_LIB_DIR')) { - define('RCUBE_LIB_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR); + define('RCUBE_LIB_DIR', dirname(__FILE__).'/'); } if (!defined('RCUBE_INSTALL_PATH')) { @@ -303,6 +303,32 @@ function is_ascii($str, $control_chars = true) /** + * Remove single and double quotes from a given string + * + * @param string Input value + * + * @return string Dequoted string + */ +function strip_quotes($str) +{ + return str_replace(array("'", '"'), '', $str); +} + + +/** + * Remove new lines characters from given string + * + * @param string $str Input value + * + * @return string Stripped string + */ +function strip_newlines($str) +{ + return preg_replace('/[\r\n]/', '', $str); +} + + +/** * Compose a valid representation of name and e-mail address * * @param string $email E-mail address diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index a36711281..1a4c3beba 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -21,7 +21,7 @@ * Class for HTML code creation * * @package Framework - * @subpackage View + * @subpackage HTML */ class html { @@ -218,7 +218,7 @@ class html $attr = array('src' => $attr); } return self::tag('iframe', $attr, $cont, array_merge(self::$common_attrib, - array('src','name','width','height','border','frameborder','onload'))); + array('src','name','width','height','border','frameborder'))); } /** @@ -288,7 +288,7 @@ class html } // attributes with no value - if (in_array($key, array('checked', 'multiple', 'disabled', 'selected', 'autofocus'))) { + if (in_array($key, array('checked', 'multiple', 'disabled', 'selected'))) { if ($value) { $attrib_arr[] = $key . '="' . $key . '"'; } @@ -350,18 +350,16 @@ class html /** * Class to create an HTML input field * - * @package Framework - * @subpackage View + * @package HTML */ class html_inputfield extends html { protected $tagname = 'input'; protected $type = 'text'; protected $allowed = array( - 'type','name','value','size','tabindex','autocapitalize','required', + 'type','name','value','size','tabindex','autocapitalize', 'autocomplete','checked','onchange','onclick','disabled','readonly', - 'spellcheck','results','maxlength','src','multiple','accept', - 'placeholder','autofocus', + 'spellcheck','results','maxlength','src','multiple','placeholder', ); /** @@ -407,8 +405,7 @@ class html_inputfield extends html /** * Class to create an HTML password field * - * @package Framework - * @subpackage View + * @package HTML */ class html_passwordfield extends html_inputfield { @@ -418,9 +415,9 @@ class html_passwordfield extends html_inputfield /** * Class to create an hidden HTML input field * - * @package Framework - * @subpackage View + * @package HTML */ + class html_hiddenfield extends html { protected $tagname = 'input'; @@ -468,8 +465,7 @@ class html_hiddenfield extends html /** * Class to create HTML radio buttons * - * @package Framework - * @subpackage View + * @package HTML */ class html_radiobutton extends html_inputfield { @@ -499,8 +495,7 @@ class html_radiobutton extends html_inputfield /** * Class to create HTML checkboxes * - * @package Framework - * @subpackage View + * @package HTML */ class html_checkbox extends html_inputfield { @@ -530,8 +525,7 @@ class html_checkbox extends html_inputfield /** * Class to create an HTML textarea * - * @package Framework - * @subpackage View + * @package HTML */ class html_textarea extends html { @@ -589,8 +583,7 @@ class html_textarea extends html * print $select->show('CH'); * </pre> * - * @package Framework - * @subpackage View + * @package HTML */ class html_select extends html { @@ -655,8 +648,7 @@ class html_select extends html /** * Class to build an HTML table * - * @package Framework - * @subpackage View + * @package HTML */ class html_table extends html { @@ -678,11 +670,6 @@ class html_table extends html { $default_attrib = self::$doctype == 'xhtml' ? array('summary' => '', 'border' => 0) : array(); $this->attrib = array_merge($attrib, $default_attrib); - - if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') { - $this->tagname = $attrib['tagname']; - $this->allowed = self::$common_attrib; - } } /** @@ -826,20 +813,19 @@ class html_table extends html if (!empty($this->header)) { $rowcontent = ''; foreach ($this->header as $c => $col) { - $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); + $rowcontent .= self::tag('td', $col->attrib, $col->content); } - $thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) : - self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib); + $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)); } foreach ($this->rows as $r => $row) { $rowcontent = ''; foreach ($row->cells as $c => $col) { - $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); + $rowcontent .= self::tag('td', $col->attrib, $col->content); } if ($r < $this->rowindex || count($row->cells)) { - $tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib); + $tbody .= self::tag('tr', $row->attrib, $rowcontent, parent::$common_attrib); } } @@ -848,7 +834,7 @@ class html_table extends html } // add <tbody> - $this->content = $thead . ($this->tagname == 'table' ? self::tag('tbody', null, $tbody) : $tbody); + $this->content = $thead . self::tag('tbody', null, $tbody); unset($this->attrib['cols'], $this->attrib['rowsonly']); return parent::show(); @@ -873,22 +859,4 @@ class html_table extends html $this->rowindex = 0; } - /** - * Getter for the corresponding tag name for table row elements - */ - private function _row_tagname() - { - static $row_tagnames = array('table' => 'tr', 'ul' => 'li', '*' => 'div'); - return $row_tagnames[$this->tagname] ?: $row_tagnames['*']; - } - - /** - * Getter for the corresponding tag name for table cell elements - */ - private function _col_tagname() - { - static $col_tagnames = array('table' => 'td', '*' => 'span'); - return $col_tagnames[$this->tagname] ?: $col_tagnames['*']; - } - } diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index d9c3dd8b9..7329b09fb 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -99,20 +99,20 @@ class rcube protected $texts; protected $caches = array(); protected $shutdown_functions = array(); + protected $expunge_cache = false; /** * This implements the 'singleton' design pattern * * @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants - * @param string Environment name to run (e.g. live, dev, test) * * @return rcube The one and only instance */ - static function get_instance($mode = 0, $env = '') + static function get_instance($mode = 0) { if (!self::$instance) { - self::$instance = new rcube($env); + self::$instance = new rcube(); self::$instance->init($mode); } @@ -123,10 +123,10 @@ class rcube /** * Private constructor */ - protected function __construct($env = '') + protected function __construct() { // load configuration - $this->config = new rcube_config($env); + $this->config = new rcube_config; $this->plugins = new rcube_dummy_plugin_api; register_shutdown_function(array($this, 'shutdown')); @@ -258,39 +258,6 @@ class rcube /** - * Initialize and get shared cache object - * - * @param string $name Cache identifier - * @param bool $packed Enables/disables data serialization - * - * @return rcube_cache_shared Cache object - */ - public function get_cache_shared($name, $packed=true) - { - $shared_name = "shared_$name"; - - if (!array_key_exists($shared_name, $this->caches)) { - $opt = strtolower($name) . '_cache'; - $type = $this->config->get($opt); - $ttl = $this->config->get($opt . '_ttl'); - - if (!$type) { - // cache is disabled - return $this->caches[$shared_name] = null; - } - - if ($ttl === null) { - $ttl = $this->config->get('shared_cache_ttl', '10d'); - } - - $this->caches[$shared_name] = new rcube_cache_shared($type, $name, $ttl, $packed); - } - - return $this->caches[$shared_name]; - } - - - /** * Create SMTP object and connect to server * * @param boolean True if connection should be established @@ -378,7 +345,6 @@ class rcube 'auth_pw' => $this->config->get("{$driver}_auth_pw"), 'debug' => (bool) $this->config->get("{$driver}_debug"), 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), - 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"), 'timeout' => (int) $this->config->get("{$driver}_timeout"), 'skip_deleted' => (bool) $this->config->get('skip_deleted'), 'driver' => $driver, @@ -458,12 +424,15 @@ class rcube ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid'); ini_set('session.use_cookies', 1); ini_set('session.use_only_cookies', 1); + ini_set('session.serialize_handler', 'php'); ini_set('session.cookie_httponly', 1); // use database for storing session data $this->session = new rcube_session($this->get_dbh(), $this->config); - $this->session->register_gc_handler(array($this, 'gc')); + $this->session->register_gc_handler(array($this, 'temp_gc')); + $this->session->register_gc_handler(array($this, 'cache_gc')); + $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME'])); $this->session->set_ip_check($this->config->get('ip_check')); @@ -473,47 +442,27 @@ class rcube // start PHP session (if not in CLI mode) if ($_SERVER['REMOTE_ADDR']) { - $this->session->start(); + session_start(); } } /** - * Garbage collector - cache/temp cleaner - */ - public function gc() - { - rcube_cache::gc(); - rcube_cache_shared::gc(); - $this->get_storage()->cache_gc(); - - $this->gc_temp(); - } - - - /** * Garbage collector function for temp files. * Remove temp files older than two days */ - public function gc_temp() + public function temp_gc() { $tmp = unslashify($this->config->get('temp_dir')); - - // expire in 48 hours by default - $temp_dir_ttl = $this->config->get('temp_dir_ttl', '48h'); - $temp_dir_ttl = get_offset_sec($temp_dir_ttl); - if ($temp_dir_ttl < 6*3600) - $temp_dir_ttl = 6*3600; // 6 hours sensible lower bound. - - $expire = time() - $temp_dir_ttl; + $expire = time() - 172800; // expire in 48 hours if ($tmp && ($dir = opendir($tmp))) { while (($fname = readdir($dir)) !== false) { - if ($fname[0] == '.') { + if ($fname{0} == '.') { continue; } - if (@filemtime($tmp.'/'.$fname) < $expire) { + if (filemtime($tmp.'/'.$fname) < $expire) { @unlink($tmp.'/'.$fname); } } @@ -524,21 +473,14 @@ class rcube /** - * Runs garbage collector with probability based on - * session settings. This is intended for environments - * without a session. + * Garbage collector for cache entries. + * Set flag to expunge caches on shutdown */ - public function gc_run() + public function cache_gc() { - $probability = (int) ini_get('session.gc_probability'); - $divisor = (int) ini_get('session.gc_divisor'); - - if ($divisor > 0 && $probability > 0) { - $random = mt_rand(1, $divisor); - if ($random <= $probability) { - $this->gc(); - } - } + // because this gc function is called before storage is initialized, + // we just set a flag to expunge storage cache on shutdown. + $this->expunge_cache = true; } @@ -797,7 +739,7 @@ class rcube mcrypt_module_close($td); } else { - @include_once 'des.inc'; + // @include_once 'des.inc'; (not shipped with this distribution) if (function_exists('des')) { $des_iv_size = 8; @@ -852,7 +794,7 @@ class rcube mcrypt_module_close($td); } else { - @include_once 'des.inc'; + // @include_once 'des.inc'; (not shipped with this distribution) if (function_exists('des')) { $des_iv_size = 8; @@ -922,14 +864,6 @@ class rcube call_user_func($function); } - // write session data as soon as possible and before - // closing database connection, don't do this before - // registered shutdown functions, they may need the session - // Note: this will run registered gc handlers (ie. cache gc) - if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { - $this->session->write_close(); - } - if (is_object($this->smtp)) { $this->smtp->disconnect(); } @@ -941,6 +875,9 @@ class rcube } if (is_object($this->storage)) { + if ($this->expunge_cache) { + $this->storage->expunge_cache(); + } $this->storage->close(); } } @@ -1132,8 +1069,8 @@ class rcube * - code: Error code (required) * - type: Error type [php|db|imap|javascript] (required) * - message: Error message - * - file: File where error occured - * - line: Line where error occured + * - file: File where error occurred + * - line: Line where error occurred * @param boolean True to log the error * @param boolean Terminate script execution */ @@ -1359,191 +1296,6 @@ class rcube } } - /** - * Unique Message-ID generator. - * - * @return string Message-ID - */ - public function gen_message_id() - { - $local_part = md5(uniqid('rcube'.mt_rand(), true)); - $domain_part = $this->user->get_username('domain'); - - // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924) - if (!preg_match('/\.[a-z]+$/i', $domain_part)) { - foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) { - $host = preg_replace('/:[0-9]+$/', '', $host); - if ($host && preg_match('/\.[a-z]+$/i', $host)) { - $domain_part = $host; - } - } - } - - return sprintf('<%s@%s>', $local_part, $domain_part); - } - - /** - * Send the given message using the configured method. - * - * @param object $message Reference to Mail_MIME object - * @param string $from Sender address string - * @param array $mailto Array of recipient address strings - * @param array $error SMTP error array (reference) - * @param string $body_file Location of file with saved message body (reference), - * used when delay_file_io is enabled - * @param array $options SMTP options (e.g. DSN request) - * - * @return boolean Send status. - */ - public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) - { - $plugin = $this->plugins->exec_hook('message_before_send', array( - 'message' => $message, - 'from' => $from, - 'mailto' => $mailto, - 'options' => $options, - )); - - if ($plugin['abort']) { - return isset($plugin['result']) ? $plugin['result'] : false; - } - - $from = $plugin['from']; - $mailto = $plugin['mailto']; - $options = $plugin['options']; - $message = $plugin['message']; - $headers = $message->headers(); - - // send thru SMTP server using custom SMTP library - if ($this->config->get('smtp_server')) { - // generate list of recipients - $a_recipients = array($mailto); - - if (strlen($headers['Cc'])) - $a_recipients[] = $headers['Cc']; - if (strlen($headers['Bcc'])) - $a_recipients[] = $headers['Bcc']; - - // clean Bcc from header for recipients - $send_headers = $headers; - unset($send_headers['Bcc']); - // here too, it because txtHeaders() below use $message->_headers not only $send_headers - unset($message->_headers['Bcc']); - - $smtp_headers = $message->txtHeaders($send_headers, true); - - if ($message->getParam('delay_file_io')) { - // use common temp dir - $temp_dir = $this->config->get('temp_dir'); - $body_file = tempnam($temp_dir, 'rcmMsg'); - if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { - self::raise_error(array('code' => 650, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not create message: ".$mime_result->getMessage()), - TRUE, FALSE); - return false; - } - $msg_body = fopen($body_file, 'r'); - } - else { - $msg_body = $message->get(); - } - - // send message - if (!is_object($this->smtp)) { - $this->smtp_init(true); - } - - $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options); - $response = $this->smtp->get_response(); - $error = $this->smtp->get_error(); - - // log error - if (!$sent) { - self::raise_error(array('code' => 800, 'type' => 'smtp', - 'line' => __LINE__, 'file' => __FILE__, - 'message' => "SMTP error: ".join("\n", $response)), TRUE, FALSE); - } - } - // send mail using PHP's mail() function - else { - // unset some headers because they will be added by the mail() function - $headers_enc = $message->headers($headers); - $headers_php = $message->_headers; - unset($headers_php['To'], $headers_php['Subject']); - - // reset stored headers and overwrite - $message->_headers = array(); - $header_str = $message->txtHeaders($headers_php); - - // #1485779 - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { - $headers_enc['To'] = implode(', ', $m[1]); - } - } - - $msg_body = $message->get(); - - if (PEAR::isError($msg_body)) { - self::raise_error(array('code' => 650, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not create message: ".$msg_body->getMessage()), - TRUE, FALSE); - } - else { - $delim = $this->config->header_delimiter(); - $to = $headers_enc['To']; - $subject = $headers_enc['Subject']; - $header_str = rtrim($header_str); - - if ($delim != "\r\n") { - $header_str = str_replace("\r\n", $delim, $header_str); - $msg_body = str_replace("\r\n", $delim, $msg_body); - $to = str_replace("\r\n", $delim, $to); - $subject = str_replace("\r\n", $delim, $subject); - } - - if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN)) - $sent = mail($to, $subject, $msg_body, $header_str); - else - $sent = mail($to, $subject, $msg_body, $header_str, "-f$from"); - } - } - - if ($sent) { - $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); - - // remove MDN headers after sending - unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); - - // get all recipients - if ($headers['Cc']) - $mailto .= $headers['Cc']; - if ($headers['Bcc']) - $mailto .= $headers['Bcc']; - if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) - $mailto = implode(', ', array_unique($m[1])); - - if ($this->config->get('smtp_log')) { - self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", - $this->user->get_username(), - $_SERVER['REMOTE_ADDR'], - $mailto, - !empty($response) ? join('; ', $response) : '')); - } - } - - if (is_resource($msg_body)) { - fclose($msg_body); - } - - $message->_headers = array(); - $message->headers($headers); - - return $sent; - } - } diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index 9301211ff..13016ecc7 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2013, The Roundcube Dev Team | + | Copyright (C) 2006-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -35,7 +35,6 @@ abstract class rcube_addressbook /** public properties (mandatory) */ public $primary_key; public $groups = false; - public $export_groups = true; public $readonly = true; public $searchonly = false; public $undelete = false; @@ -134,7 +133,7 @@ abstract class rcube_addressbook abstract function get_record($id, $assoc=false); /** - * Returns the last error occured (e.g. when updating/inserting failed) + * Returns the last error occurred (e.g. when updating/inserting failed) * * @return array Hash array with the following fields: type, message */ @@ -424,7 +423,7 @@ abstract class rcube_addressbook * @param boolean True to return one array with all values, False for hash array with values grouped by type * @return array List of column values */ - public static function get_col_values($col, $data, $flat = false) + function get_col_values($col, $data, $flat = false) { $out = array(); foreach ((array)$data as $c => $values) { @@ -433,7 +432,7 @@ abstract class rcube_addressbook $out = array_merge($out, (array)$values); } else { - list(, $type) = explode(':', $c); + list($f, $type) = explode(':', $c); $out[$type] = array_merge((array)$out[$type], (array)$values); } } @@ -477,8 +476,7 @@ abstract class rcube_addressbook $fn = trim(join(' ', array_filter(array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix'])))); // use email address part for name - $email = self::get_col_values('email', $contact, true); - $email = $email[0]; + $email = is_array($contact['email']) ? $contact['email'][0] : $contact['email']; if ($email && (empty($fn) || $fn == $email)) { // return full email @@ -525,9 +523,9 @@ abstract class rcube_addressbook $fn = $contact['name']; // fallback to email address - if (empty($fn) && ($email = self::get_col_values('email', $contact, true)) && !empty($email)) { - return $email[0]; - } + $email = is_array($contact['email']) ? $contact['email'][0] : $contact['email']; + if (empty($fn) && $email) + return $email; return $fn; } @@ -540,11 +538,11 @@ abstract class rcube_addressbook $key = $contact[$sort_col] . ':' . $contact['sourceid']; // add email to a key to not skip contacts with the same name (#1488375) - if (($email = self::get_col_values('email', $contact, true)) && !empty($email)) { - $key .= ':' . implode(':', (array)$email); - } + if (!empty($contact['email'])) { + $key .= ':' . implode(':', (array)$contact['email']); + } - return $key; + return $key; } /** @@ -563,9 +561,9 @@ abstract class rcube_addressbook // use only strict comparison (mode = 1) // @TODO: partial search, e.g. match only day and month if (in_array($colname, $this->date_cols)) { - return (($value = rcube_utils::anytodatetime($value)) - && ($search = rcube_utils::anytodatetime($search)) - && $value->format('Ymd') == $search->format('Ymd')); + return (($value = rcube_utils::strtotime($value)) + && ($search = rcube_utils::strtotime($search)) + && date('Ymd', $value) == date('Ymd', $search)); } // composite field, e.g. address diff --git a/program/lib/Roundcube/rcube_base_replacer.php b/program/lib/Roundcube/rcube_base_replacer.php index a59bba926..aaaa2028c 100644 --- a/program/lib/Roundcube/rcube_base_replacer.php +++ b/program/lib/Roundcube/rcube_base_replacer.php @@ -21,7 +21,7 @@ * using a predefined base * * @package Framework - * @subpackage Utils + * @subpackage Core * @author Thomas Bruederli <roundcube@gmail.com> */ class rcube_base_replacer diff --git a/program/lib/Roundcube/rcube_browser.php b/program/lib/Roundcube/rcube_browser.php index 34128291b..d10fe2a2c 100644 --- a/program/lib/Roundcube/rcube_browser.php +++ b/program/lib/Roundcube/rcube_browser.php @@ -20,7 +20,7 @@ * Provide details about the client's browser based on the User-Agent header * * @package Framework - * @subpackage Utils + * @subpackage Core */ class rcube_browser { diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php index a708cb292..deaba68e9 100644 --- a/program/lib/Roundcube/rcube_cache.php +++ b/program/lib/Roundcube/rcube_cache.php @@ -38,7 +38,6 @@ class rcube_cache private $type; private $userid; private $prefix; - private $table; private $ttl; private $packed; private $index; @@ -72,9 +71,8 @@ class rcube_cache $this->db = function_exists('apc_exists'); // APC 3.1.4 required } else { - $this->type = 'db'; - $this->db = $rcube->get_dbh(); - $this->table = $this->db->table_name('cache'); + $this->type = 'db'; + $this->db = $rcube->get_dbh(); } // convert ttl string to seconds @@ -194,31 +192,20 @@ class rcube_cache */ function expunge() { - if ($this->type == 'db' && $this->db && $this->ttl) { + if ($this->type == 'db' && $this->db) { $this->db->query( - "DELETE FROM ".$this->table. + "DELETE FROM ".$this->db->table_name('cache'). " WHERE user_id = ?". " AND cache_key LIKE ?". - " AND expires < " . $this->db->now(), + " AND " . $this->db->unixtimestamp('created')." < ?", $this->userid, - $this->prefix.'.%'); + $this->prefix.'.%', + time() - $this->ttl); } } /** - * Remove expired records of all caches - */ - static function gc() - { - $rcube = rcube::get_instance(); - $db = $rcube->get_dbh(); - - $db->query("DELETE FROM " . $db->table_name('cache') . " WHERE expires < " . $db->now()); - } - - - /** * Writes the cache back to the DB. */ function close() @@ -284,7 +271,7 @@ class rcube_cache else { $sql_result = $this->db->limitquery( "SELECT data, cache_key". - " FROM " . $this->table. + " FROM ".$this->db->table_name('cache'). " WHERE user_id = ?". " AND cache_key = ?". // for better performance we allow more records for one key @@ -339,7 +326,7 @@ class rcube_cache // Remove NULL rows (here we don't need to check if the record exist) if ($data == 'N;') { $this->db->query( - "DELETE FROM " . $this->table. + "DELETE FROM ".$this->db->table_name('cache'). " WHERE user_id = ?". " AND cache_key = ?", $this->userid, $key); @@ -350,10 +337,8 @@ class rcube_cache // update existing cache record if ($key_exists) { $result = $this->db->query( - "UPDATE " . $this->table. - " SET created = " . $this->db->now(). - ", expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL'). - ", data = ?". + "UPDATE ".$this->db->table_name('cache'). + " SET created = ". $this->db->now().", data = ?". " WHERE user_id = ?". " AND cache_key = ?", $data, $this->userid, $key); @@ -363,9 +348,9 @@ class rcube_cache // for better performance we allow more records for one key // so, no need to check if record exist (see rcube_cache::read_record()) $result = $this->db->query( - "INSERT INTO " . $this->table. - " (created, expires, user_id, cache_key, data)". - " VALUES (" . $this->db->now() . ", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?, ?)", + "INSERT INTO ".$this->db->table_name('cache'). + " (created, user_id, cache_key, data)". + " VALUES (".$this->db->now().", ?, ?, ?)", $this->userid, $key, $data); } @@ -426,7 +411,7 @@ class rcube_cache } $this->db->query( - "DELETE FROM " . $this->table. + "DELETE FROM ".$this->db->table_name('cache'). " WHERE user_id = ?" . $where, $this->userid); } diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php index ac3ea678c..3edec4242 100644 --- a/program/lib/Roundcube/rcube_config.php +++ b/program/lib/Roundcube/rcube_config.php @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2013, The Roundcube Dev Team | + | Copyright (C) 2008-2012, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -26,8 +26,6 @@ class rcube_config { const DEFAULT_SKIN = 'larry'; - private $env = ''; - private $paths = array(); private $prop = array(); private $errors = array(); private $userprefs = array(); @@ -45,46 +43,14 @@ class rcube_config 'reply_mode' => 'top_posting', 'refresh_interval' => 'keep_alive', 'min_refresh_interval' => 'min_keep_alive', - 'messages_cache_ttl' => 'message_cache_lifetime', - 'redundant_attachments_cache_ttl' => 'redundant_attachments_memcache_ttl', ); /** * Object constructor - * - * @param string Environment suffix for config files to load */ - public function __construct($env = '') + public function __construct() { - $this->env = $env; - - if ($paths = getenv('RCUBE_CONFIG_PATH')) { - $this->paths = explode(PATH_SEPARATOR, $paths); - // make all paths absolute - foreach ($this->paths as $i => $path) { - if (!$this->_is_absolute($path)) { - if ($realpath = realpath(RCUBE_INSTALL_PATH . $path)) { - $this->paths[$i] = unslashify($realpath) . '/'; - } - else { - unset($this->paths[$i]); - } - } - else { - $this->paths[$i] = unslashify($path) . '/'; - } - } - } - - if (defined('RCUBE_CONFIG_DIR') && !in_array(RCUBE_CONFIG_DIR, $this->paths)) { - $this->paths[] = RCUBE_CONFIG_DIR; - } - - if (empty($this->paths)) { - $this->paths[] = RCUBE_INSTALL_PATH . 'config/'; - } - $this->load(); // Defaults, that we do not require you to configure, @@ -101,26 +67,16 @@ class rcube_config */ private function load() { - // Load default settings - if (!$this->load_from_file('defaults.inc.php')) { - $this->errors[] = 'defaults.inc.php was not found.'; - } - // load main config file - if (!$this->load_from_file('config.inc.php')) { - // Old configuration files - if (!$this->load_from_file('main.inc.php') || - !$this->load_from_file('db.inc.php')) { - $this->errors[] = 'config.inc.php was not found.'; - } - else if (rand(1,100) == 10) { // log warning on every 100th request (average) - trigger_error("config.inc.php was not found. Please migrate your config by running bin/update.sh", E_USER_WARNING); - } - } + if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'main.inc.php')) + $this->errors[] = 'main.inc.php was not found.'; + + // load database config + if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'db.inc.php')) + $this->errors[] = 'db.inc.php was not found.'; // load host-specific configuration - if (!empty($_SERVER['HTTP_HOST'])) - $this->load_host_config(); + $this->load_host_config(); // set skin (with fallback to old 'skin_path' property) if (empty($this->prop['skin'])) { @@ -163,6 +119,17 @@ class rcube_config // enable display_errors in 'show' level, but not for ajax requests ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4))); + // set timezone auto settings values + if ($this->prop['timezone'] == 'auto') { + $this->prop['_timezone_value'] = $this->client_timezone(); + } + else if (is_numeric($this->prop['timezone']) && ($tz = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0))) { + $this->prop['timezone'] = $tz; + } + else if (empty($this->prop['timezone'])) { + $this->prop['timezone'] = 'UTC'; + } + // remove deprecated properties unset($this->prop['dst_active']); @@ -186,7 +153,7 @@ class rcube_config } if ($fname) { - $this->load_from_file($fname); + $this->load_from_file(RCUBE_CONFIG_DIR . $fname); } } @@ -195,78 +162,26 @@ class rcube_config * Read configuration from a file * and merge with the already stored config values * - * @param string $file Name of the config file to be loaded + * @param string $fpath Full path to the config file to be loaded * @return booelan True on success, false on failure */ - public function load_from_file($file) - { - $success = false; - - foreach ($this->resolve_paths($file) as $fpath) { - if ($fpath && is_file($fpath) && is_readable($fpath)) { - // use output buffering, we don't need any output here - ob_start(); - include($fpath); - ob_end_clean(); - - if (is_array($config)) { - $this->merge($config); - $success = true; - } - // deprecated name of config variable - else if (is_array($rcmail_config)) { - $this->merge($rcmail_config); - $success = true; - } - } - } - - return $success; - } - - /** - * Helper method to resolve absolute paths to the given config file. - * This also takes the 'env' property into account. - * - * @param string Filename or absolute file path - * @param boolean Return -$env file path if exists - * @return array List of candidates in config dir path(s) - */ - public function resolve_paths($file, $use_env = true) + public function load_from_file($fpath) { - $files = array(); - $abs_path = $this->_is_absolute($file); - - foreach ($this->paths as $basepath) { - $realpath = $abs_path ? $file : realpath($basepath . '/' . $file); - - // check if <file>-env.ini exists - if ($realpath && $use_env && !empty($this->env)) { - $envfile = preg_replace('/\.(inc.php)$/', '-' . $this->env . '.\\1', $realpath); - if (is_file($envfile)) - $realpath = $envfile; - } - - if ($realpath) { - $files[] = $realpath; - - // no need to continue the loop if an absolute file path is given - if ($abs_path) { - break; - } + if (is_file($fpath) && is_readable($fpath)) { + // use output buffering, we don't need any output here + ob_start(); + include($fpath); + ob_end_clean(); + + if (is_array($rcmail_config)) { + $this->merge($rcmail_config); + return true; } } - return $files; + return false; } - /** - * Determine whether the given file path is absolute or relative - */ - private function _is_absolute($path) - { - return $path[0] == DIRECTORY_SEPARATOR || preg_match('!^[a-z]:[\\\\/]!i', $path); - } /** * Getter for a specific config parameter @@ -286,10 +201,8 @@ class rcube_config $rcube = rcube::get_instance(); - if ($name == 'timezone') { - if (empty($result) || $result == 'auto') { - $result = $this->client_timezone(); - } + if ($name == 'timezone' && isset($this->prop['_timezone_value'])) { + $result = $this->prop['_timezone_value']; } else if ($name == 'client_mimetypes') { if ($result == null && $def == null) @@ -347,6 +260,11 @@ class rcube_config } } + // convert user's timezone into the new format + if (is_numeric($prefs['timezone']) && ($tz = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0))) { + $prefs['timezone'] = $tz; + } + // larry is the new default skin :-) if ($prefs['skin'] == 'default') { $prefs['skin'] = self::DEFAULT_SKIN; @@ -354,6 +272,13 @@ class rcube_config $this->userprefs = $prefs; $this->prop = array_merge($this->prop, $prefs); + + // override timezone settings with client values + if ($this->prop['timezone'] == 'auto') { + $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $this->client_timezone() : $this->prop['_timezone_value']; + } + else if (isset($this->prop['_timezone_value'])) + unset($this->prop['_timezone_value']); } @@ -494,12 +419,13 @@ class rcube_config */ private function client_timezone() { - // @TODO: remove this legacy timezone handling in the future - $props = $this->fix_legacy_props(array('timezone' => $_SESSION['timezone'])); - - if (!empty($props['timezone'])) { + if (isset($_SESSION['timezone']) && is_numeric($_SESSION['timezone']) + && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0))) { + return $ctz; + } + else if (!empty($_SESSION['timezone'])) { try { - $tz = new DateTimeZone($props['timezone']); + $tz = timezone_open($_SESSION['timezone']); return $tz->getName(); } catch (Exception $e) { /* gracefully ignore */ } @@ -527,77 +453,6 @@ class rcube_config } } - // convert deprecated numeric timezone value - if (isset($props['timezone']) && is_numeric($props['timezone'])) { - if ($tz = self::timezone_name_from_abbr($props['timezone'])) { - $props['timezone'] = $tz; - } - else { - unset($props['timezone']); - } - } - return $props; } - - /** - * timezone_name_from_abbr() replacement. Converts timezone offset - * into timezone name abbreviation. - * - * @param float $offset Timezone offset (in hours) - * - * @return string Timezone abbreviation - */ - static public function timezone_name_from_abbr($offset) - { - // List of timezones here is not complete - https://bugs.php.net/bug.php?id=44780 - if ($tz = timezone_name_from_abbr('', $offset * 3600, 0)) { - return $tz; - } - - // try with more complete list (#1489261) - $timezones = array( - '-660' => "Pacific/Apia", - '-600' => "Pacific/Honolulu", - '-570' => "Pacific/Marquesas", - '-540' => "America/Anchorage", - '-480' => "America/Los_Angeles", - '-420' => "America/Denver", - '-360' => "America/Chicago", - '-300' => "America/New_York", - '-270' => "America/Caracas", - '-240' => "America/Halifax", - '-210' => "Canada/Newfoundland", - '-180' => "America/Sao_Paulo", - '-60' => "Atlantic/Azores", - '0' => "Europe/London", - '60' => "Europe/Paris", - '120' => "Europe/Helsinki", - '180' => "Europe/Moscow", - '210' => "Asia/Tehran", - '240' => "Asia/Dubai", - '300' => "Asia/Karachi", - '270' => "Asia/Kabul", - '300' => "Asia/Karachi", - '330' => "Asia/Kolkata", - '345' => "Asia/Katmandu", - '360' => "Asia/Yekaterinburg", - '390' => "Asia/Rangoon", - '420' => "Asia/Krasnoyarsk", - '480' => "Asia/Shanghai", - '525' => "Australia/Eucla", - '540' => "Asia/Tokyo", - '570' => "Australia/Adelaide", - '600' => "Australia/Melbourne", - '630' => "Australia/Lord_Howe", - '660' => "Asia/Vladivostok", - '690' => "Pacific/Norfolk", - '720' => "Pacific/Auckland", - '765' => "Pacific/Chatham", - '780' => "Pacific/Enderbury", - '840' => "Pacific/Kiritimati", - ); - - return $timezones[(string) intval($offset * 60)]; - } } diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index 6d01368a1..3919cdc6e 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -718,10 +718,6 @@ class rcube_contacts extends rcube_addressbook foreach ($save_data as $key => $values) { list($field, $section) = explode(':', $key); $fulltext = in_array($field, $this->fulltext_cols); - // avoid casting DateTime objects to array - if (is_object($values) && is_a($values, 'DateTime')) { - $values = array(0 => $values); - } foreach ((array)$values as $value) { if (isset($value)) $vcard->set($field, $value, $section); diff --git a/program/lib/Roundcube/rcube_content_filter.php b/program/lib/Roundcube/rcube_content_filter.php index ae6617d1b..b814bb71d 100644 --- a/program/lib/Roundcube/rcube_content_filter.php +++ b/program/lib/Roundcube/rcube_content_filter.php @@ -20,7 +20,7 @@ * PHP stream filter to detect html/javascript code in attachments * * @package Framework - * @subpackage Utils + * @subpackage Core */ class rcube_content_filter extends php_user_filter { diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index 00e6d4e20..506a4b740 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -130,22 +130,6 @@ class rcube_csv2vcard 'work_state' => 'region:work', 'home_city_short' => 'locality:home', 'home_state_short' => 'region:home', - - // Atmail - 'date_of_birth' => 'birthday', - 'email' => 'email:pref', - 'home_mobile' => 'phone:cell', - 'home_zip' => 'zipcode:home', - 'info' => 'notes', - 'user_photo' => 'photo', - 'url' => 'website:homepage', - 'work_company' => 'organization', - 'work_dept' => 'departament', - 'work_fax' => 'phone:work,fax', - 'work_mobile' => 'phone:work,cell', - 'work_title' => 'jobtitle', - 'work_zip' => 'zipcode:work', - 'group' => 'groups', ); /** @@ -246,30 +230,8 @@ class rcube_csv2vcard 'work_phone' => "Work Phone", 'work_address' => "Work Address", //'work_address_2' => "Work Address 2", - 'work_city' => "Work City", 'work_country' => "Work Country", - 'work_state' => "Work State", 'work_zipcode' => "Work ZipCode", - - // Atmail - 'date_of_birth' => "Date of Birth", - 'email' => "Email", - //'email_2' => "Email2", - //'email_3' => "Email3", - //'email_4' => "Email4", - //'email_5' => "Email5", - 'home_mobile' => "Home Mobile", - 'home_zip' => "Home Zip", - 'info' => "Info", - 'user_photo' => "User Photo", - 'url' => "URL", - 'work_company' => "Work Company", - 'work_dept' => "Work Dept", - 'work_fax' => "Work Fax", - 'work_mobile' => "Work Mobile", - 'work_title' => "Work Title", - 'work_zip' => "Work Zip", - 'groups' => "Group", ); protected $local_label_map = array(); @@ -306,6 +268,7 @@ class rcube_csv2vcard { // convert to UTF-8 $head = substr($csv, 0, 4096); + $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1? $charset = rcube_charset::detect($head, RCUBE_CHARSET); $csv = rcube_charset::convert($csv, $charset); $head = ''; @@ -313,7 +276,7 @@ class rcube_csv2vcard $this->map = array(); // Parse file - foreach (preg_split("/[\r\n]+/", $csv) as $line) { + foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) { $elements = $this->parse_line($line); if (empty($elements)) { continue; @@ -427,13 +390,9 @@ class rcube_csv2vcard $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; } - // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00" foreach (array('birthday', 'anniversary') as $key) { - if (!empty($contact[$key])) { - $date = preg_replace('/[0[:^word:]]/', '', $contact[$key]); - if (empty($date)) { - unset($contact[$key]); - } + if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization? + unset($contact[$key]); } } diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index 852070073..5083a0dfe 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -47,7 +47,6 @@ class rcube_db 'identifier_end' => '"', ); - const DEBUG_LINE_LENGTH = 4096; /** * Factory, returns driver-specific instance of the class @@ -63,6 +62,7 @@ class rcube_db $driver = strtolower(substr($db_dsnw, 0, strpos($db_dsnw, ':'))); $driver_map = array( 'sqlite2' => 'sqlite', + 'sqlite3' => 'sqlite', 'sybase' => 'mssql', 'dblib' => 'mssql', 'mysqli' => 'mysql', @@ -100,15 +100,27 @@ class rcube_db $this->db_dsnw_array = self::parse_dsn($db_dsnw); $this->db_dsnr_array = self::parse_dsn($db_dsnr); + + // Initialize driver class + $this->init(); + } + + /** + * Initialization of the object with driver specific code + */ + protected function init() + { + // To be used by driver classes } /** * Connect to specific database * - * @param array $dsn DSN for DB connections - * @param string $mode Connection mode (r|w) + * @param array $dsn DSN for DB connections + * + * @return PDO database handle */ - protected function dsn_connect($dsn, $mode) + protected function dsn_connect($dsn) { $this->db_error = false; $this->db_error_msg = null; @@ -146,10 +158,9 @@ class rcube_db return null; } - $this->dbh = $dbh; - $this->db_mode = $mode; - $this->db_connected = true; $this->conn_configure($dsn, $dbh); + + return $dbh; } /** @@ -172,6 +183,16 @@ class rcube_db } /** + * Driver-specific database character set setting + * + * @param string $charset Character set name + */ + protected function set_charset($charset) + { + $this->query("SET NAMES 'utf8'"); + } + + /** * Connect to appropriate database depending on the operation * * @param string $mode Connection mode (r|w) @@ -198,14 +219,23 @@ class rcube_db $dsn = ($mode == 'r') ? $this->db_dsnr_array : $this->db_dsnw_array; - $this->dsn_connect($dsn, $mode); + $this->dbh = $this->dsn_connect($dsn); + $this->db_connected = is_object($this->dbh); // use write-master when read-only fails - if (!$this->db_connected && $mode == 'r' && $this->is_replicated()) { - $this->dsn_connect($this->db_dsnw_array, 'w'); + if (!$this->db_connected && $mode == 'r') { + $mode = 'w'; + $this->dbh = $this->dsn_connect($this->db_dsnw_array); + $this->db_connected = is_object($this->dbh); } - $this->conn_failure = !$this->db_connected; + if ($this->db_connected) { + $this->db_mode = $mode; + $this->set_charset('utf8'); + } + else { + $this->conn_failure = true; + } } /** @@ -226,11 +256,6 @@ class rcube_db protected function debug($query) { if ($this->options['debug_mode']) { - if (($len = strlen($query)) > self::DEBUG_LINE_LENGTH) { - $diff = $len - self::DEBUG_LINE_LENGTH; - $query = substr($query, 0, self::DEBUG_LINE_LENGTH) - . "... [truncated $diff bytes]"; - } rcube::write_log('sql', '[' . (++$this->db_index) . '] ' . $query . ';'); } } @@ -338,10 +363,8 @@ class rcube_db */ protected function _query($query, $offset, $numrows, $params) { - $query = trim($query); - // Read or write ? - $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w'; + $mode = preg_match('/^(select|show)/i', ltrim($query)) ? 'r' : 'w'; $this->db_connect($mode); @@ -387,16 +410,13 @@ class rcube_db if ($result === false) { $error = $this->dbh->errorInfo(); + $this->db_error = true; + $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); - if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') { - $this->db_error = true; - $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); - - rcube::raise_error(array('code' => 500, 'type' => 'db', - 'line' => __LINE__, 'file' => __FILE__, - 'message' => $this->db_error_msg . " (SQL Query: $query)" - ), true, false); - } + rcube::raise_error(array('code' => 500, 'type' => 'db', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => $this->db_error_msg . " (SQL Query: $query)" + ), true, false); } $this->last_result = $result; @@ -683,19 +703,11 @@ class rcube_db /** * Return SQL function for current time and date * - * @param int $interval Optional interval (in seconds) to add/subtract - * * @return string SQL function to use in query */ - public function now($interval = 0) + public function now() { - if ($interval) { - $add = ' ' . ($interval > 0 ? '+' : '-') . ' INTERVAL '; - $add .= $interval > 0 ? intval($interval) : intval($interval) * -1; - $add .= ' SECOND'; - } - - return "now()" . $add; + return "now()"; } /** @@ -856,26 +868,17 @@ class rcube_db { $rcube = rcube::get_instance(); - // add prefix to the table name if configured - if ($prefix = $rcube->config->get('db_prefix')) { - return $prefix . $table; + // return table name if configured + $config_key = 'db_table_'.$table; + + if ($name = $rcube->config->get($config_key)) { + return $name; } return $table; } /** - * Set class option value - * - * @param string $name Option name - * @param mixed $value Option value - */ - public function set_option($name, $value) - { - $this->options[$name] = $value; - } - - /** * MDB2 DSN string parser * * @param string $sequence Secuence name diff --git a/program/lib/Roundcube/rcube_db_mssql.php b/program/lib/Roundcube/rcube_db_mssql.php index 3c1b9d71f..37a42678a 100644 --- a/program/lib/Roundcube/rcube_db_mssql.php +++ b/program/lib/Roundcube/rcube_db_mssql.php @@ -29,52 +29,38 @@ class rcube_db_mssql extends rcube_db public $db_provider = 'mssql'; /** - * Object constructor - * - * @param string $db_dsnw DSN for read/write operations - * @param string $db_dsnr Optional DSN for read only operations - * @param bool $pconn Enables persistent connections + * Driver initialization */ - public function __construct($db_dsnw, $db_dsnr = '', $pconn = false) + protected function init() { - parent::__construct($db_dsnw, $db_dsnr, $pconn); - $this->options['identifier_start'] = '['; $this->options['identifier_end'] = ']'; } /** - * Driver-specific configuration of database connection - * - * @param array $dsn DSN for DB connections - * @param PDO $dbh Connection handler + * Character setting */ - protected function conn_configure($dsn, $dbh) + protected function set_charset($charset) { - // Set date format in case of non-default language (#1488918) - $this->query("SET DATEFORMAT ymd"); + // UTF-8 is default } /** * Return SQL function for current time and date * - * @param int $interval Optional interval (in seconds) to add/subtract - * * @return string SQL function to use in query */ - public function now($interval = 0) + public function now() { - if ($interval) { - $interval = intval($interval); - return "dateadd(second, $interval, getdate())"; - } - return "getdate()"; } /** * Return SQL statement to convert a field value into a unix timestamp * + * This method is deprecated and should not be used anymore due to limitations + * of timestamp functions in Mysql (year 2038 problem) + * * @param string $field Field name * * @return string SQL statement to use in query diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php index 6fa5ad768..7f5ad2b36 100644 --- a/program/lib/Roundcube/rcube_db_mysql.php +++ b/program/lib/Roundcube/rcube_db_mysql.php @@ -30,13 +30,9 @@ class rcube_db_mysql extends rcube_db public $db_provider = 'mysql'; /** - * Object constructor - * - * @param string $db_dsnw DSN for read/write operations - * @param string $db_dsnr Optional DSN for read only operations - * @param bool $pconn Enables persistent connections + * Driver initialization/configuration */ - public function __construct($db_dsnw, $db_dsnr = '', $pconn = false) + protected function init() { if (version_compare(PHP_VERSION, '5.3.0', '<')) { rcube::raise_error(array('code' => 600, 'type' => 'db', @@ -45,25 +41,12 @@ class rcube_db_mysql extends rcube_db true, true); } - parent::__construct($db_dsnw, $db_dsnr, $pconn); - // SQL identifiers quoting $this->options['identifier_start'] = '`'; $this->options['identifier_end'] = '`'; } /** - * Driver-specific configuration of database connection - * - * @param array $dsn DSN for DB connections - * @param PDO $dbh Connection handler - */ - protected function conn_configure($dsn, $dbh) - { - $this->query("SET NAMES 'utf8'"); - } - - /** * Abstract SQL statement for value concatenation * * @return string SQL statement to be used in query @@ -151,7 +134,7 @@ class rcube_db_mysql extends rcube_db $result[PDO::MYSQL_ATTR_FOUND_ROWS] = true; // Enable AUTOCOMMIT mode (#1488902) - $result[PDO::ATTR_AUTOCOMMIT] = true; + $dsn_options[PDO::ATTR_AUTOCOMMIT] = true; return $result; } diff --git a/program/lib/Roundcube/rcube_db_pgsql.php b/program/lib/Roundcube/rcube_db_pgsql.php index d72c9d6b3..a06a37c10 100644 --- a/program/lib/Roundcube/rcube_db_pgsql.php +++ b/program/lib/Roundcube/rcube_db_pgsql.php @@ -29,17 +29,6 @@ class rcube_db_pgsql extends rcube_db public $db_provider = 'postgres'; /** - * Driver-specific configuration of database connection - * - * @param array $dsn DSN for DB connections - * @param PDO $dbh Connection handler - */ - protected function conn_configure($dsn, $dbh) - { - $this->query("SET NAMES 'utf8'"); - } - - /** * Get last inserted record ID * * @param string $table Table name (to find the incremented sequence) @@ -64,20 +53,19 @@ class rcube_db_pgsql extends rcube_db /** * Return correct name for a specific database sequence * - * @param string $table Table name + * @param string $sequence Secuence name * * @return string Translated sequence name */ - protected function sequence_name($table) + protected function sequence_name($sequence) { - // Note: we support only one sequence per table - // Note: The sequence name must be <table_name>_seq - $sequence = $table . '_seq'; - $rcube = rcube::get_instance(); + $rcube = rcube::get_instance(); // return sequence name if configured - if ($prefix = $rcube->config->get('db_prefix')) { - return $prefix . $sequence; + $config_key = 'db_sequence_'.$sequence; + + if ($name = $rcube->config->get($config_key)) { + return $name; } return $sequence; @@ -86,6 +74,9 @@ class rcube_db_pgsql extends rcube_db /** * Return SQL statement to convert a field value into a unix timestamp * + * This method is deprecated and should not be used anymore due to limitations + * of timestamp functions in Mysql (year 2038 problem) + * * @param string $field Field name * * @return string SQL statement to use in query @@ -97,24 +88,6 @@ class rcube_db_pgsql extends rcube_db } /** - * Return SQL function for current time and date - * - * @param int $interval Optional interval (in seconds) to add/subtract - * - * @return string SQL function to use in query - */ - public function now($interval = 0) - { - if ($interval) { - $add = ' ' . ($interval > 0 ? '+' : '-') . " interval '"; - $add .= $interval > 0 ? intval($interval) : intval($interval) * -1; - $add .= " seconds'"; - } - - return "now()" . $add; - } - - /** * Return SQL statement for case insensitive LIKE * * @param string $column Field name diff --git a/program/lib/Roundcube/rcube_db_sqlite.php b/program/lib/Roundcube/rcube_db_sqlite.php index b66c56097..145b8a371 100644 --- a/program/lib/Roundcube/rcube_db_sqlite.php +++ b/program/lib/Roundcube/rcube_db_sqlite.php @@ -29,6 +29,13 @@ class rcube_db_sqlite extends rcube_db public $db_provider = 'sqlite'; /** + * Database character set + */ + protected function set_charset($charset) + { + } + + /** * Prepare connection */ protected function conn_prepare($dsn) @@ -49,6 +56,10 @@ class rcube_db_sqlite extends rcube_db */ protected function conn_configure($dsn, $dbh) { + // we emulate via callback some missing functions + $dbh->sqliteCreateFunction('unix_timestamp', array('rcube_db_sqlite', 'sqlite_unix_timestamp'), 1); + $dbh->sqliteCreateFunction('now', array('rcube_db_sqlite', 'sqlite_now'), 0); + // Initialize database structure in file is empty if (!empty($dsn['database']) && !filesize($dsn['database'])) { $data = file_get_contents(RCUBE_INSTALL_PATH . 'SQL/sqlite.initial.sql'); @@ -72,32 +83,30 @@ class rcube_db_sqlite extends rcube_db } /** - * Return SQL statement to convert a field value into a unix timestamp - * - * @param string $field Field name - * - * @return string SQL statement to use in query - * @deprecated + * Callback for sqlite: unix_timestamp() */ - public function unixtimestamp($field) + public static function sqlite_unix_timestamp($timestamp = '') { - return "strftime('%s', $field)"; + $timestamp = trim($timestamp); + if (!$timestamp) { + $ret = time(); + } + else if (!preg_match('/^[0-9]+$/s', $timestamp)) { + $ret = strtotime($timestamp); + } + else { + $ret = $timestamp; + } + + return $ret; } /** - * Return SQL function for current time and date - * - * @param int $interval Optional interval (in seconds) to add/subtract - * - * @return string SQL function to use in query + * Callback for sqlite: now() */ - public function now($interval = 0) + public static function sqlite_now() { - if ($interval) { - $add = ($interval > 0 ? '+' : '') . intval($interval) . ' seconds'; - } - - return "datetime('now'" . ($add ? ",'$add'" : "") . ")"; + return date("Y-m-d H:i:s"); } /** diff --git a/program/lib/Roundcube/rcube_db_sqlsrv.php b/program/lib/Roundcube/rcube_db_sqlsrv.php index 45c41cdaf..e5dfb1154 100644 --- a/program/lib/Roundcube/rcube_db_sqlsrv.php +++ b/program/lib/Roundcube/rcube_db_sqlsrv.php @@ -29,46 +29,29 @@ class rcube_db_sqlsrv extends rcube_db public $db_provider = 'mssql'; /** - * Object constructor - * - * @param string $db_dsnw DSN for read/write operations - * @param string $db_dsnr Optional DSN for read only operations - * @param bool $pconn Enables persistent connections + * Driver initialization */ - public function __construct($db_dsnw, $db_dsnr = '', $pconn = false) + protected function init() { - parent::__construct($db_dsnw, $db_dsnr, $pconn); - $this->options['identifier_start'] = '['; $this->options['identifier_end'] = ']'; } /** - * Driver-specific configuration of database connection - * - * @param array $dsn DSN for DB connections - * @param PDO $dbh Connection handler + * Database character set setting */ - protected function conn_configure($dsn, $dbh) + protected function set_charset($charset) { - // Set date format in case of non-default language (#1488918) - $this->query("SET DATEFORMAT ymd"); + // UTF-8 is default } /** * Return SQL function for current time and date * - * @param int $interval Optional interval (in seconds) to add/subtract - * * @return string SQL function to use in query */ - public function now($interval = 0) + public function now() { - if ($interval) { - $interval = intval($interval); - return "dateadd(second, $interval, getdate())"; - } - return "getdate()"; } diff --git a/program/lib/Roundcube/rcube_enriched.php b/program/lib/Roundcube/rcube_enriched.php index 12deb33ce..8c628c912 100644 --- a/program/lib/Roundcube/rcube_enriched.php +++ b/program/lib/Roundcube/rcube_enriched.php @@ -118,7 +118,7 @@ class rcube_enriched $quoted = ''; $lines = explode('<br>', $a[2]); - foreach ($lines as $line) + foreach ($lines as $n => $line) $quoted .= '>'.$line.'<br>'; $body = $a[1].'<span class="quotes">'.$quoted.'</span>'.$a[3]; diff --git a/program/lib/Roundcube/rcube_image.php b/program/lib/Roundcube/rcube_image.php index 4e4caae93..ffcfd4b1d 100644 --- a/program/lib/Roundcube/rcube_image.php +++ b/program/lib/Roundcube/rcube_image.php @@ -93,10 +93,6 @@ class rcube_image $convert = $rcube->config->get('im_convert_path', false); $props = $this->props(); - if (empty($props)) { - return false; - } - if (!$filename) { $filename = $this->image_file; } @@ -105,6 +101,7 @@ class rcube_image if ($convert) { $p['out'] = $filename; $p['in'] = $this->image_file; + $p['size'] = $size.'x'.$size; $type = $props['type']; if (!$type && ($data = $this->identify())) { @@ -119,37 +116,11 @@ class rcube_image $type = 'jpg'; } - // If only one dimension is greater than the limit convert doesn't - // work as expected, we need to calculate new dimensions - $scale = $size / max($props['width'], $props['height']); + $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); + $p['-opts'] = array('-resize' => $p['size'].'>'); - // if file is smaller than the limit, we do nothing - // but copy original file to destination file - if ($scale >= 1 && $p['intype'] == $type) { - $result = ($this->image_file == $filename || copy($this->image_file, $filename)) ? '' : false; - } - else { - if ($scale >= 1) { - $width = $props['width']; - $height = $props['height']; - } - else { - $width = intval($props['width'] * $scale); - $height = intval($props['height'] * $scale); - } - - $valid_types = "bmp,eps,gif,jp2,jpg,png,svg,tif"; - - $p += array( - 'type' => $type, - 'quality' => 75, - 'size' => $width . 'x' . $height, - ); - - if (in_array($type, explode(',', $valid_types))) { // Valid type? - $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace sRGB -strip' - . ' -quality {quality} -resize {size} {intype}:{in} {type}:{out}', $p); - } + if (in_array($type, explode(',', $p['types']))) { // Valid type? + $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace sRGB -quality {quality} {-opts} {intype}:{in} {type}:{out}', $p); } if ($result === '') { @@ -177,43 +148,39 @@ class rcube_image return false; } - if ($image === false) { - return false; - } - $scale = $size / max($props['width'], $props['height']); // Imagemagick resize is implemented in shrinking mode (see -resize argument above) // we do the same here, if an image is smaller than specified size // we do nothing but copy original file to destination file - if ($scale >= 1) { - $result = $this->image_file == $filename || copy($this->image_file, $filename); + if ($scale > 1) { + return $this->image_file == $filename || copy($this->image_file, $filename) ? $type : false; } - else { - $width = intval($props['width'] * $scale); - $height = intval($props['height'] * $scale); - $new_image = imagecreatetruecolor($width, $height); - - // Fix transparency of gif/png image - if ($props['gd_type'] != IMAGETYPE_JPEG) { - imagealphablending($new_image, false); - imagesavealpha($new_image, true); - $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127); - imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent); - } - - imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']); - $image = $new_image; - - if ($props['gd_type'] == IMAGETYPE_JPEG) { - $result = imagejpeg($image, $filename, 75); - } - elseif($props['gd_type'] == IMAGETYPE_GIF) { - $result = imagegif($image, $filename); - } - elseif($props['gd_type'] == IMAGETYPE_PNG) { - $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); - } + + $width = $props['width'] * $scale; + $height = $props['height'] * $scale; + + $new_image = imagecreatetruecolor($width, $height); + + // Fix transparency of gif/png image + if ($props['gd_type'] != IMAGETYPE_JPEG) { + imagealphablending($new_image, false); + imagesavealpha($new_image, true); + $transparent = imagecolorallocatealpha($new_image, 255, 255, 255, 127); + imagefilledrectangle($new_image, 0, 0, $width, $height, $transparent); + } + + imagecopyresampled($new_image, $image, 0, 0, 0, 0, $width, $height, $props['width'], $props['height']); + $image = $new_image; + + if ($props['gd_type'] == IMAGETYPE_JPEG) { + $result = imagejpeg($image, $filename, 75); + } + elseif($props['gd_type'] == IMAGETYPE_GIF) { + $result = imagegif($image, $filename); + } + elseif($props['gd_type'] == IMAGETYPE_PNG) { + $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); } if ($result) { @@ -255,7 +222,7 @@ class rcube_image $p['out'] = $filename; $p['type'] = self::$extensions[$type]; - $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p); + $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -quality 75 {in} {type}:{out}', $p); if ($result === '') { @chmod($filename, 0600); diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index aa074233f..ca5e35f2c 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -308,7 +308,14 @@ class rcube_imap extends rcube_storage */ public function set_folder($folder) { + if ($this->folder == $folder) { + return; + } + $this->folder = $folder; + + // clear messagecount cache for this folder + $this->clear_messagecount($folder); } @@ -606,7 +613,7 @@ class rcube_imap extends rcube_storage } if ($mode == 'THREADS') { - $res = $this->threads($folder); + $res = $this->fetch_threads($folder, $force); $count = $res->count(); if ($status) { @@ -636,11 +643,11 @@ class rcube_imap extends rcube_storage $keys[] = 'ALL'; } if ($status) { - $keys[] = 'MAX'; + $keys[] = 'MAX'; } } - // @TODO: if $mode == 'ALL' we could try to use cache index here + // @TODO: if $force==false && $mode == 'ALL' we could try to use cache index here // get message count using (E)SEARCH // not very performant but more precise (using UNDELETED) @@ -771,7 +778,7 @@ class rcube_imap extends rcube_storage $threads = $mcache->get_thread($folder); } else { - $threads = $this->threads($folder); + $threads = $this->fetch_threads($folder); } return $this->fetch_thread_headers($folder, $threads, $page, $slice); @@ -780,47 +787,32 @@ class rcube_imap extends rcube_storage /** * Method for fetching threads data * - * @param string $folder Folder name + * @param string $folder Folder name + * @param bool $force Use IMAP server, no cache * * @return rcube_imap_thread Thread data object */ - function threads($folder) + function fetch_threads($folder, $force = false) { - if ($mcache = $this->get_mcache_engine()) { + if (!$force && ($mcache = $this->get_mcache_engine())) { // don't store in self's internal cache, cache has it's own internal cache return $mcache->get_thread($folder); } - if (!empty($this->icache['threads'])) { - if ($this->icache['threads']->get_parameters('MAILBOX') == $folder) { - return $this->icache['threads']; + if (empty($this->icache['threads'])) { + if (!$this->check_connection()) { + return new rcube_result_thread(); } - } - // get all threads - $result = $this->threads_direct($folder); + // get all threads + $result = $this->conn->thread($folder, $this->threading, + $this->options['skip_deleted'] ? 'UNDELETED' : '', true); - // add to internal (fast) cache - return $this->icache['threads'] = $result; - } - - - /** - * Method for direct fetching of threads data - * - * @param string $folder Folder name - * - * @return rcube_imap_thread Thread data object - */ - function threads_direct($folder) - { - if (!$this->check_connection()) { - return new rcube_result_thread(); + // add to internal (fast) cache + $this->icache['threads'] = $result; } - // get all threads - return $this->conn->thread($folder, $this->threading, - $this->options['skip_deleted'] ? 'UNDELETED' : '', true); + return $this->icache['threads']; } @@ -1091,17 +1083,16 @@ class rcube_imap extends rcube_storage /** - * Returns current status of a folder (compared to the last time use) + * Returns current status of folder * * We compare the maximum UID to determine the number of * new messages because the RECENT flag is not reliable. * * @param string $folder Folder name - * @param array $diff Difference data * - * @return int Folder status + * @return int Folder status */ - public function folder_status($folder = null, &$diff = array()) + public function folder_status($folder = null) { if (!strlen($folder)) { $folder = $this->folder; @@ -1122,9 +1113,6 @@ class rcube_imap extends rcube_storage // got new messages if ($new['maxuid'] > $old['maxuid']) { $result += 1; - // get new message UIDs range, that can be used for example - // to get the data of these messages - $diff['new'] = ($old['maxuid'] + 1 < $new['maxuid'] ? ($old['maxuid']+1).':' : '') . $new['maxuid']; } // some messages has been deleted if ($new['cnt'] < $old['cnt']) { @@ -1175,15 +1163,12 @@ class rcube_imap extends rcube_storage * @param string $folder Folder to get index from * @param string $sort_field Sort column * @param string $sort_order Sort order [ASC, DESC] - * @param bool $no_threads Get not threaded index - * @param bool $no_search Get index not limited to search result (optionally) * * @return rcube_result_index|rcube_result_thread List of messages (UIDs) */ - public function index($folder = '', $sort_field = NULL, $sort_order = NULL, - $no_threads = false, $no_search = false - ) { - if (!$no_threads && $this->threading) { + public function index($folder = '', $sort_field = NULL, $sort_order = NULL) + { + if ($this->threading) { return $this->thread_index($folder, $sort_field, $sort_order); } @@ -1195,50 +1180,43 @@ class rcube_imap extends rcube_storage // we have a saved search result, get index from there if ($this->search_string) { - if ($this->search_set->is_empty()) { - return new rcube_result_index($folder, '* SORT'); + if ($this->search_threads) { + $this->search($folder, $this->search_string, $this->search_charset, $this->sort_field); } - // search result is an index with the same sorting? - if (($this->search_set instanceof rcube_result_index) - && ((!$this->sort_field && !$this->search_sorted) || - ($this->search_sorted && $this->search_sort_field == $this->sort_field)) - ) { + // use message index sort as default sorting + if (!$this->sort_field || $this->search_sorted) { + if ($this->sort_field && $this->search_sort_field != $this->sort_field) { + $this->search($folder, $this->search_string, $this->search_charset, $this->sort_field); + } $index = $this->search_set; } - // $no_search is enabled when we are not interested in - // fetching index for search result, e.g. to sort - // threaded search result we can use full mailbox index. - // This makes possible to use index from cache - else if (!$no_search) { - if (!$this->sort_field) { - // No sorting needed, just build index from the search result - // @TODO: do we need to sort by UID here? - $search = $this->search_set->get_compressed(); - $index = new rcube_result_index($folder, '* ESEARCH ALL ' . $search); - } - else { - $index = $this->index_direct($folder, $this->search_charset, - $this->sort_field, $this->search_set); - } + else if (!$this->check_connection()) { + return new rcube_result_index(); + } + else { + $index = $this->conn->index($folder, $this->search_set->get(), + $this->sort_field, $this->options['skip_deleted'], true, true); } - if (isset($index)) { - if ($this->sort_order != $index->get_parameters('ORDER')) { - $index->revert(); - } - - return $index; + if ($this->sort_order != $index->get_parameters('ORDER')) { + $index->revert(); } + + return $index; } // check local cache if ($mcache = $this->get_mcache_engine()) { - return $mcache->get_index($folder, $this->sort_field, $this->sort_order); + $index = $mcache->get_index($folder, $this->sort_field, $this->sort_order); } - // fetch from IMAP server - return $this->index_direct($folder, $this->sort_field, $this->sort_order); + else { + $index = $this->index_direct( + $folder, $this->sort_field, $this->sort_order); + } + + return $index; } @@ -1246,24 +1224,22 @@ class rcube_imap extends rcube_storage * Return sorted list of message UIDs ignoring current search settings. * Doesn't uses cache by default. * - * @param string $folder Folder to get index from - * @param string $sort_field Sort column - * @param string $sort_order Sort order [ASC, DESC] - * @param rcube_result_* $search Optional messages set to limit the result + * @param string $folder Folder to get index from + * @param string $sort_field Sort column + * @param string $sort_order Sort order [ASC, DESC] + * @param bool $skip_cache Disables cache usage * * @return rcube_result_index Sorted list of message UIDs */ - public function index_direct($folder, $sort_field = null, $sort_order = null, $search = null) + public function index_direct($folder, $sort_field = null, $sort_order = null, $skip_cache = true) { - if (!empty($search)) { - $search = $this->search_set->get_compressed(); + if (!$skip_cache && ($mcache = $this->get_mcache_engine())) { + $index = $mcache->get_index($folder, $sort_field, $sort_order); } - // use message index sort as default sorting - if (!$sort_field) { + else if (!$sort_field) { // use search result from count() if possible - if (empty($search) && $this->options['skip_deleted'] - && !empty($this->icache['undeleted_idx']) + if ($this->options['skip_deleted'] && !empty($this->icache['undeleted_idx']) && $this->icache['undeleted_idx']->get_parameters('ALL') !== null && $this->icache['undeleted_idx']->get_parameters('MAILBOX') == $folder ) { @@ -1273,12 +1249,8 @@ class rcube_imap extends rcube_storage return new rcube_result_index(); } else { - $query = $this->options['skip_deleted'] ? 'UNDELETED' : ''; - if ($search) { - $query = trim($query . ' UID ' . $search); - } - - $index = $this->conn->search($folder, $query, true); + $index = $this->conn->search($folder, + 'ALL' .($this->options['skip_deleted'] ? ' UNDELETED' : ''), true); } } else if (!$this->check_connection()) { @@ -1287,18 +1259,13 @@ class rcube_imap extends rcube_storage // fetch complete message index else { if ($this->get_capability('SORT')) { - $query = $this->options['skip_deleted'] ? 'UNDELETED' : ''; - if ($search) { - $query = trim($query . ' UID ' . $search); - } - - $index = $this->conn->sort($folder, $sort_field, $query, true); + $index = $this->conn->sort($folder, $sort_field, + $this->options['skip_deleted'] ? 'UNDELETED' : '', true); } if (empty($index) || $index->is_error()) { - $index = $this->conn->index($folder, $search ? $search : "1:*", - $sort_field, $this->options['skip_deleted'], - $search ? true : false, true); + $index = $this->conn->index($folder, "1:*", $sort_field, + $this->options['skip_deleted'], false, true); } } @@ -1331,7 +1298,7 @@ class rcube_imap extends rcube_storage } else { // get all threads (default sort order) - $threads = $this->threads($folder); + $threads = $this->fetch_threads($folder); } $this->set_sort_order($sort_field, $sort_order); @@ -1342,10 +1309,9 @@ class rcube_imap extends rcube_storage /** - * Sort threaded result, using THREAD=REFS method if available. - * If not, use any method and re-sort the result in THREAD=REFS way. + * Sort threaded result, using THREAD=REFS method * - * @param rcube_result_thread $threads Threads result set + * @param rcube_result_thread $threads Threads result set */ protected function sort_threads($threads) { @@ -1359,7 +1325,7 @@ class rcube_imap extends rcube_storage if ($this->threading != 'REFS' || ($this->sort_field && $this->sort_field != 'date')) { $sortby = $this->sort_field ? $this->sort_field : 'date'; - $index = $this->index($this->folder, $sortby, $this->sort_order, true, true); + $index = $this->index_direct($this->folder, $sortby, $this->sort_order, false); if (!$index->is_empty()) { $threads->sort($index); @@ -1439,6 +1405,8 @@ class rcube_imap extends rcube_storage */ protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL) { + $orig_criteria = $criteria; + if (!$this->check_connection()) { if ($this->threading) { return new rcube_result_thread(); @@ -2079,18 +2047,17 @@ class rcube_imap extends rcube_storage /** * Fetch message body of a specific message from the server * - * @param int Message UID - * @param string Part number - * @param rcube_message_part Part object created by get_structure() - * @param mixed True to print part, resource to write part contents in - * @param resource File pointer to save the message part - * @param boolean Disables charset conversion - * @param int Only read this number of bytes - * @param boolean Enables formatting of text/* parts bodies + * @param int $uid Message UID + * @param string $part Part number + * @param rcube_message_part $o_part Part object created by get_structure() + * @param mixed $print True to print part, ressource to write part contents in + * @param resource $fp File pointer to save the message part + * @param boolean $skip_charset_conv Disables charset conversion + * @param int $max_bytes Only read this number of bytes * * @return string Message/part body if not printed */ - public function get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false, $max_bytes=0, $formatted=true) + public function get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false, $max_bytes=0) { if (!$this->check_connection()) { return null; @@ -2109,9 +2076,8 @@ class rcube_imap extends rcube_storage } if ($o_part && $o_part->size) { - $formatted = $formatted && $o_part->ctype_primary == 'text'; $body = $this->conn->handlePartBody($this->folder, $uid, true, - $part ? $part : 'TEXT', $o_part->encoding, $print, $fp, $formatted, $max_bytes); + $part ? $part : 'TEXT', $o_part->encoding, $print, $fp, $o_part->ctype_primary == 'text', $max_bytes); } if ($fp || $print) { @@ -2256,14 +2222,13 @@ class rcube_imap extends rcube_storage /** * Append a mail message (source) to a specific folder * - * @param string $folder Target folder - * @param string|array $message The message source string or filename - * or array (of strings and file pointers) - * @param string $headers Headers string if $message contains only the body - * @param boolean $is_file True if $message is a filename - * @param array $flags Message flags - * @param mixed $date Message internal date - * @param bool $binary Enables BINARY append + * @param string $folder Target folder + * @param string $message The message source string or filename + * @param string $headers Headers string if $message contains only the body + * @param boolean $is_file True if $message is a filename + * @param array $flags Message flags + * @param mixed $date Message internal date + * @param bool $binary Enables BINARY append * * @return int|bool Appended message UID or True on success, False on error */ @@ -2354,7 +2319,10 @@ class rcube_imap extends rcube_storage // move messages $moved = $this->conn->move($uids, $from_mbox, $to_mbox); + // send expunge command in order to have the moved message + // really deleted from the source folder if ($moved) { + $this->expunge_message($uids, $from_mbox, false); $this->clear_messagecount($from_mbox); $this->clear_messagecount($to_mbox); } @@ -2656,6 +2624,7 @@ class rcube_imap extends rcube_storage if ($list_extended) { // unsubscribe non-existent folders, remove from the list + // we can do this only when LIST response is available if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) { foreach ($a_folders as $idx => $folder) { if (($opts = $this->conn->data['LIST'][$folder]) @@ -2668,14 +2637,19 @@ class rcube_imap extends rcube_storage } } else { - // unsubscribe non-existent folders, remove them from the list - if (is_array($a_folders) && !empty($a_folders) && $name == '*') { - $existing = $this->list_folders($root, $name); - $nonexisting = array_diff($a_folders, $existing); - $a_folders = array_diff($a_folders, $nonexisting); - - foreach ($nonexisting as $folder) { - $this->conn->unsubscribe($folder); + // unsubscribe non-existent folders, remove them from the list, + // we can do this only when LIST response is available + if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) { + foreach ($a_folders as $idx => $folder) { + if (!isset($this->conn->data['LIST'][$folder]) + || in_array('\\Noselect', $this->conn->data['LIST'][$folder]) + ) { + // Some servers returns \Noselect for existing folders + if (!$this->folder_exists($folder)) { + $this->conn->unsubscribe($folder); + unset($a_folders[$idx]); + } + } } } } @@ -2794,6 +2768,7 @@ class rcube_imap extends rcube_storage */ private function list_folders_update(&$result, $type = null) { + $delim = $this->get_hierarchy_delimiter(); $namespace = $this->get_namespace(); $search = array(); @@ -3704,7 +3679,7 @@ class rcube_imap extends rcube_storage { if ($this->caching && !$this->cache) { $rcube = rcube::get_instance(); - $ttl = $rcube->config->get('imap_cache_ttl', '10d'); + $ttl = $rcube->config->get('message_cache_lifetime', '10d'); $this->cache = $rcube->get_cache('IMAP', $this->caching, $ttl); } @@ -3752,6 +3727,21 @@ class rcube_imap extends rcube_storage } } + /** + * Delete outdated cache entries + */ + public function expunge_cache() + { + if ($this->mcache) { + $ttl = rcube::get_instance()->config->get('message_cache_lifetime', '10d'); + $this->mcache->expunge($ttl); + } + + if ($this->cache) { + $this->cache->expunge(); + } + } + /* -------------------------------- * message caching methods @@ -3785,10 +3775,8 @@ class rcube_imap extends rcube_storage if ($this->messages_caching && !$this->mcache) { $rcube = rcube::get_instance(); if (($dbh = $rcube->get_dbh()) && ($userid = $rcube->get_user_id())) { - $ttl = $rcube->config->get('messages_cache_ttl', '10d'); - $threshold = $rcube->config->get('messages_cache_threshold', 50); $this->mcache = new rcube_imap_cache( - $dbh, $this, $userid, $this->options['skip_deleted'], $ttl, $threshold); + $dbh, $this, $userid, $this->options['skip_deleted']); } } @@ -3810,15 +3798,6 @@ class rcube_imap extends rcube_storage } - /** - * Delete outdated cache entries - */ - function cache_gc() - { - rcube_imap_cache::gc(); - } - - /* -------------------------------- * protected methods * --------------------------------*/ @@ -3852,7 +3831,7 @@ class rcube_imap extends rcube_storage $delimiter = $this->get_hierarchy_delimiter(); // find default folders and skip folders starting with '.' - foreach ($a_folders as $folder) { + foreach ($a_folders as $i => $folder) { if ($folder[0] == '.') { continue; } @@ -4112,9 +4091,9 @@ class rcube_imap extends rcube_storage return $this->index($folder, $sort_field, $sort_order); } - public function message_index_direct($folder, $sort_field = null, $sort_order = null) + public function message_index_direct($folder, $sort_field = null, $sort_order = null, $skip_cache = true) { - return $this->index_direct($folder, $sort_field, $sort_order); + return $this->index_direct($folder, $sort_field, $sort_order, $skip_cache); } public function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php index d72bfe0ab..5170e9e21 100644 --- a/program/lib/Roundcube/rcube_imap_cache.php +++ b/program/lib/Roundcube/rcube_imap_cache.php @@ -49,20 +49,6 @@ class rcube_imap_cache private $userid; /** - * Expiration time in seconds - * - * @var int - */ - private $ttl; - - /** - * Maximum cached message size - * - * @var int - */ - private $threshold; - - /** * Internal (in-memory) cache * * @var array @@ -97,26 +83,13 @@ class rcube_imap_cache /** * Object constructor. - * - * @param rcube_db $db DB handler - * @param rcube_imap $imap IMAP handler - * @param int $userid User identifier - * @param bool $skip_deleted skip_deleted flag - * @param string $ttl Expiration time of memcache/apc items - * @param int $threshold Maximum cached message size */ - function __construct($db, $imap, $userid, $skip_deleted, $ttl=0, $threshold=0) + function __construct($db, $imap, $userid, $skip_deleted) { - // convert ttl string to seconds - $ttl = get_offset_sec($ttl); - if ($ttl > 2592000) $ttl = 2592000; - $this->db = $db; $this->imap = $imap; $this->userid = $userid; $this->skip_deleted = $skip_deleted; - $this->ttl = $ttl; - $this->threshold = $threshold; } @@ -242,7 +215,9 @@ class rcube_imap_cache * Return messages thread. * If threaded index doesn't exist or is invalid, will be updated. * - * @param string $mailbox Folder name + * @param string $mailbox Folder name + * @param string $sort_field Sorting column + * @param string $sort_order Sorting order (ASC|DESC) * * @return array Messages threaded index */ @@ -281,11 +256,19 @@ class rcube_imap_cache if ($index === null) { // Get mailbox data (UIDVALIDITY, counters, etc.) for status check $mbox_data = $this->imap->folder_data($mailbox); - // Get THREADS result - $index['object'] = $this->get_thread_data($mailbox, $mbox_data); + + if ($mbox_data['EXISTS']) { + // get all threads (default sort order) + $threads = $this->imap->fetch_threads($mailbox, true); + } + else { + $threads = new rcube_result_thread($mailbox, '* THREAD'); + } + + $index['object'] = $threads; // insert/update - $this->add_thread_row($mailbox, $index['object'], $mbox_data, $exists); + $this->add_thread_row($mailbox, $threads, $mbox_data, $exists); } $this->icache[$mailbox]['thread'] = $index; @@ -443,40 +426,23 @@ class rcube_imap_cache if (!$force) { $res = $this->db->query( "UPDATE ".$this->db->table_name('cache_messages') - ." SET flags = ?, data = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') + ." SET flags = ?, data = ?, changed = ".$this->db->now() ." WHERE user_id = ?" ." AND mailbox = ?" ." AND uid = ?", $flags, $msg, $this->userid, $mailbox, (int) $message->uid); - if ($this->db->affected_rows($res)) { + if ($this->db->affected_rows()) { return; } } - $this->db->set_option('ignore_key_errors', true); - // insert new record - $res = $this->db->query( + $this->db->query( "INSERT INTO ".$this->db->table_name('cache_messages') - ." (user_id, mailbox, uid, flags, expires, data)" - ." VALUES (?, ?, ?, ?, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?)", + ." (user_id, mailbox, uid, flags, changed, data)" + ." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)", $this->userid, $mailbox, (int) $message->uid, $flags, $msg); - - // race-condition, insert failed so try update (#1489146) - // thanks to ignore_key_errors "duplicate row" errors will be ignored - if ($force && !$res && !$this->db->is_error($res)) { - $this->db->query( - "UPDATE ".$this->db->table_name('cache_messages') - ." SET expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') - .", flags = ?, data = ?" - ." WHERE user_id = ?" - ." AND mailbox = ?" - ." AND uid = ?", - $flags, $msg, $this->userid, $mailbox, (int) $message->uid); - } - - $this->db->set_option('ignore_key_errors', false); } @@ -517,7 +483,7 @@ class rcube_imap_cache $this->db->query( "UPDATE ".$this->db->table_name('cache_messages') - ." SET expires = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') + ." SET changed = ".$this->db->now() .", flags = flags ".($enabled ? "+ $idx" : "- $idx") ." WHERE user_id = ?" ." AND mailbox = ?" @@ -640,21 +606,23 @@ class rcube_imap_cache /** - * Delete expired cache entries + * Delete cache entries older than TTL + * + * @param string $ttl Lifetime of message cache entries */ - static function gc() + function expunge($ttl) { - $rcube = rcube::get_instance(); - $db = $rcube->get_dbh(); + // get expiration timestamp + $ts = get_offset_time($ttl, -1); - $db->query("DELETE FROM ".$db->table_name('cache_messages') - ." WHERE expires < " . $db->now()); + $this->db->query("DELETE FROM ".$this->db->table_name('cache_messages') + ." WHERE changed < " . $this->db->fromunixtime($ts)); - $db->query("DELETE FROM ".$db->table_name('cache_index') - ." WHERE expires < " . $db->now()); + $this->db->query("DELETE FROM ".$this->db->table_name('cache_index') + ." WHERE changed < " . $this->db->fromunixtime($ts)); - $db->query("DELETE FROM ".$db->table_name('cache_thread') - ." WHERE expires < " . $db->now()); + $this->db->query("DELETE FROM ".$this->db->table_name('cache_thread') + ." WHERE changed < " . $this->db->fromunixtime($ts)); } @@ -746,38 +714,20 @@ class rcube_imap_cache $data = implode('@', $data); if ($exists) { - $res = $this->db->query( + $sql_result = $this->db->query( "UPDATE ".$this->db->table_name('cache_index') - ." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') + ." SET data = ?, valid = 1, changed = ".$this->db->now() ." WHERE user_id = ?" ." AND mailbox = ?", $data, $this->userid, $mailbox); - - if ($this->db->affected_rows($res)) { - return; - } } - - $this->db->set_option('ignore_key_errors', true); - - $res = $this->db->query( - "INSERT INTO ".$this->db->table_name('cache_index') - ." (user_id, mailbox, valid, expires, data)" - ." VALUES (?, ?, 1, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .", ?)", - $this->userid, $mailbox, $data); - - // race-condition, insert failed so try update (#1489146) - // thanks to ignore_key_errors "duplicate row" errors will be ignored - if (!$exists && !$res && !$this->db->is_error($res)) { - $res = $this->db->query( - "UPDATE ".$this->db->table_name('cache_index') - ." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') - ." WHERE user_id = ?" - ." AND mailbox = ?", - $data, $this->userid, $mailbox); + else { + $sql_result = $this->db->query( + "INSERT INTO ".$this->db->table_name('cache_index') + ." (user_id, mailbox, data, valid, changed)" + ." VALUES (?, ?, ?, 1, ".$this->db->now().")", + $this->userid, $mailbox, $data); } - - $this->db->set_option('ignore_key_errors', false); } @@ -794,41 +744,21 @@ class rcube_imap_cache ); $data = implode('@', $data); - $expires = ($this->ttl ? $this->db->now($this->ttl) : 'NULL'); - if ($exists) { - $res = $this->db->query( + $sql_result = $this->db->query( "UPDATE ".$this->db->table_name('cache_thread') - ." SET data = ?, expires = $expires" + ." SET data = ?, changed = ".$this->db->now() ." WHERE user_id = ?" ." AND mailbox = ?", $data, $this->userid, $mailbox); - - if ($this->db->affected_rows($res)) { - return; - } } - - $this->db->set_option('ignore_key_errors', true); - - $res = $this->db->query( - "INSERT INTO ".$this->db->table_name('cache_thread') - ." (user_id, mailbox, expires, data)" - ." VALUES (?, ?, $expires, ?)", - $this->userid, $mailbox, $data); - - // race-condition, insert failed so try update (#1489146) - // thanks to ignore_key_errors "duplicate row" errors will be ignored - if (!$exists && !$res && !$this->db->is_error($res)) { - $this->db->query( - "UPDATE ".$this->db->table_name('cache_thread') - ." SET expires = $expires, data = ?" - ." WHERE user_id = ?" - ." AND mailbox = ?", - $data, $this->userid, $mailbox); + else { + $sql_result = $this->db->query( + "INSERT INTO ".$this->db->table_name('cache_thread') + ." (user_id, mailbox, data, changed)" + ." VALUES (?, ?, ?, ".$this->db->now().")", + $this->userid, $mailbox, $data); } - - $this->db->set_option('ignore_key_errors', false); } @@ -1055,7 +985,7 @@ class rcube_imap_cache $uids, true, array('FLAGS'), $index['modseq'], $qresync); if (!empty($result)) { - foreach ($result as $msg) { + foreach ($result as $id => $msg) { $uid = $msg->uid; // Remove deleted message if ($this->skip_deleted && !empty($msg->flags['DELETED'])) { @@ -1076,7 +1006,7 @@ class rcube_imap_cache $this->db->query( "UPDATE ".$this->db->table_name('cache_messages') - ." SET flags = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') + ." SET flags = ?, changed = ".$this->db->now() ." WHERE user_id = ?" ." AND mailbox = ?" ." AND uid = ?" @@ -1104,18 +1034,17 @@ class rcube_imap_cache } } + // Invalidate thread index (?) + if (!$index['valid']) { + $this->remove_thread($mailbox); + } + $sort_field = $index['sort_field']; $sort_order = $index['object']->get_parameters('ORDER'); $exists = true; // Validate index if (!$this->validate($mailbox, $index, $exists)) { - // Invalidate (remove) thread index - // if $exists=false it was already removed in validate() - if ($exists) { - $this->remove_thread($mailbox); - } - // Update index $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data); } @@ -1182,16 +1111,11 @@ class rcube_imap_cache * * @param rcube_message_header|rcube_message_part */ - private function message_object_prepare(&$msg, &$size = 0) + private function message_object_prepare(&$msg) { - // Remove body too big - if ($msg->body && ($length = strlen($msg->body))) { - $size += $length; - - if ($size > $this->threshold * 1024) { - $size -= $length; - unset($msg->body); - } + // Remove body too big (>25kB) + if ($msg->body && strlen($msg->body) > 25 * 1024) { + unset($msg->body); } // Fix mimetype which might be broken by some code when message is displayed @@ -1205,13 +1129,13 @@ class rcube_imap_cache if (is_array($msg->structure->parts)) { foreach ($msg->structure->parts as $part) { - $this->message_object_prepare($part, $size); + $this->message_object_prepare($part); } } if (is_array($msg->parts)) { foreach ($msg->parts as $part) { - $this->message_object_prepare($part, $size); + $this->message_object_prepare($part); } } } @@ -1236,25 +1160,6 @@ class rcube_imap_cache return $index; } - - - /** - * Fetches thread data from IMAP server - */ - private function get_thread_data($mailbox, $mbox_data = array()) - { - if (empty($mbox_data)) { - $mbox_data = $this->imap->folder_data($mailbox); - } - - if ($mbox_data['EXISTS']) { - // get all threads (default sort order) - return $this->imap->threads_direct($mailbox); - } - - return new rcube_result_thread($mailbox, '* THREAD'); - } - } // for backward compat. diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index bce4cd4e2..1b28c3bd7 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -72,8 +72,6 @@ class rcube_imap_generic const COMMAND_CAPABILITY = 2; const COMMAND_LASTLINE = 4; - const DEBUG_LINE_LENGTH = 4098; // 4KB + 2B for \r\n - /** * Object constructor */ @@ -789,21 +787,23 @@ class rcube_imap_generic // TLS connection if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { - $res = $this->execute('STARTTLS'); + if (version_compare(PHP_VERSION, '5.1.0', '>=')) { + $res = $this->execute('STARTTLS'); - if ($res[0] != self::ERROR_OK) { - $this->closeConnection(); - return false; - } + if ($res[0] != self::ERROR_OK) { + $this->closeConnection(); + return false; + } - if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { - $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); - $this->closeConnection(); - return false; - } + if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); + $this->closeConnection(); + return false; + } - // Now we're secure, capabilities need to be reread - $this->clearCapability(); + // Now we're secure, capabilities need to be reread + $this->clearCapability(); + } } // Send ID info @@ -902,11 +902,6 @@ class rcube_imap_generic $this->prefs['auth_type'] = 'CHECK'; } - // disabled capabilities - if (!empty($this->prefs['disabled_caps'])) { - $this->prefs['disabled_caps'] = array_map('strtoupper', (array)$this->prefs['disabled_caps']); - } - // additional message flags if (!empty($this->prefs['message_flags'])) { $this->flags = array_merge($this->flags, $this->prefs['message_flags']); @@ -1088,8 +1083,8 @@ class rcube_imap_generic /** * Executes EXPUNGE command * - * @param string $mailbox Mailbox name - * @param string|array $messages Message UIDs to expunge + * @param string $mailbox Mailbox name + * @param string $messages Message UIDs to expunge * * @return boolean True on success, False on error */ @@ -1107,13 +1102,10 @@ class rcube_imap_generic // Clear internal status cache unset($this->data['STATUS:'.$mailbox]); - if (!empty($messages) && $messages != '*' && $this->hasCapability('UIDPLUS')) { - $messages = self::compressMessageSet($messages); - $result = $this->execute('UID EXPUNGE', array($messages), self::COMMAND_NORESPONSE); - } - else { + if ($messages) + $result = $this->execute('UID EXPUNGE', array($messages), self::COMMAND_NORESPONSE); + else $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE); - } if ($result == self::ERROR_OK) { $this->selected = null; // state has changed, need to reselect @@ -1350,8 +1342,9 @@ class rcube_imap_generic $folders[$mailbox] = array(); } - // store folder options - if ($cmd == 'LIST') { + // store LSUB options only if not empty, this way + // we can detect a situation when LIST doesn't return specified folder + if (!empty($opts) || $cmd == 'LIST') { // Add to options array if (empty($this->data['LIST'][$mailbox])) $this->data['LIST'][$mailbox] = $opts; @@ -1583,12 +1576,11 @@ class rcube_imap_generic } // message IDs - if (!empty($add)) { + if (!empty($add)) $add = $this->compressMessageSet($add); - } list($code, $response) = $this->execute($return_uid ? 'UID SORT' : 'SORT', - array("($field)", $encoding, !empty($add) ? $add : 'ALL')); + array("($field)", $encoding, 'ALL' . (!empty($add) ? ' '.$add : ''))); if ($code != self::ERROR_OK) { $response = null; @@ -1675,6 +1667,7 @@ class rcube_imap_generic } if (!empty($criteria)) { + $modseq = stripos($criteria, 'MODSEQ') !== false; $params .= ($params ? ' ' : '') . $criteria; } else { @@ -1813,6 +1806,7 @@ class rcube_imap_generic if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { $flags = explode(' ', strtoupper($matches[1])); if (in_array('\\DELETED', $flags)) { + $deleted[$id] = $id; continue; } } @@ -2004,6 +1998,7 @@ class rcube_imap_generic /** * Moves message(s) from one folder to another. + * Original message(s) will be marked as deleted. * * @param string|array $messages Message UID(s) * @param string $from Mailbox name @@ -2022,41 +2017,15 @@ class rcube_imap_generic return false; } - // use MOVE command (RFC 6851) - if ($this->hasCapability('MOVE')) { - // Clear last COPYUID data - unset($this->data['COPYUID']); + $r = $this->copy($messages, $from, $to); + if ($r) { // Clear internal status cache - unset($this->data['STATUS:'.$to]); unset($this->data['STATUS:'.$from]); - $result = $this->execute('UID MOVE', array( - $this->compressMessageSet($messages), $this->escape($to)), - self::COMMAND_NORESPONSE); - - return ($result == self::ERROR_OK); - } - - // use COPY + STORE +FLAGS.SILENT \Deleted + EXPUNGE - $result = $this->copy($messages, $from, $to); - - if ($result) { - // Clear internal status cache - unset($this->data['STATUS:'.$from]); - - $result = $this->flag($from, $messages, 'DELETED'); - - if ($messages == '*') { - // CLOSE+SELECT should be faster than EXPUNGE - $this->close(); - } - else { - $this->expunge($from, $messages); - } + return $this->flag($from, $messages, 'DELETED'); } - - return $result; + return $r; } /** @@ -2197,7 +2166,7 @@ class rcube_imap_generic // create array with header field:data if (!empty($headers)) { $headers = explode("\n", trim($headers)); - foreach ($headers as $resln) { + foreach ($headers as $hid => $resln) { if (ord($resln[0]) <= 32) { $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln); } else { @@ -2205,7 +2174,7 @@ class rcube_imap_generic } } - foreach ($lines as $str) { + while (list($lines_key, $str) = each($lines)) { list($field, $string) = explode(':', $str, 2); $field = strtolower($field); @@ -2509,7 +2478,7 @@ class rcube_imap_generic } if ($binary) { - // WARNING: Use $formatted argument with care, this may break binary data stream + // WARNING: Use $formatting argument with care, this may break binary data stream $mode = -1; } @@ -2530,7 +2499,6 @@ class rcube_imap_generic // handle one line response if ($line[0] == '(' && substr($line, -1) == ')') { // tokenize content inside brackets - // the content can be e.g.: (UID 9844 BODY[2.4] NIL) $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line)); for ($i=0; $i<count($tokens); $i+=2) { @@ -2645,11 +2613,11 @@ class rcube_imap_generic /** * Handler for IMAP APPEND command * - * @param string $mailbox Mailbox name - * @param string|array $message The message source string or array (of strings and file pointers) - * @param array $flags Message flags - * @param string $date Message internal date - * @param bool $binary Enable BINARY append (RFC3516) + * @param string $mailbox Mailbox name + * @param string $message Message content + * @param array $flags Message flags + * @param string $date Message internal date + * @param bool $binary Enable BINARY append (RFC3516) * * @return string|bool On success APPENDUID response (if available) or True, False on failure */ @@ -2663,28 +2631,13 @@ class rcube_imap_generic $binary = $binary && $this->getCapability('BINARY'); $literal_plus = !$binary && $this->prefs['literal+']; - $len = 0; - $msg = is_array($message) ? $message : array(&$message); - $chunk_size = 512000; - - for ($i=0, $cnt=count($msg); $i<$cnt; $i++) { - if (is_resource($msg[$i])) { - $stat = fstat($msg[$i]); - if ($stat === false) { - return false; - } - $len += $stat['size']; - } - else { - if (!$binary) { - $msg[$i] = str_replace("\r", '', $msg[$i]); - $msg[$i] = str_replace("\n", "\r\n", $msg[$i]); - } - $len += strlen($msg[$i]); - } + if (!$binary) { + $message = str_replace("\r", '', $message); + $message = str_replace("\n", "\r\n", $message); } + $len = strlen($message); if (!$len) { return false; } @@ -2709,32 +2662,7 @@ class rcube_imap_generic } } - foreach ($msg as $msg_part) { - // file pointer - if (is_resource($msg_part)) { - rewind($msg_part); - while (!feof($msg_part) && $this->fp) { - $buffer = fread($msg_part, $chunk_size); - $this->putLine($buffer, false); - } - fclose($msg_part); - } - // string - else { - $size = strlen($msg_part); - - // Break up the data by sending one chunk (up to 512k) at a time. - // This approach reduces our peak memory usage - for ($offset = 0; $offset < $size; $offset += $chunk_size) { - $chunk = substr($msg_part, $offset, $chunk_size); - if (!$this->putLine($chunk, false)) { - return false; - } - } - } - } - - if (!$this->putLine('')) { // \r\n + if (!$this->putLine($message)) { return false; } @@ -2773,23 +2701,94 @@ class rcube_imap_generic */ function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null, $binary = false) { + unset($this->data['APPENDUID']); + + if ($mailbox === null || $mailbox === '') { + return false; + } + // open message file + $in_fp = false; if (file_exists(realpath($path))) { - $fp = fopen($path, 'r'); + $in_fp = fopen($path, 'r'); } - if (!$fp) { + if (!$in_fp) { $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading"); return false; } - $message = array(); + $body_separator = "\r\n\r\n"; + $len = filesize($path); + + if (!$len) { + return false; + } + if ($headers) { - $message[] = trim($headers, "\r\n") . "\r\n\r\n"; + $headers = preg_replace('/[\r\n]+$/', '', $headers); + $len += strlen($headers) + strlen($body_separator); + } + + $binary = $binary && $this->getCapability('BINARY'); + $literal_plus = !$binary && $this->prefs['literal+']; + + // build APPEND command + $key = $this->nextTag(); + $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')'; + if (!empty($date)) { + $request .= ' ' . $this->escape($date); } - $message[] = $fp; + $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}'; + + // send APPEND command + if ($this->putLine($request)) { + // Don't wait when LITERAL+ is supported + if (!$literal_plus) { + $line = $this->readReply(); - return $this->append($mailbox, $message, $flags, $date, $binary); + if ($line[0] != '+') { + $this->parseResult($line, 'APPEND: '); + return false; + } + } + + // send headers with body separator + if ($headers) { + $this->putLine($headers . $body_separator, false); + } + + // send file + while (!feof($in_fp) && $this->fp) { + $buffer = fgets($in_fp, 4096); + $this->putLine($buffer, false); + } + fclose($in_fp); + + if (!$this->putLine('')) { // \r\n + return false; + } + + // read response + do { + $line = $this->readLine(); + } while (!$this->startsWith($line, $key, true, true)); + + // Clear internal status cache + unset($this->data['STATUS:'.$mailbox]); + + if ($this->parseResult($line, 'APPEND: ') != self::ERROR_OK) + return false; + else if (!empty($this->data['APPENDUID'])) + return $this->data['APPENDUID']; + else + return true; + } + else { + $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); + } + + return false; } /** @@ -3538,7 +3537,7 @@ class rcube_imap_generic if (is_array($element)) { reset($element); - foreach ($element as $value) { + while (list($key, $value) = each($element)) { $string .= ' ' . self::r_implode($value); } } @@ -3566,7 +3565,7 @@ class rcube_imap_generic // if less than 255 bytes long, let's not bother if (!$force && strlen($messages)<255) { return $messages; - } + } // see if it's already been compressed if (strpos($messages, ':') !== false) { @@ -3674,20 +3673,8 @@ class rcube_imap_generic */ static function strToTime($date) { - // Clean malformed data - $date = preg_replace( - array( - '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal - '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters - '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names - ), - array( - '\\1', - '', - '', - ), $date); - - $date = trim($date); + // support non-standard "GMTXXXX" literal + $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); // if date parsing fails, we have a date in non-rfc format // remove token from the end and try again @@ -3712,10 +3699,6 @@ class rcube_imap_generic $this->capability = explode(' ', strtoupper($str)); - if (!empty($this->prefs['disabled_caps'])) { - $this->capability = array_diff($this->capability, $this->prefs['disabled_caps']); - } - if (!isset($this->prefs['literal+']) && in_array('LITERAL+', $this->capability)) { $this->prefs['literal+'] = true; } @@ -3761,10 +3744,9 @@ class rcube_imap_generic /** * Set the value of the debugging flag. * - * @param boolean $debug New value for the debugging flag. - * @param callback $handler Logging handler function + * @param boolean $debug New value for the debugging flag. * - * @since 0.5-stable + * @since 0.5-stable */ function setDebug($debug, $handler = null) { @@ -3775,18 +3757,12 @@ class rcube_imap_generic /** * Write the given debug text to the current debug output handler. * - * @param string $message Debug mesage text. + * @param string $message Debug mesage text. * - * @since 0.5-stable + * @since 0.5-stable */ private function debug($message) { - if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) { - $diff = $len - self::DEBUG_LINE_LENGTH; - $message = substr($message, 0, self::DEBUG_LINE_LENGTH) - . "... [truncated $diff bytes]"; - } - if ($this->resourceid) { $message = sprintf('[%s] %s', $this->resourceid, $message); } diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 78573789b..7c4002337 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -3,8 +3,8 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2013, The Roundcube Dev Team | - | Copyright (C) 2011-2013, Kolab Systems AG | + | Copyright (C) 2006-2012, The Roundcube Dev Team | + | Copyright (C) 2011-2012, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -27,51 +27,38 @@ */ class rcube_ldap extends rcube_addressbook { - // public properties + /** public properties */ public $primary_key = 'ID'; - public $groups = false; - public $readonly = true; - public $ready = false; - public $group_id = 0; - public $coltypes = array(); - public $export_groups = false; - - // private properties - protected $ldap; - protected $prop = array(); + public $groups = false; + public $readonly = true; + public $ready = false; + public $group_id = 0; + public $coltypes = array(); + + /** private properties */ + protected $conn; + protected $prop = array(); protected $fieldmap = array(); - protected $filter = ''; protected $sub_filter; - protected $result; - protected $ldap_result; + protected $filter = ''; + protected $result = null; + protected $ldap_result = null; protected $mail_domain = ''; protected $debug = false; - /** - * Group objectclass (lowercase) to member attribute mapping - * - * @var array - */ - private static $group_types = array( - 'group' => 'member', - 'groupofnames' => 'member', - 'kolabgroupofnames' => 'member', - 'groupofuniquenames' => 'uniqueMember', - 'kolabgroupofuniquenames' => 'uniqueMember', - 'univentiongroup' => 'uniqueMember', - 'groupofurls' => null, - ); - - private $base_dn = ''; + private $base_dn = ''; private $groups_base_dn = ''; - private $group_url; + private $group_url = null; private $cache; + private $vlv_active = false; + private $vlv_count = 0; + /** * Object constructor * - * @param array $p LDAP connection properties + * @param array $p LDAP connection properties * @param boolean $debug Enables debug mode * @param string $mail_domain Current user mail domain name */ @@ -79,7 +66,8 @@ class rcube_ldap extends rcube_addressbook { $this->prop = $p; - $fetch_attributes = array('objectClass'); + if (isset($p['searchonly'])) + $this->searchonly = $p['searchonly']; // check if groups are configured if (is_array($p['groups']) && count($p['groups'])) { @@ -94,21 +82,6 @@ class rcube_ldap extends rcube_addressbook $this->prop['groups']['name_attr'] = 'cn'; if (empty($this->prop['groups']['scope'])) $this->prop['groups']['scope'] = 'sub'; - - // add group name attrib to the list of attributes to be fetched - $fetch_attributes[] = $this->prop['groups']['name_attr']; - } - if (is_array($p['group_filters']) && count($p['group_filters'])) { - $this->groups = true; - - foreach ($p['group_filters'] as $k => $group_filter) { - // set default name attribute to cn - if (empty($group_filter['name_attr']) && empty($this->prop['groups']['name_attr'])) - $this->prop['group_filters'][$k]['name_attr'] = $group_filter['name_attr'] = 'cn'; - - if ($group_filter['name_attr']) - $fetch_attributes[] = $group_filter['name_attr']; - } } // fieldmap property is given @@ -196,7 +169,7 @@ class rcube_ldap extends rcube_addressbook // Build sub_fields filter if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { $this->sub_filter = ''; - foreach ($this->prop['sub_fields'] as $class) { + foreach ($this->prop['sub_fields'] as $attr => $class) { if (!empty($class)) { $class = is_array($class) ? array_pop($class) : $class; $this->sub_filter .= '(objectClass=' . $class . ')'; @@ -213,24 +186,7 @@ class rcube_ldap extends rcube_addressbook // initialize cache $rcube = rcube::get_instance(); - if ($cache_type = $rcube->config->get('ldap_cache', 'db')) { - $cache_ttl = $rcube->config->get('ldap_cache_ttl', '10m'); - $cache_name = 'LDAP.' . asciiwords($this->prop['name']); - - $this->cache = $rcube->get_cache($cache_name, $cache_type, $cache_ttl); - } - - // determine which attributes to fetch - $this->prop['list_attributes'] = array_unique($fetch_attributes); - $this->prop['attributes'] = array_merge(array_values($this->fieldmap), $fetch_attributes); - foreach ($rcube->config->get('contactlist_fields') as $col) { - $this->prop['list_attributes'] = array_merge($this->prop['list_attributes'], $this->_map_field($col)); - } - - // initialize ldap wrapper object - $this->ldap = new rcube_ldap_generic($this->prop); - $this->ldap->set_cache($this->cache); - $this->ldap->set_debug($this->debug); + $this->cache = $rcube->get_cache('LDAP.' . asciiwords($this->prop['name']), 'db', 600); $this->_connect(); } @@ -243,18 +199,49 @@ class rcube_ldap extends rcube_addressbook { $rcube = rcube::get_instance(); - if ($this->ready) + if (!function_exists('ldap_connect')) + rcube::raise_error(array('code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "No ldap support in this installation of PHP"), + true, true); + + if (is_resource($this->conn)) return true; if (!is_array($this->prop['hosts'])) $this->prop['hosts'] = array($this->prop['hosts']); + if (empty($this->prop['ldap_version'])) + $this->prop['ldap_version'] = 3; + // try to connect + bind for every host configured // with OpenLDAP 2.x ldap_connect() always succeeds but ldap_bind will fail if host isn't reachable // see http://www.php.net/manual/en/function.ldap-connect.php foreach ($this->prop['hosts'] as $host) { - // skip host if connection failed - if (!$this->ldap->connect($host)) { + $host = rcube_utils::idn_to_ascii(rcube_utils::parse_host($host)); + $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); + + $this->_debug("C: Connect [$hostname] [{$this->prop['name']}]"); + + if ($lc = @ldap_connect($host, $this->prop['port'])) { + if ($this->prop['use_tls'] === true) + if (!ldap_start_tls($lc)) + continue; + + $this->_debug("S: OK"); + + ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']); + $this->prop['host'] = $host; + $this->conn = $lc; + + if (!empty($this->prop['network_timeout'])) + ldap_set_option($lc, LDAP_OPT_NETWORK_TIMEOUT, $this->prop['network_timeout']); + + if (isset($this->prop['referrals'])) + ldap_set_option($lc, LDAP_OPT_REFERRALS, $this->prop['referrals']); + } + else { + $this->_debug("S: NOT OK"); continue; } @@ -269,7 +256,7 @@ class rcube_ldap extends rcube_addressbook $this->base_dn = $this->prop['base_dn']; $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? - $this->prop['groups']['base_dn'] : $this->base_dn; + $this->prop['groups']['base_dn'] : $this->base_dn; // User specific access, generate the proper values to use. if ($this->prop['user_specific']) { @@ -288,47 +275,30 @@ class rcube_ldap extends rcube_addressbook $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); - // Search for the dn to use to authenticate if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { - $search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces); - $search_base_dn = strtr($this->prop['search_base_dn'], $replaces); - $search_filter = strtr($this->prop['search_filter'], $replaces); - - $cache_key = 'DN.' . md5("$host:$search_bind_dn:$search_base_dn:$search_filter:" - .$this->prop['search_bind_pw']); - - if ($this->cache && ($dn = $this->cache->get($cache_key))) { - $replaces['%dn'] = $dn; + if (!empty($this->prop['search_bind_dn']) && !empty($this->prop['search_bind_pw'])) { + $this->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']); } - else { - $ldap = $this->ldap; - if (!empty($search_bind_dn) && !empty($this->prop['search_bind_pw'])) { - // To protect from "Critical extension is unavailable" error - // we need to use a separate LDAP connection - if (!empty($this->prop['vlv'])) { - $ldap = new rcube_ldap_generic($this->prop); - $ldap->set_debug($this->debug); - $ldap->set_cache($this->cache); - if (!$ldap->connect($host)) { - continue; - } - } - - if (!$ldap->bind($search_bind_dn, $this->prop['search_bind_pw'])) { - continue; // bind failed, try next host - } - } - $res = $ldap->search($search_base_dn, $search_filter, 'sub', array('uid')); - if ($res) { - $res->rewind(); - $replaces['%dn'] = $res->get_dn(); - } + // Search for the dn to use to authenticate + $this->prop['search_base_dn'] = strtr($this->prop['search_base_dn'], $replaces); + $this->prop['search_filter'] = strtr($this->prop['search_filter'], $replaces); + + $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); - if ($ldap != $this->ldap) { - $ldap->close(); + $res = @ldap_search($this->conn, $this->prop['search_base_dn'], $this->prop['search_filter'], array('uid')); + if ($res) { + if (($entry = ldap_first_entry($this->conn, $res)) + && ($bind_dn = ldap_get_dn($this->conn, $entry)) + ) { + $this->_debug("S: search returned dn: $bind_dn"); + $dn = ldap_explode_dn($bind_dn, 1); + $replaces['%dn'] = $dn[0]; } } + else { + $this->_debug("S: ".ldap_error($this->conn)); + } // DN not found if (empty($replaces['%dn'])) { @@ -339,13 +309,9 @@ class rcube_ldap extends rcube_addressbook 'code' => 100, 'type' => 'ldap', 'file' => __FILE__, 'line' => __LINE__, 'message' => "DN not found using LDAP search."), true); - continue; + return false; } } - - if ($this->cache && !empty($replaces['%dn'])) { - $this->cache->set($cache_key, $replaces['%dn']); - } } // Replace the bind_dn and base_dn variables. @@ -363,13 +329,13 @@ class rcube_ldap extends rcube_addressbook } else { if (!empty($bind_dn)) { - $this->ready = $this->ldap->bind($bind_dn, $bind_pass); + $this->ready = $this->bind($bind_dn, $bind_pass); } else if (!empty($this->prop['auth_cid'])) { - $this->ready = $this->ldap->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); + $this->ready = $this->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); } else { - $this->ready = $this->ldap->sasl_bind($bind_user, $bind_pass); + $this->ready = $this->sasl_bind($bind_user, $bind_pass); } } @@ -380,10 +346,10 @@ class rcube_ldap extends rcube_addressbook } // end foreach hosts - if (!is_resource($this->ldap->conn)) { + if (!is_resource($this->conn)) { rcube::raise_error(array('code' => 100, 'type' => 'ldap', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not connect to any LDAP server, last tried $host"), true); + 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); return false; } @@ -393,47 +359,112 @@ class rcube_ldap extends rcube_addressbook /** - * Close connection to LDAP server + * Bind connection with (SASL-) user and password + * + * @param string $authc Authentication user + * @param string $pass Bind password + * @param string $authz Autorization user + * + * @return boolean True on success, False on error */ - function close() + public function sasl_bind($authc, $pass, $authz=null) { - if ($this->ldap) { - $this->ldap->close(); + if (!$this->conn) { + return false; + } + + if (!function_exists('ldap_sasl_bind')) { + rcube::raise_error(array('code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Unable to bind: ldap_sasl_bind() not exists"), + true, true); } + + if (!empty($authz)) { + $authz = 'u:' . $authz; + } + + if (!empty($this->prop['auth_method'])) { + $method = $this->prop['auth_method']; + } + else { + $method = 'DIGEST-MD5'; + } + + $this->_debug("C: Bind [mech: $method, authc: $authc, authz: $authz] [pass: $pass]"); + + if (ldap_sasl_bind($this->conn, NULL, $pass, $method, NULL, $authc, $authz)) { + $this->_debug("S: OK"); + return true; + } + + $this->_debug("S: ".ldap_error($this->conn)); + + rcube::raise_error(array( + 'code' => ldap_errno($this->conn), 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Bind failed for authcid=$authc ".ldap_error($this->conn)), + true); + + return false; } /** - * Returns address book name + * Bind connection with DN and password * - * @return string Address book name + * @param string Bind DN + * @param string Bind password + * + * @return boolean True on success, False on error */ - function get_name() + public function bind($dn, $pass) { - return $this->prop['name']; + if (!$this->conn) { + return false; + } + + $this->_debug("C: Bind [dn: $dn] [pass: $pass]"); + + if (@ldap_bind($this->conn, $dn, $pass)) { + $this->_debug("S: OK"); + return true; + } + + $this->_debug("S: ".ldap_error($this->conn)); + + rcube::raise_error(array( + 'code' => ldap_errno($this->conn), 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)), + true); + + return false; } /** - * Set internal list page - * - * @param number Page number to list + * Close connection to LDAP server */ - function set_page($page) + function close() { - $this->list_page = (int)$page; - $this->ldap->set_vlv_page($this->list_page, $this->page_size); + if ($this->conn) + { + $this->_debug("C: Close"); + ldap_unbind($this->conn); + $this->conn = null; + } } + /** - * Set internal page size + * Returns address book name * - * @param number Number of records to display on one page + * @return string Address book name */ - function set_pagesize($size) + function get_name() { - $this->page_size = (int)$size; - $this->ldap->set_vlv_page($this->list_page, $this->page_size); + return $this->prop['name']; } @@ -493,14 +524,16 @@ class rcube_ldap extends rcube_addressbook */ function list_records($cols=null, $subset=0) { - if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id) { + if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id) + { $this->result = new rcube_result_set(0); $this->result->searchonly = true; return $this->result; } // fetch group members recursively - if ($this->group_id && $this->group_data['dn']) { + if ($this->group_id && $this->group_data['dn']) + { $entries = $this->list_group_members($this->group_data['dn']); // make list of entries unique and sort it @@ -514,35 +547,34 @@ class rcube_ldap extends rcube_addressbook $entries['count'] = count($entries); $this->result = new rcube_result_set($entries['count'], ($this->list_page-1) * $this->page_size); } - else { - $prop = $this->group_id ? $this->group_data : $this->prop; - $base_dn = $this->group_id ? $this->group_base_dn : $this->base_dn; - - // use global search filter - if (!empty($this->filter)) - $prop['filter'] = $this->filter; + else + { + // add general filter to query + if (!empty($this->prop['filter']) && empty($this->filter)) + $this->set_search_set($this->prop['filter']); // exec LDAP search if no result resource is stored - if ($this->ready && !$this->ldap_result) - $this->ldap_result = $this->ldap->search($base_dn, $prop['filter'], $prop['scope'], $this->prop['attributes'], $prop); + if ($this->conn && !$this->ldap_result) + $this->_exec_search(); // count contacts for this user $this->result = $this->count(); // we have a search result resource - if ($this->ldap_result && $this->result->count > 0) { + if ($this->ldap_result && $this->result->count > 0) + { // sorting still on the ldap server - if ($this->sort_col && $prop['scope'] !== 'base' && !$this->ldap->vlv_active) - $this->ldap_result->sort($this->sort_col); + if ($this->sort_col && $this->prop['scope'] !== 'base' && !$this->vlv_active) + ldap_sort($this->conn, $this->ldap_result, $this->sort_col); // get all entries from the ldap server - $entries = $this->ldap_result->entries(); + $entries = ldap_get_entries($this->conn, $this->ldap_result); } } // end else // start and end of the page - $start_row = $this->ldap->vlv_active ? 0 : $this->result->first; + $start_row = $this->vlv_active ? 0 : $this->result->first; $start_row = $subset < 0 ? $start_row + $this->page_size + $subset : $start_row; $last_row = $this->result->first + $this->page_size; $last_row = $subset != 0 ? $start_row + abs($subset) : $last_row; @@ -567,34 +599,43 @@ class rcube_ldap extends rcube_addressbook // fetch group object if (empty($entries)) { - $attribs = array('dn','objectClass','member','uniqueMember','memberURL'); - $entries = $this->ldap->read_entries($dn, '(objectClass=*)', $attribs); - if ($entries === false) { + $result = @ldap_read($this->conn, $dn, '(objectClass=*)', array('dn','objectClass','member','uniqueMember','memberURL')); + if ($result === false) + { + $this->_debug("S: ".ldap_error($this->conn)); return $group_members; } + + $entries = @ldap_get_entries($this->conn, $result); } - for ($i=0; $i < $entries['count']; $i++) { + for ($i=0; $i < $entries['count']; $i++) + { $entry = $entries[$i]; - $attrs = array(); - foreach ((array)$entry['objectclass'] as $objectclass) { - if (strtolower($objectclass) == 'groupofurls') { - $members = $this->_list_group_memberurl($dn, $entry, $count); - $group_members = array_merge($group_members, $members); - } - else if (($member_attr = $this->get_group_member_attr(array($objectclass), '')) - && ($member_attr = strtolower($member_attr)) && !in_array($member_attr, $attrs) - ) { - $members = $this->_list_group_members($dn, $entry, $member_attr, $count); - $group_members = array_merge($group_members, $members); - $attrs[] = $member_attr; - } + if (empty($entry['objectclass'])) + continue; - if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) { - break 2; + foreach ((array)$entry['objectclass'] as $objectclass) + { + switch (strtolower($objectclass)) { + case "group": + case "groupofnames": + case "kolabgroupofnames": + $group_members = array_merge($group_members, $this->_list_group_members($dn, $entry, 'member', $count)); + break; + case "groupofuniquenames": + case "kolabgroupofuniquenames": + $group_members = array_merge($group_members, $this->_list_group_members($dn, $entry, 'uniquemember', $count)); + break; + case "groupofurls": + $group_members = array_merge($group_members, $this->_list_group_memberurl($dn, $entry, $count)); + break; } } + + if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) + break; } return array_filter($group_members); @@ -613,24 +654,28 @@ class rcube_ldap extends rcube_addressbook // Use the member attributes to return an array of member ldap objects // NOTE that the member attribute is supposed to contain a DN $group_members = array(); - if (empty($entry[$attr])) { + if (empty($entry[$attr])) return $group_members; - } // read these attributes for all members - $attrib = $count ? array('dn','objectClass') : $this->prop['list_attributes']; + $attrib = $count ? array('dn') : array_values($this->fieldmap); + $attrib[] = 'objectClass'; $attrib[] = 'member'; $attrib[] = 'uniqueMember'; $attrib[] = 'memberURL'; - $filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)'; - - for ($i=0; $i < $entry[$attr]['count']; $i++) { + for ($i=0; $i < $entry[$attr]['count']; $i++) + { if (empty($entry[$attr][$i])) continue; - $members = $this->ldap->read_entries($entry[$attr][$i], $filter, $attrib); - if ($members == false) { + $result = @ldap_read($this->conn, $entry[$attr][$i], '(objectclass=*)', + $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']); + + $members = @ldap_get_entries($this->conn, $result); + if ($members == false) + { + $this->_debug("S: ".ldap_error($this->conn)); $members = array(); } @@ -656,22 +701,34 @@ class rcube_ldap extends rcube_addressbook { $group_members = array(); - for ($i=0; $i < $entry['memberurl']['count']; $i++) { + for ($i=0; $i < $entry['memberurl']['count']; $i++) + { // extract components from url if (!preg_match('!ldap:///([^\?]+)\?\?(\w+)\?(.*)$!', $entry['memberurl'][$i], $m)) continue; // add search filter if any $filter = $this->filter ? '(&(' . $m[3] . ')(' . $this->filter . '))' : $m[3]; - $attrs = $count ? array('dn','objectClass') : $this->prop['list_attributes']; - if ($result = $this->ldap->search($m[1], $filter, $m[2], $attrs, $this->group_data)) { - $entries = $result->entries(); - for ($j = 0; $j < $entries['count']; $j++) { - if (self::is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count))) - $group_members = array_merge($group_members, $nested_group_members); - else - $group_members[] = $entries[$j]; - } + $func = $m[2] == 'sub' ? 'ldap_search' : ($m[2] == 'base' ? 'ldap_read' : 'ldap_list'); + + $attrib = $count ? array('dn') : array_values($this->fieldmap); + if ($result = @$func($this->conn, $m[1], $filter, + $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) + ) { + $this->_debug("S: ".ldap_count_entries($this->conn, $result)." record(s) for ".$m[1]); + } + else { + $this->_debug("S: ".ldap_error($this->conn)); + return $group_members; + } + + $entries = @ldap_get_entries($this->conn, $result); + for ($j = 0; $j < $entries['count']; $j++) + { + if ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count)) + $group_members = array_merge($group_members, $nested_group_members); + else + $group_members[] = $entries[$j]; } } @@ -707,11 +764,14 @@ class rcube_ldap extends rcube_addressbook $mode = intval($mode); // special treatment for ID-based search - if ($fields == 'ID' || $fields == $this->primary_key) { + if ($fields == 'ID' || $fields == $this->primary_key) + { $ids = !is_array($value) ? explode(',', $value) : $value; $result = new rcube_result_set(); - foreach ($ids as $id) { - if ($rec = $this->get_record($id, true)) { + foreach ($ids as $id) + { + if ($rec = $this->get_record($id, true)) + { $result->add($rec); $result->count++; } @@ -723,20 +783,34 @@ class rcube_ldap extends rcube_addressbook $rcube = rcube::get_instance(); $list_fields = $rcube->config->get('contactlist_fields'); - if ($this->prop['vlv_search'] && $this->ready && join(',', (array)$fields) == join(',', $list_fields)) { + if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == join(',', $list_fields)) + { + // add general filter to query + if (!empty($this->prop['filter']) && empty($this->filter)) + $this->set_search_set($this->prop['filter']); + + // set VLV controls with encoded search string + $this->_vlv_set_controls($this->prop, $this->list_page, $this->page_size, $value); + + $function = $this->_scope2func($this->prop['scope']); + $this->ldap_result = @$function($this->conn, $this->base_dn, $this->filter ? $this->filter : '(objectclass=*)', + array_values($this->fieldmap), 0, $this->page_size, (int)$this->prop['timelimit']); + $this->result = new rcube_result_set(0); - $search_suffix = $this->prop['fuzzy_search'] && $mode != 1 ? '*' : ''; - $ldap_data = $this->ldap->search($this->base_dn, $this->prop['filter'], $this->prop['scope'], $this->prop['attributes'], - array('search' => $value . $search_suffix /*, 'sort' => $this->prop['sort'] */)); - if ($ldap_data === false) { + if (!$this->ldap_result) { + $this->_debug("S: ".ldap_error($this->conn)); return $this->result; } + $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); + // get all entries of this page and post-filter those that really match the query - $search = mb_strtolower($value); - foreach ($ldap_data as $i => $entry) { - $rec = $this->_ldap2result($entry); + $search = mb_strtolower($value); + $entries = ldap_get_entries($this->conn, $this->ldap_result); + + for ($i = 0; $i < $entries['count']; $i++) { + $rec = $this->_ldap2result($entries[$i]); foreach ($fields as $f) { foreach ((array)$rec[$f] as $val) { if ($this->compare_search_value($f, $val, $search, $mode)) { @@ -762,27 +836,31 @@ class rcube_ldap extends rcube_addressbook } } - if ($fields == '*') { + if ($fields == '*') + { // search_fields are required for fulltext search - if (empty($this->prop['search_fields'])) { + if (empty($this->prop['search_fields'])) + { $this->set_error(self::ERROR_SEARCH, 'nofulltextsearch'); $this->result = new rcube_result_set(); return $this->result; } - if (is_array($this->prop['search_fields'])) { + if (is_array($this->prop['search_fields'])) + { foreach ($this->prop['search_fields'] as $field) { - $filter .= "($field=$wp" . rcube_ldap_generic::quote_string($value) . "$ws)"; + $filter .= "($field=$wp" . $this->_quote_string($value) . "$ws)"; } } } - else { + else + { foreach ((array)$fields as $idx => $field) { $val = is_array($value) ? $value[$idx] : $value; if ($attrs = $this->_map_field($field)) { if (count($attrs) > 1) $filter .= '(|'; foreach ($attrs as $f) - $filter .= "($f=$wp" . rcube_ldap_generic::quote_string($val) . "$ws)"; + $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; if (count($attrs) > 1) $filter .= ')'; } @@ -817,6 +895,7 @@ class rcube_ldap extends rcube_addressbook // set filter string and execute search $this->set_search_set($filter); + $this->_exec_search(); if ($select) $this->list_records(); @@ -835,21 +914,20 @@ class rcube_ldap extends rcube_addressbook function count() { $count = 0; - if ($this->ldap_result) { - $count = $this->ldap_result->count(); + if ($this->conn && $this->ldap_result) { + $count = $this->vlv_active ? $this->vlv_count : ldap_count_entries($this->conn, $this->ldap_result); } else if ($this->group_id && $this->group_data['dn']) { $count = count($this->list_group_members($this->group_data['dn'], true)); } - // We have a connection but no result set, attempt to get one. - else if ($this->ready) { - $prop = $this->group_id ? $this->group_data : $this->prop; - $base_dn = $this->group_id ? $this->group_base_dn : $this->base_dn; - - if (!empty($this->filter)) { // Use global search filter - $prop['filter'] = $this->filter; + else if ($this->conn) { + // We have a connection but no result set, attempt to get one. + if (empty($this->filter)) { + // The filter is not set, set it. + $this->filter = $this->prop['filter']; } - $count = $this->ldap->search($base_dn, $prop['filter'], $prop['scope'], array('dn'), $prop, true); + + $count = (int) $this->_exec_search(true); } return new rcube_result_set($count, ($this->list_page-1) * $this->page_size); @@ -879,16 +957,28 @@ class rcube_ldap extends rcube_addressbook { $res = $this->result = null; - if ($this->ready && $dn) { + if ($this->conn && $dn) + { $dn = self::dn_decode($dn); - if ($rec = $this->ldap->get_entry($dn)) { - $rec = array_change_key_case($rec, CASE_LOWER); + $this->_debug("C: Read [dn: $dn] [(objectclass=*)]"); + + if ($ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', array_values($this->fieldmap))) { + $this->_debug("S: OK"); + + $entry = ldap_first_entry($this->conn, $ldap_result); + + if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) { + $rec = array_change_key_case($rec, CASE_LOWER); + } + } + else { + $this->_debug("S: ".ldap_error($this->conn)); } // Use ldap_list to get subentries like country (c) attribute (#1488123) if (!empty($rec) && $this->sub_filter) { - if ($entries = $this->ldap->list_entries($dn, $this->sub_filter, array_keys($this->prop['sub_fields']))) { + if ($entries = $this->ldap_list($dn, $this->sub_filter, array_keys($this->prop['sub_fields']))) { foreach ($entries as $entry) { $lrec = array_change_key_case($entry, CASE_LOWER); $rec = array_merge($lrec, $rec); @@ -900,7 +990,7 @@ class rcube_ldap extends rcube_addressbook // Add in the dn for the entry. $rec['dn'] = $dn; $res = $this->_ldap2result($rec); - $this->result = new rcube_result_set(1); + $this->result = new rcube_result_set(); $this->result->add($res); } } @@ -947,6 +1037,7 @@ class rcube_ldap extends rcube_addressbook $mail_field = $this->fieldmap['email']; // try to extract surname and firstname from displayname + $reverse_map = array_flip($this->fieldmap); $name_parts = preg_split('/[\s,.]+/', $save_data['name']); if ($sn_field && $missing[$sn_field]) { @@ -1013,12 +1104,12 @@ class rcube_ldap extends rcube_addressbook } // Build the new entries DN. - $dn = $this->prop['LDAP_rdn'].'='.rcube_ldap_generic::quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->base_dn; + $dn = $this->prop['LDAP_rdn'].'='.$this->_quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->base_dn; // Remove attributes that need to be added separately (child objects) $xfields = array(); if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { - foreach (array_keys($this->prop['sub_fields']) as $xf) { + foreach ($this->prop['sub_fields'] as $xf => $xclass) { if (!empty($newentry[$xf])) { $xfields[$xf] = $newentry[$xf]; unset($newentry[$xf]); @@ -1026,19 +1117,19 @@ class rcube_ldap extends rcube_addressbook } } - if (!$this->ldap->add($dn, $newentry)) { + if (!$this->ldap_add($dn, $newentry)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } foreach ($xfields as $xidx => $xf) { - $xdn = $xidx.'='.rcube_ldap_generic::quote_string($xf).','.$dn; + $xdn = $xidx.'='.$this->_quote_string($xf).','.$dn; $xf = array( $xidx => $xf, 'objectClass' => (array) $this->prop['sub_fields'][$xidx], ); - $this->ldap->add($xdn, $xf); + $this->ldap_add($xdn, $xf); } $dn = self::dn_encode($dn); @@ -1081,7 +1172,7 @@ class rcube_ldap extends rcube_addressbook } } - foreach ($this->fieldmap as $fld) { + foreach ($this->fieldmap as $col => $fld) { if ($fld) { $val = $ldap_data[$fld]; $old = $old_data[$fld]; @@ -1144,7 +1235,7 @@ class rcube_ldap extends rcube_addressbook // Update the entry as required. if (!empty($deletedata)) { // Delete the fields. - if (!$this->ldap->mod_del($dn, $deletedata)) { + if (!$this->ldap_mod_del($dn, $deletedata)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1154,17 +1245,17 @@ class rcube_ldap extends rcube_addressbook // Handle RDN change if ($replacedata[$this->prop['LDAP_rdn']]) { $newdn = $this->prop['LDAP_rdn'].'=' - .rcube_ldap_generic::quote_string($replacedata[$this->prop['LDAP_rdn']], true) + .$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true) .','.$this->base_dn; if ($dn != $newdn) { $newrdn = $this->prop['LDAP_rdn'].'=' - .rcube_ldap_generic::quote_string($replacedata[$this->prop['LDAP_rdn']], true); + .$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true); unset($replacedata[$this->prop['LDAP_rdn']]); } } // Replace the fields. if (!empty($replacedata)) { - if (!$this->ldap->mod_replace($dn, $replacedata)) { + if (!$this->ldap_mod_replace($dn, $replacedata)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1180,8 +1271,8 @@ class rcube_ldap extends rcube_addressbook // remove sub-entries if (!empty($subdeldata)) { foreach ($subdeldata as $fld => $val) { - $subdn = $fld.'='.rcube_ldap_generic::quote_string($val).','.$dn; - if (!$this->ldap->delete($subdn)) { + $subdn = $fld.'='.$this->_quote_string($val).','.$dn; + if (!$this->ldap_delete($subdn)) { return false; } } @@ -1189,7 +1280,7 @@ class rcube_ldap extends rcube_addressbook if (!empty($newdata)) { // Add the fields. - if (!$this->ldap->mod_add($dn, $newdata)) { + if (!$this->ldap_mod_add($dn, $newdata)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1197,7 +1288,7 @@ class rcube_ldap extends rcube_addressbook // Handle RDN change if (!empty($newrdn)) { - if (!$this->ldap->rename($dn, $newrdn, null, true)) { + if (!$this->ldap_rename($dn, $newrdn, null, true)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1208,7 +1299,8 @@ class rcube_ldap extends rcube_addressbook // change the group membership of the contact if ($this->groups) { $group_ids = $this->get_record_groups($dn); - foreach (array_keys($group_ids) as $group_id) { + foreach ($group_ids as $group_id) + { $this->remove_from_group($group_id, $dn); $this->add_to_group($group_id, $newdn); } @@ -1220,12 +1312,12 @@ class rcube_ldap extends rcube_addressbook // add sub-entries if (!empty($subnewdata)) { foreach ($subnewdata as $fld => $val) { - $subdn = $fld.'='.rcube_ldap_generic::quote_string($val).','.$dn; + $subdn = $fld.'='.$this->_quote_string($val).','.$dn; $xf = array( $fld => $val, 'objectClass' => (array) $this->prop['sub_fields'][$fld], ); - $this->ldap->add($subdn, $xf); + $this->ldap_add($subdn, $xf); } } @@ -1253,9 +1345,9 @@ class rcube_ldap extends rcube_addressbook // Need to delete all sub-entries first if ($this->sub_filter) { - if ($entries = $this->ldap->list_entries($dn, $this->sub_filter)) { + if ($entries = $this->ldap_list($dn, $this->sub_filter)) { foreach ($entries as $entry) { - if (!$this->ldap->delete($entry['dn'])) { + if (!$this->ldap_delete($entry['dn'])) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1264,7 +1356,7 @@ class rcube_ldap extends rcube_addressbook } // Delete the record. - if (!$this->ldap->delete($dn)) { + if (!$this->ldap_delete($dn)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } @@ -1273,7 +1365,7 @@ class rcube_ldap extends rcube_addressbook if ($this->groups) { $dn = self::dn_encode($dn); $group_ids = $this->get_record_groups($dn); - foreach (array_keys($group_ids) as $group_id) { + foreach ($group_ids as $group_id) { $this->remove_from_group($group_id, $dn); } } @@ -1288,8 +1380,8 @@ class rcube_ldap extends rcube_addressbook */ function delete_all() { - // searching for contact entries - $dn_list = $this->ldap->list_entries($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)'); + //searching for contact entries + $dn_list = $this->ldap_list($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)'); if (!empty($dn_list)) { foreach ($dn_list as $idx => $entry) { @@ -1306,10 +1398,6 @@ class rcube_ldap extends rcube_addressbook */ protected function add_autovalues(&$attrs) { - if (empty($this->prop['autovalues'])) { - return; - } - $attrvals = array(); foreach ($attrs as $k => $v) { $attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v; @@ -1320,16 +1408,7 @@ class rcube_ldap extends rcube_addressbook if (strpos($templ, '(') !== false) { // replace {attr} placeholders with (escaped!) attribute values to be safely eval'd $code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals))); - $fn = create_function('', "return ($code);"); - if (!$fn) { - rcube::raise_error(array( - 'code' => 505, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Expression parse error on: ($code)"), true, false); - continue; - } - - $attrs[$lf] = $fn(); + $attrs[$lf] = eval("return ($code);"); } else { // replace {attr} placeholders with concrete attribute values @@ -1339,26 +1418,120 @@ class rcube_ldap extends rcube_addressbook } } + /** + * Execute the LDAP search based on the stored credentials + */ + private function _exec_search($count = false) + { + if ($this->ready) + { + $filter = $this->filter ? $this->filter : '(objectclass=*)'; + $function = $this->_scope2func($this->prop['scope'], $ns_function); + + $this->_debug("C: Search [$filter][dn: $this->base_dn]"); + + // when using VLV, we get the total count by... + if (!$count && $function != 'ldap_read' && $this->prop['vlv'] && !$this->group_id) { + // ...either reading numSubOrdinates attribute + if ($this->prop['numsub_filter'] && ($result_count = @$ns_function($this->conn, $this->base_dn, $this->prop['numsub_filter'], array('numSubOrdinates'), 0, 0, 0))) { + $counts = ldap_get_entries($this->conn, $result_count); + for ($this->vlv_count = $j = 0; $j < $counts['count']; $j++) + $this->vlv_count += $counts[$j]['numsubordinates'][0]; + $this->_debug("D: total numsubordinates = " . $this->vlv_count); + } + else if (!function_exists('ldap_parse_virtuallist_control')) // ...or by fetching all records dn and count them + $this->vlv_count = $this->_exec_search(true); + + $this->vlv_active = $this->_vlv_set_controls($this->prop, $this->list_page, $this->page_size); + } + + // only fetch dn for count (should keep the payload low) + $attrs = $count ? array('dn') : array_values($this->fieldmap); + if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter, + $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) + ) { + // when running on a patched PHP we can use the extended functions to retrieve the total count from the LDAP search result + if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) { + if (ldap_parse_result($this->conn, $this->ldap_result, + $errcode, $matcheddn, $errmsg, $referrals, $serverctrls) + && $serverctrls // can be null e.g. in case of adm. limit error + ) { + ldap_parse_virtuallist_control($this->conn, $serverctrls, + $last_offset, $this->vlv_count, $vresult); + $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$this->vlv_count"); + } + else { + $this->_debug("S: ".($errmsg ? $errmsg : ldap_error($this->conn))); + } + } + + $entries_count = ldap_count_entries($this->conn, $this->ldap_result); + $this->_debug("S: $entries_count record(s)"); + + return $count ? $entries_count : true; + } + else { + $this->_debug("S: ".ldap_error($this->conn)); + } + } + + return false; + } + + /** + * Choose the right PHP function according to scope property + */ + private function _scope2func($scope, &$ns_function = null) + { + switch ($scope) { + case 'sub': + $function = $ns_function = 'ldap_search'; + break; + case 'base': + $function = $ns_function = 'ldap_read'; + break; + default: + $function = 'ldap_list'; + $ns_function = 'ldap_read'; + break; + } + + return $function; + } + + /** + * Set server controls for Virtual List View (paginated listing) + */ + private function _vlv_set_controls($prop, $list_page, $page_size, $search = null) + { + $sort_ctrl = array('oid' => "1.2.840.113556.1.4.473", 'value' => $this->_sort_ber_encode((array)$prop['sort'])); + $vlv_ctrl = array('oid' => "2.16.840.1.113730.3.4.9", 'value' => $this->_vlv_ber_encode(($offset = ($list_page-1) * $page_size + 1), $page_size, $search), 'iscritical' => true); + + $sort = (array)$prop['sort']; + $this->_debug("C: set controls sort=" . join(' ', unpack('H'.(strlen($sort_ctrl['value'])*2), $sort_ctrl['value'])) . " ($sort[0]);" + . " vlv=" . join(' ', (unpack('H'.(strlen($vlv_ctrl['value'])*2), $vlv_ctrl['value']))) . " ($offset/$page_size)"); + + if (!ldap_set_option($this->conn, LDAP_OPT_SERVER_CONTROLS, array($sort_ctrl, $vlv_ctrl))) { + $this->_debug("S: ".ldap_error($this->conn)); + $this->set_error(self::ERROR_SEARCH, 'vlvnotsupported'); + return false; + } + + return true; + } + /** * Converts LDAP entry into an array */ private function _ldap2result($rec) { - $out = array('_type' => 'person'); - $fieldmap = $this->fieldmap; + $out = array(); if ($rec['dn']) $out[$this->primary_key] = self::dn_encode($rec['dn']); - // determine record type - if (self::is_group_entry($rec)) { - $out['_type'] = 'group'; - $out['readonly'] = true; - $fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr']; - } - - foreach ($fieldmap as $rf => $lf) + foreach ($this->fieldmap as $rf => $lf) { for ($i=0; $i < $rec[$lf]['count']; $i++) { if (!($value = $rec[$lf][$i])) @@ -1420,10 +1593,8 @@ class rcube_ldap extends rcube_addressbook if (is_array($colprop['serialized'])) { foreach ($colprop['serialized'] as $subtype => $delim) { $key = $col.':'.$subtype; - foreach ((array)$save_cols[$key] as $i => $val) { - $values = array($val['street'], $val['locality'], $val['zipcode'], $val['country']); - $save_cols[$key][$i] = count(array_filter($values)) ? join($delim, $values) : null; - } + foreach ((array)$save_cols[$key] as $i => $val) + $save_cols[$key][$i] = join($delim, array($val['street'], $val['locality'], $val['zipcode'], $val['country'])); } } } @@ -1461,11 +1632,11 @@ class rcube_ldap extends rcube_addressbook { // list of known attribute aliases static $aliases = array( - 'gn' => 'givenname', + 'gn' => 'givenname', 'rfc822mailbox' => 'email', - 'userid' => 'uid', - 'emailaddress' => 'email', - 'pkcs9email' => 'email', + 'userid' => 'uid', + 'emailaddress' => 'email', + 'pkcs9email' => 'email', ); list($name, $limit) = explode(':', $namev, 2); @@ -1474,15 +1645,6 @@ class rcube_ldap extends rcube_addressbook return (isset($aliases[$name]) ? $aliases[$name] : $name) . $suffix; } - /** - * Determines whether the given LDAP entry is a group record - */ - private static function is_group_entry($entry) - { - $classes = array_map('strtolower', (array)$entry['objectclass']); - - return count(array_intersect(array_keys(self::$group_types), $classes)) > 0; - } /** * Prints debug info to the log @@ -1499,27 +1661,55 @@ class rcube_ldap extends rcube_addressbook * Activate/deactivate debug mode * * @param boolean $dbg True if LDAP commands should be logged + * @access public */ function set_debug($dbg = true) { $this->debug = $dbg; + } - if ($this->ldap) { - $this->ldap->set_debug($dbg); - } + + /** + * Quotes attribute value string + * + * @param string $str Attribute value + * @param bool $dn True if the attribute is a DN + * + * @return string Quoted string + */ + private static function _quote_string($str, $dn=false) + { + // take firt entry if array given + if (is_array($str)) + $str = reset($str); + + if ($dn) + $replace = array(','=>'\2c', '='=>'\3d', '+'=>'\2b', '<'=>'\3c', + '>'=>'\3e', ';'=>'\3b', '\\'=>'\5c', '"'=>'\22', '#'=>'\23'); + else + $replace = array('*'=>'\2a', '('=>'\28', ')'=>'\29', '\\'=>'\5c', + '/'=>'\2f'); + + return strtr($str, $replace); } /** * Setter for the current group + * (empty, has to be re-implemented by extending class) */ function set_group($group_id) { - if ($group_id) { + if ($group_id) + { + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); + $this->group_id = $group_id; - $this->group_data = $this->get_group_entry($group_id); + $this->group_data = $group_cache[$group_id]; } - else { + else + { $this->group_id = 0; $this->group_data = null; } @@ -1538,13 +1728,15 @@ class rcube_ldap extends rcube_addressbook */ function list_groups($search = null, $mode = 0) { - if (!$this->groups) { + if (!$this->groups) return array(); - } - $group_cache = $this->_fetch_groups(); - $groups = array(); + // use cached list for searching + $this->cache->expunge(); + if (!$search || ($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); + $groups = array(); if ($search) { foreach ($group_cache as $group) { if ($this->compare_search_value('name', $group['name'], $search, $mode)) { @@ -1552,9 +1744,8 @@ class rcube_ldap extends rcube_addressbook } } } - else { + else $groups = $group_cache; - } return array_values($groups); } @@ -1562,140 +1753,80 @@ class rcube_ldap extends rcube_addressbook /** * Fetch groups from server */ - private function _fetch_groups($vlv_page = null) + private function _fetch_groups($vlv_page = 0) { - // special case: list groups from 'group_filters' config - if ($vlv_page === null && !empty($this->prop['group_filters'])) { - $groups = array(); - - // list regular groups configuration as special filter - if (!empty($this->prop['groups']['filter'])) { - $id = '__groups__'; - $groups[$id] = array('ID' => $id, 'name' => rcube_label('groups'), 'virtual' => true) + $this->prop['groups']; - } - - foreach ($this->prop['group_filters'] as $id => $prop) { - $groups[$id] = $prop + array('ID' => $id, 'name' => ucfirst($id), 'virtual' => true, 'base_dn' => $this->base_dn); - } - - return $groups; - } - - if ($this->cache && $vlv_page === null && ($groups = $this->cache->get('groups')) !== null) { - return $groups; - } - - $base_dn = $this->groups_base_dn; - $filter = $this->prop['groups']['filter']; - $scope = $this->prop['groups']['scope']; - $name_attr = $this->prop['groups']['name_attr']; + $base_dn = $this->groups_base_dn; + $filter = $this->prop['groups']['filter']; + $name_attr = $this->prop['groups']['name_attr']; $email_attr = $this->prop['groups']['email_attr'] ? $this->prop['groups']['email_attr'] : 'mail'; $sort_attrs = $this->prop['groups']['sort'] ? (array)$this->prop['groups']['sort'] : array($name_attr); - $sort_attr = $sort_attrs[0]; + $sort_attr = $sort_attrs[0]; - $ldap = $this->ldap; + $this->_debug("C: Search [$filter][dn: $base_dn]"); // use vlv to list groups if ($this->prop['groups']['vlv']) { $page_size = 200; - if (!$this->prop['groups']['sort']) { + if (!$this->prop['groups']['sort']) $this->prop['groups']['sort'] = $sort_attrs; - } - - $ldap = clone $this->ldap; - $ldap->set_config($this->prop['groups']); - $ldap->set_vlv_page($vlv_page+1, $page_size); + $vlv_active = $this->_vlv_set_controls($this->prop['groups'], $vlv_page+1, $page_size); } - $attrs = array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr)); - $ldap_data = $ldap->search($base_dn, $filter, $scope, $attrs, $this->prop['groups']); - - if ($ldap_data === false) { + $function = $this->_scope2func($this->prop['groups']['scope'], $ns_function); + $res = @$function($this->conn, $base_dn, $filter, array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr))); + if ($res === false) + { + $this->_debug("S: ".ldap_error($this->conn)); return array(); } - $groups = array(); - $group_sortnames = array(); - $group_count = $ldap_data->count(); - - foreach ($ldap_data as $entry) { - if (!$entry['dn']) // DN is mandatory - $entry['dn'] = $ldap_data->get_dn(); + $ldap_data = ldap_get_entries($this->conn, $res); + $this->_debug("S: ".ldap_count_entries($this->conn, $res)." record(s)"); - $group_name = is_array($entry[$name_attr]) ? $entry[$name_attr][0] : $entry[$name_attr]; - $group_id = self::dn_encode($entry['dn']); + $groups = array(); + $group_sortnames = array(); + $group_count = $ldap_data["count"]; + for ($i=0; $i < $group_count; $i++) + { + $group_name = is_array($ldap_data[$i][$name_attr]) ? $ldap_data[$i][$name_attr][0] : $ldap_data[$i][$name_attr]; + $group_id = self::dn_encode($group_name); $groups[$group_id]['ID'] = $group_id; - $groups[$group_id]['dn'] = $entry['dn']; + $groups[$group_id]['dn'] = $ldap_data[$i]['dn']; $groups[$group_id]['name'] = $group_name; - $groups[$group_id]['member_attr'] = $this->get_group_member_attr($entry['objectclass']); + $groups[$group_id]['member_attr'] = $this->get_group_member_attr($ldap_data[$i]['objectclass']); // list email attributes of a group - for ($j=0; $entry[$email_attr] && $j < $entry[$email_attr]['count']; $j++) { - if (strpos($entry[$email_attr][$j], '@') > 0) - $groups[$group_id]['email'][] = $entry[$email_attr][$j]; + for ($j=0; $ldap_data[$i][$email_attr] && $j < $ldap_data[$i][$email_attr]['count']; $j++) { + if (strpos($ldap_data[$i][$email_attr][$j], '@') > 0) + $groups[$group_id]['email'][] = $ldap_data[$i][$email_attr][$j]; } - $group_sortnames[] = mb_strtolower($entry[$sort_attr][0]); + $group_sortnames[] = mb_strtolower($ldap_data[$i][$sort_attr][0]); } // recursive call can exit here - if ($vlv_page > 0) { + if ($vlv_page > 0) return $groups; - } // call recursively until we have fetched all groups - while ($this->prop['groups']['vlv'] && $group_count == $page_size) { - $next_page = $this->_fetch_groups(++$vlv_page); - $groups = array_merge($groups, $next_page); + while ($vlv_active && $group_count == $page_size) + { + $next_page = $this->_fetch_groups(++$vlv_page); + $groups = array_merge($groups, $next_page); $group_count = count($next_page); } // when using VLV the list of groups is already sorted - if (!$this->prop['groups']['vlv']) { + if (!$this->prop['groups']['vlv']) array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups); - } // cache this - if ($this->cache) { - $this->cache->set('groups', $groups); - } + $this->cache->set('groups', $groups); return $groups; } /** - * Fetch a group entry from LDAP and save in local cache - */ - private function get_group_entry($group_id) - { - $group_cache = $this->_fetch_groups(); - - // add group record to cache if it isn't yet there - if (!isset($group_cache[$group_id])) { - $name_attr = $this->prop['groups']['name_attr']; - $dn = self::dn_decode($group_id); - - if ($list = $this->ldap->read_entries($dn, '(objectClass=*)', array('dn','objectClass','member','uniqueMember','memberURL',$name_attr,$this->fieldmap['email']))) { - $entry = $list[0]; - $group_name = is_array($entry[$name_attr]) ? $entry[$name_attr][0] : $entry[$name_attr]; - $group_cache[$group_id]['ID'] = $group_id; - $group_cache[$group_id]['dn'] = $dn; - $group_cache[$group_id]['name'] = $group_name; - $group_cache[$group_id]['member_attr'] = $this->get_group_member_attr($entry['objectclass']); - } - else { - $group_cache[$group_id] = false; - } - - if ($this->cache) { - $this->cache->set('groups', $group_cache); - } - } - - return $group_cache[$group_id]; - } - - /** * Get group properties such as name and email address(es) * * @param string Group identifier @@ -1703,7 +1834,10 @@ class rcube_ldap extends rcube_addressbook */ function get_group($group_id) { - $group_data = $this->get_group_entry($group_id); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); + + $group_data = $group_cache[$group_id]; unset($group_data['dn'], $group_data['member_attr']); return $group_data; @@ -1717,24 +1851,24 @@ class rcube_ldap extends rcube_addressbook */ function create_group($group_name) { - $new_dn = 'cn=' . rcube_ldap_generic::quote_string($group_name, true) . ',' . $this->groups_base_dn; - $new_gid = self::dn_encode($new_dn); + $base_dn = $this->groups_base_dn; + $new_dn = "cn=$group_name,$base_dn"; + $new_gid = self::dn_encode($group_name); $member_attr = $this->get_group_member_attr(); - $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; - $new_entry = array( + $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; + + $new_entry = array( 'objectClass' => $this->prop['groups']['object_classes'], $name_attr => $group_name, $member_attr => '', ); - if (!$this->ldap->add($new_dn, $new_entry)) { + if (!$this->ldap_add($new_dn, $new_entry)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } - if ($this->cache) { - $this->cache->remove('groups'); - } + $this->cache->remove('groups'); return array('id' => $new_gid, 'name' => $group_name); } @@ -1747,18 +1881,19 @@ class rcube_ldap extends rcube_addressbook */ function delete_group($group_id) { - $group_cache = $this->_fetch_groups(); - $del_dn = $group_cache[$group_id]['dn']; + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); - if (!$this->ldap->delete($del_dn)) { + $base_dn = $this->groups_base_dn; + $group_name = $group_cache[$group_id]['name']; + $del_dn = "cn=$group_name,$base_dn"; + + if (!$this->ldap_delete($del_dn)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } - if ($this->cache) { - unset($group_cache[$group_id]); - $this->cache->set('groups', $group_cache); - } + $this->cache->remove('groups'); return true; } @@ -1773,19 +1908,21 @@ class rcube_ldap extends rcube_addressbook */ function rename_group($group_id, $new_name, &$new_gid) { - $group_cache = $this->_fetch_groups(); - $old_dn = $group_cache[$group_id]['dn']; - $new_rdn = "cn=" . rcube_ldap_generic::quote_string($new_name, true); - $new_gid = self::dn_encode($new_rdn . ',' . $this->groups_base_dn); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); + + $base_dn = $this->groups_base_dn; + $group_name = $group_cache[$group_id]['name']; + $old_dn = "cn=$group_name,$base_dn"; + $new_rdn = "cn=$new_name"; + $new_gid = self::dn_encode($new_name); - if (!$this->ldap->rename($old_dn, $new_rdn, null, true)) { + if (!$this->ldap_rename($old_dn, $new_rdn, null, true)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return false; } - if ($this->cache) { - $this->cache->remove('groups'); - } + $this->cache->remove('groups'); return $new_name; } @@ -1800,27 +1937,27 @@ class rcube_ldap extends rcube_addressbook */ function add_to_group($group_id, $contact_ids) { - $group_cache = $this->_fetch_groups(); - $member_attr = $group_cache[$group_id]['member_attr']; - $group_dn = $group_cache[$group_id]['dn']; - $new_attrs = array(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); - if (!is_array($contact_ids)) { + if (!is_array($contact_ids)) $contact_ids = explode(',', $contact_ids); - } - foreach ($contact_ids as $id) { + $base_dn = $this->groups_base_dn; + $group_name = $group_cache[$group_id]['name']; + $member_attr = $group_cache[$group_id]['member_attr']; + $group_dn = "cn=$group_name,$base_dn"; + $new_attrs = array(); + + foreach ($contact_ids as $id) $new_attrs[$member_attr][] = self::dn_decode($id); - } - if (!$this->ldap->mod_add($group_dn, $new_attrs)) { + if (!$this->ldap_mod_add($group_dn, $new_attrs)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return 0; } - if ($this->cache) { - $this->cache->remove('groups'); - } + $this->cache->remove('groups'); return count($new_attrs[$member_attr]); } @@ -1835,27 +1972,27 @@ class rcube_ldap extends rcube_addressbook */ function remove_from_group($group_id, $contact_ids) { - $group_cache = $this->_fetch_groups(); - $member_attr = $group_cache[$group_id]['member_attr']; - $group_dn = $group_cache[$group_id]['dn']; - $del_attrs = array(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); - if (!is_array($contact_ids)) { + if (!is_array($contact_ids)) $contact_ids = explode(',', $contact_ids); - } - foreach ($contact_ids as $id) { + $base_dn = $this->groups_base_dn; + $group_name = $group_cache[$group_id]['name']; + $member_attr = $group_cache[$group_id]['member_attr']; + $group_dn = "cn=$group_name,$base_dn"; + $del_attrs = array(); + + foreach ($contact_ids as $id) $del_attrs[$member_attr][] = self::dn_decode($id); - } - if (!$this->ldap->mod_del($group_dn, $del_attrs)) { + if (!$this->ldap_mod_del($group_dn, $del_attrs)) { $this->set_error(self::ERROR_SAVING, 'errorsaving'); return 0; } - if ($this->cache) { - $this->cache->remove('groups'); - } + $this->cache->remove('groups'); return count($del_attrs[$member_attr]); } @@ -1870,63 +2007,206 @@ class rcube_ldap extends rcube_addressbook */ function get_record_groups($contact_id) { - if (!$this->groups) { + if (!$this->groups) return array(); - } $base_dn = $this->groups_base_dn; $contact_dn = self::dn_decode($contact_id); $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; $member_attr = $this->get_group_member_attr(); $add_filter = ''; - if ($member_attr != 'member' && $member_attr != 'uniqueMember') $add_filter = "($member_attr=$contact_dn)"; $filter = strtr("(|(member=$contact_dn)(uniqueMember=$contact_dn)$add_filter)", array('\\' => '\\\\')); - $ldap_data = $this->ldap->search($base_dn, $filter, 'sub', array('dn', $name_attr)); - if ($res === false) { + $this->_debug("C: Search [$filter][dn: $base_dn]"); + + $res = @ldap_search($this->conn, $base_dn, $filter, array($name_attr)); + if ($res === false) + { + $this->_debug("S: ".ldap_error($this->conn)); return array(); } + $ldap_data = ldap_get_entries($this->conn, $res); + $this->_debug("S: ".ldap_count_entries($this->conn, $res)." record(s)"); $groups = array(); - foreach ($ldap_data as $entry) { - if (!$entry['dn']) - $entry['dn'] = $ldap_data->get_dn(); - $group_name = $entry[$name_attr][0]; - $group_id = self::dn_encode($entry['dn']); - $groups[$group_id] = $group_name; + for ($i=0; $i<$ldap_data["count"]; $i++) + { + $group_name = $ldap_data[$i][$name_attr][0]; + $group_id = self::dn_encode($group_name); + $groups[$group_id] = $group_id; } - return $groups; } /** * Detects group member attribute name */ - private function get_group_member_attr($object_classes = array(), $default = 'member') + private function get_group_member_attr($object_classes = array()) { if (empty($object_classes)) { $object_classes = $this->prop['groups']['object_classes']; } - if (!empty($object_classes)) { foreach ((array)$object_classes as $oc) { - if ($attr = self::$group_types[strtolower($oc)]) { - return $attr; + switch (strtolower($oc)) { + case 'group': + case 'groupofnames': + case 'kolabgroupofnames': + $member_attr = 'member'; + break; + + case 'groupofuniquenames': + case 'kolabgroupofuniquenames': + $member_attr = 'uniqueMember'; + break; } } } + if (!empty($member_attr)) { + return $member_attr; + } + if (!empty($this->prop['groups']['member_attr'])) { return $this->prop['groups']['member_attr']; } - return $default; + return 'member'; } /** + * Generate BER encoded string for Virtual List View option + * + * @param integer List offset (first record) + * @param integer Records per page + * @return string BER encoded option value + */ + private function _vlv_ber_encode($offset, $rpp, $search = '') + { + # this string is ber-encoded, php will prefix this value with: + # 04 (octet string) and 10 (length of 16 bytes) + # the code behind this string is broken down as follows: + # 30 = ber sequence with a length of 0e (14) bytes following + # 02 = type integer (in two's complement form) with 2 bytes following (beforeCount): 01 00 (ie 0) + # 02 = type integer (in two's complement form) with 2 bytes following (afterCount): 01 18 (ie 25-1=24) + # a0 = type context-specific/constructed with a length of 06 (6) bytes following + # 02 = type integer with 2 bytes following (offset): 01 01 (ie 1) + # 02 = type integer with 2 bytes following (contentCount): 01 00 + + # whith a search string present: + # 81 = type context-specific/constructed with a length of 04 (4) bytes following (the length will change here) + # 81 indicates a user string is present where as a a0 indicates just a offset search + # 81 = type context-specific/constructed with a length of 06 (6) bytes following + + # the following info was taken from the ISO/IEC 8825-1:2003 x.690 standard re: the + # encoding of integer values (note: these values are in + # two-complement form so since offset will never be negative bit 8 of the + # leftmost octet should never by set to 1): + # 8.3.2: If the contents octets of an integer value encoding consist + # of more than one octet, then the bits of the first octet (rightmost) and bit 8 + # of the second (to the left of first octet) octet: + # a) shall not all be ones; and + # b) shall not all be zero + + if ($search) + { + $search = preg_replace('/[^-[:alpha:] ,.()0-9]+/', '', $search); + $ber_val = self::_string2hex($search); + $str = self::_ber_addseq($ber_val, '81'); + } + else + { + # construct the string from right to left + $str = "020100"; # contentCount + + $ber_val = self::_ber_encode_int($offset); // returns encoded integer value in hex format + + // calculate octet length of $ber_val + $str = self::_ber_addseq($ber_val, '02') . $str; + + // now compute length over $str + $str = self::_ber_addseq($str, 'a0'); + } + + // now tack on records per page + $str = "020100" . self::_ber_addseq(self::_ber_encode_int($rpp-1), '02') . $str; + + // now tack on sequence identifier and length + $str = self::_ber_addseq($str, '30'); + + return pack('H'.strlen($str), $str); + } + + + /** + * create ber encoding for sort control + * + * @param array List of cols to sort by + * @return string BER encoded option value + */ + private function _sort_ber_encode($sortcols) + { + $str = ''; + foreach (array_reverse((array)$sortcols) as $col) { + $ber_val = self::_string2hex($col); + + # 30 = ber sequence with a length of octet value + # 04 = octet string with a length of the ascii value + $oct = self::_ber_addseq($ber_val, '04'); + $str = self::_ber_addseq($oct, '30') . $str; + } + + // now tack on sequence identifier and length + $str = self::_ber_addseq($str, '30'); + + return pack('H'.strlen($str), $str); + } + + /** + * Add BER sequence with correct length and the given identifier + */ + private static function _ber_addseq($str, $identifier) + { + $len = dechex(strlen($str)/2); + if (strlen($len) % 2 != 0) + $len = '0'.$len; + + return $identifier . $len . $str; + } + + /** + * Returns BER encoded integer value in hex format + */ + private static function _ber_encode_int($offset) + { + $val = dechex($offset); + $prefix = ''; + + // check if bit 8 of high byte is 1 + if (preg_match('/^[89abcdef]/', $val)) + $prefix = '00'; + + if (strlen($val)%2 != 0) + $prefix .= '0'; + + return $prefix . $val; + } + + /** + * Returns ascii string encoded in hex + */ + private static function _string2hex($str) + { + $hex = ''; + for ($i=0; $i < strlen($str); $i++) + $hex .= dechex(ord($str[$i])); + return $hex; + } + + /** * HTML-safe DN string encoding * * @param string $str DN string @@ -1953,4 +2233,130 @@ class rcube_ldap extends rcube_addressbook return base64_decode($str); } + /** + * Wrapper for ldap_add() + */ + protected function ldap_add($dn, $entry) + { + $this->_debug("C: Add [dn: $dn]: ".print_r($entry, true)); + + $res = ldap_add($this->conn, $dn, $entry); + if ($res === false) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_delete() + */ + protected function ldap_delete($dn) + { + $this->_debug("C: Delete [dn: $dn]"); + + $res = ldap_delete($this->conn, $dn); + if ($res === false) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_mod_replace() + */ + protected function ldap_mod_replace($dn, $entry) + { + $this->_debug("C: Replace [dn: $dn]: ".print_r($entry, true)); + + if (!ldap_mod_replace($this->conn, $dn, $entry)) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_mod_add() + */ + protected function ldap_mod_add($dn, $entry) + { + $this->_debug("C: Add [dn: $dn]: ".print_r($entry, true)); + + if (!ldap_mod_add($this->conn, $dn, $entry)) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_mod_del() + */ + protected function ldap_mod_del($dn, $entry) + { + $this->_debug("C: Delete [dn: $dn]: ".print_r($entry, true)); + + if (!ldap_mod_del($this->conn, $dn, $entry)) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_rename() + */ + protected function ldap_rename($dn, $newrdn, $newparent = null, $deleteoldrdn = true) + { + $this->_debug("C: Rename [dn: $dn] [dn: $newrdn]"); + + if (!ldap_rename($this->conn, $dn, $newrdn, $newparent, $deleteoldrdn)) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + return true; + } + + /** + * Wrapper for ldap_list() + */ + protected function ldap_list($dn, $filter, $attrs = array('')) + { + $list = array(); + $this->_debug("C: List [dn: $dn] [{$filter}]"); + + if ($result = ldap_list($this->conn, $dn, $filter, $attrs)) { + $list = ldap_get_entries($this->conn, $result); + + if ($list === false) { + $this->_debug("S: ".ldap_error($this->conn)); + return array(); + } + + $count = $list['count']; + unset($list['count']); + + $this->_debug("S: $count record(s)"); + } + else { + $this->_debug("S: ".ldap_error($this->conn)); + } + + return $list; + } + } diff --git a/program/lib/Roundcube/rcube_ldap_generic.php b/program/lib/Roundcube/rcube_ldap_generic.php index 88378dc22..923a12a41 100644 --- a/program/lib/Roundcube/rcube_ldap_generic.php +++ b/program/lib/Roundcube/rcube_ldap_generic.php @@ -696,11 +696,17 @@ class rcube_ldap_generic * Turn an LDAP entry into a regular PHP array with attributes as keys. * * @param array $entry Attributes array as retrieved from ldap_get_attributes() or ldap_get_entries() + * * @return array Hash array with attributes as keys */ public static function normalize_entry($entry) { + if (!isset($entry['count'])) { + return $entry; + } + $rec = array(); + for ($i=0; $i < $entry['count']; $i++) { $attr = $entry[$i]; if ($entry[$attr]['count'] == 1) { diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 0d33ea44d..a8bcf6afc 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -168,11 +168,10 @@ class rcube_message * @param resource $fp File pointer to save the message part * @param boolean $skip_charset_conv Disables charset conversion * @param int $max_bytes Only read this number of bytes - * @param boolean $formatted Enables formatting of text/* parts bodies * * @return string Part content */ - public function get_part_content($mime_id, $fp = null, $skip_charset_conv = false, $max_bytes = 0, $formatted = true) + public function get_part_content($mime_id, $fp = null, $skip_charset_conv = false, $max_bytes = 0) { if ($part = $this->mime_parts[$mime_id]) { // stored in message structure (winmail/inline-uuencode) @@ -186,89 +185,47 @@ class rcube_message // get from IMAP $this->storage->set_folder($this->folder); - return $this->storage->get_message_part($this->uid, $mime_id, $part, - NULL, $fp, $skip_charset_conv, $max_bytes, $formatted); + return $this->storage->get_message_part($this->uid, $mime_id, $part, NULL, $fp, $skip_charset_conv, $max_bytes); } } /** - * Determine if the message contains a HTML part. This must to be - * a real part not an attachment (or its part) - * This must to be - * a real part not an attachment (or its part) + * Determine if the message contains a HTML part * - * @param bool $enriched Enables checking for text/enriched parts too + * @param bool $recursive Enables checking in all levels of the structure + * @param bool $enriched Enables checking for text/enriched parts too * * @return bool True if a HTML is available, False if not */ - function has_html_part($enriched = false) + function has_html_part($recursive = true, $enriched = false) { // check all message parts - foreach ($this->mime_parts as $part) { + foreach ($this->parts as $part) { if ($part->mimetype == 'text/html' || ($enriched && $part->mimetype == 'text/enriched')) { - // Skip if part is an attachment, don't use is_attachment() here - if ($part->filename) { - continue; - } - - $level = explode('.', $part->mime_id); - - // Check if the part belongs to higher-level's alternative/related - while (array_pop($level) !== null) { - if (!count($level)) { - return true; - } + // Level check, we'll skip e.g. HTML attachments + if (!$recursive) { + $level = explode('.', $part->mime_id); - $parent = $this->mime_parts[join('.', $level)]; - if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { - continue 2; + // Skip if part is an attachment + if ($this->is_attachment($part)) { + continue; } - } - if ($part->size) { - return true; - } - } - } - - return false; - } - - - /** - * Determine if the message contains a text/plain part. This must to be - * a real part not an attachment (or its part) - * - * @return bool True if a plain text part is available, False if not - */ - function has_text_part() - { - // check all message parts - foreach ($this->mime_parts as $part) { - if ($part->mimetype == 'text/plain') { - // Skip if part is an attachment, don't use is_attachment() here - if ($part->filename) { - continue; - } - - $level = explode('.', $part->mime_id); - - // Check if the part belongs to higher-level's alternative/related - while (array_pop($level) !== null) { - if (!count($level)) { - return true; - } + // Check if the part belongs to higher-level's alternative/related + while (array_pop($level) !== null) { + if (!count($level)) { + return true; + } - $parent = $this->mime_parts[join('.', $level)]; - if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { - continue 2; + $parent = $this->mime_parts[join('.', $level)]; + if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { + continue 2; + } } } - if ($part->size) { - return true; - } + return true; } } @@ -363,8 +320,8 @@ class rcube_message $mimetype = $structure->real_mimetype; // parse headers from message/rfc822 part - if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) { - list($headers, ) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); + if (!isset($structure->headers['subject'])) { + list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); $structure->headers = rcube_mime::parse_headers($headers); } } @@ -373,7 +330,7 @@ class rcube_message // show message headers if ($recursive && is_array($structure->headers) && - (isset($structure->headers['subject']) || $structure->headers['from'] || $structure->headers['to'])) { + ($structure->headers['subject'] || $structure->headers['from'] || $structure->headers['to'])) { $c = new stdClass; $c->type = 'headers'; $c->headers = $structure->headers; @@ -487,6 +444,14 @@ class rcube_message $this->parts[] = $c; } + // add html part as attachment + if ($html_part !== null && $structure->parts[$html_part] !== $print_part) { + $html_part = $structure->parts[$html_part]; + $html_part->mimetype = 'text/html'; + + $this->attachments[] = $html_part; + } + // add unsupported/unrecognized parts to attachments list if ($attach_part) { $this->attachments[] = $structure->parts[$attach_part]; @@ -571,6 +536,10 @@ class rcube_message if (!empty($mail_part->filename)) { $this->attachments[] = $mail_part; } + // list html part as attachment (here the part is most likely inside a multipart/related part) + else if ($this->parse_alternative && ($secondary_type == 'html' && !$this->opt['prefer_html'])) { + $this->attachments[] = $mail_part; + } } // part message/* else if ($primary_type == 'message') { diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 96a8eac61..323a5e900 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -637,7 +637,8 @@ class rcube_mime if ($nextChar === ' ' || $nextChar === $separator) { $afterNextChar = mb_substr($string, $width + 1, 1); - if ($afterNextChar === false) { + // Note: mb_substr() does never return False + if ($afterNextChar === false || $afterNextChar === '') { $subString .= $nextChar; } @@ -650,24 +651,23 @@ class rcube_mime $subString = mb_substr($subString, 0, $spacePos); $cutLength = $spacePos + 1; } - else if ($cut === false && $breakPos === false) { - $subString = $string; - $cutLength = null; - } else if ($cut === false) { $spacePos = mb_strpos($string, ' ', 0); - if ($spacePos !== false && $spacePos < $breakPos) { + if ($spacePos !== false && ($breakPos === false || $spacePos < $breakPos)) { $subString = mb_substr($string, 0, $spacePos); $cutLength = $spacePos + 1; } + else if ($breakPos === false) { + $subString = $string; + $cutLength = null; + } else { $subString = mb_substr($string, 0, $breakPos); $cutLength = $breakPos + 1; } } else { - $subString = mb_substr($subString, 0, $width); $cutLength = $width; } } @@ -708,20 +708,12 @@ class rcube_mime */ public static function file_content_type($path, $name, $failover = 'application/octet-stream', $is_stream = false, $skip_suffix = false) { - static $mime_ext = array(); - $mime_type = null; - $config = rcube::get_instance()->config; - $mime_magic = $config->get('mime_magic'); - - if (!$skip_suffix && empty($mime_ext)) { - foreach ($config->resolve_paths('mimetypes.php') as $fpath) { - $mime_ext = array_merge($mime_ext, (array) @include($fpath)); - } - } + $mime_magic = rcube::get_instance()->config->get('mime_magic'); + $mime_ext = $skip_suffix ? null : @include(RCUBE_CONFIG_DIR . '/mimetypes.php'); // use file name suffix with hard-coded mime-type map - if (!$skip_suffix && is_array($mime_ext) && $name) { + if (is_array($mime_ext) && $name) { if ($suffix = substr($name, strrpos($name, '.')+1)) { $mime_type = $mime_ext[strtolower($suffix)]; } @@ -826,9 +818,7 @@ class rcube_mime // fallback to some well-known types most important for daily emails if (empty($mime_types)) { - foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) { - $mime_extensions = array_merge($mime_extensions, (array) @include($fpath)); - } + $mime_extensions = (array) @include(RCUBE_CONFIG_DIR . '/mimetypes.php'); foreach ($mime_extensions as $ext => $mime) { $mime_types[$mime][] = $ext; diff --git a/program/lib/Roundcube/rcube_plugin.php b/program/lib/Roundcube/rcube_plugin.php index 3153a8410..34720cfd7 100644 --- a/program/lib/Roundcube/rcube_plugin.php +++ b/program/lib/Roundcube/rcube_plugin.php @@ -92,16 +92,6 @@ abstract class rcube_plugin abstract function init(); /** - * Provide information about this - * - * @return array Meta information about a plugin or false if not implemented - */ - public static function info() - { - return false; - } - - /** * Attempt to load the given plugin which is required for the current plugin * * @param string Plugin name @@ -227,7 +217,7 @@ abstract class rcube_plugin $rcube->load_language($lang, $add); // add labels to client - if ($add2client && method_exists($rcube->output, 'add_label')) { + if ($add2client) { if (is_array($add2client)) { $js_labels = array_map(array($this, 'label_map_callback'), $add2client); } @@ -240,24 +230,6 @@ abstract class rcube_plugin } /** - * Wrapper for add_label() adding the plugin ID as domain - */ - public function add_label() - { - $rcube = rcube::get_instance(); - - if (method_exists($rcube->output, 'add_label')) { - $args = func_get_args(); - if (count($args) == 1 && is_array($args[0])) { - $args = $args[0]; - } - - $args = array_map(array($this, 'label_map_callback'), $args); - $rcube->output->add_label($args); - } - } - - /** * Wrapper for rcube::gettext() adding the plugin ID as domain * * @param string $p Message identifier @@ -273,7 +245,7 @@ abstract class rcube_plugin /** * Register this plugin to be responsible for a specific task * - * @param string $task Task name (only characters [a-z0-9_-] are allowed) + * @param string $task Task name (only characters [a-z0-9_.-] are allowed) */ public function register_task($task) { @@ -408,10 +380,6 @@ abstract class rcube_plugin */ private function label_map_callback($key) { - if (strpos($key, $this->ID.'.') === 0) { - return $key; - } - return $this->ID.'.'.$key; } } diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index 33f04eaa5..c9602d912 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -35,8 +35,9 @@ class rcube_plugin_api public $url = 'plugins/'; public $task = ''; public $output; - public $handlers = array(); - public $allowed_prefs = array(); + public $handlers = array(); + public $allowed_prefs = array(); + public $allowed_session_prefs = array(); protected $plugins = array(); protected $tasks = array(); @@ -228,119 +229,6 @@ class rcube_plugin_api } /** - * Get information about a specific plugin. - * This is either provided my a plugin's info() method or extracted from a package.xml or a composer.json file - * - * @param string Plugin name - * @return array Meta information about a plugin or False if plugin was not found - */ - public function get_info($plugin_name) - { - static $composer_lock, $license_uris = array( - 'Apache' => 'http://www.apache.org/licenses/LICENSE-2.0.html', - 'Apache-2' => 'http://www.apache.org/licenses/LICENSE-2.0.html', - 'Apache-1' => 'http://www.apache.org/licenses/LICENSE-1.0', - 'Apache-1.1' => 'http://www.apache.org/licenses/LICENSE-1.1', - 'GPL' => 'http://www.gnu.org/licenses/gpl.html', - 'GPLv2' => 'http://www.gnu.org/licenses/gpl-2.0.html', - 'GPL-2.0' => 'http://www.gnu.org/licenses/gpl-2.0.html', - 'GPLv3' => 'http://www.gnu.org/licenses/gpl-3.0.html', - 'GPL-3.0' => 'http://www.gnu.org/licenses/gpl-3.0.html', - 'GPL-3.0+' => 'http://www.gnu.org/licenses/gpl.html', - 'GPL-2.0+' => 'http://www.gnu.org/licenses/gpl.html', - 'LGPL' => 'http://www.gnu.org/licenses/lgpl.html', - 'LGPLv2' => 'http://www.gnu.org/licenses/lgpl-2.0.html', - 'LGPLv2.1' => 'http://www.gnu.org/licenses/lgpl-2.1.html', - 'LGPLv3' => 'http://www.gnu.org/licenses/lgpl.html', - 'LGPL-2.0' => 'http://www.gnu.org/licenses/lgpl-2.0.html', - 'LGPL-2.1' => 'http://www.gnu.org/licenses/lgpl-2.1.html', - 'LGPL-3.0' => 'http://www.gnu.org/licenses/lgpl.html', - 'LGPL-3.0+' => 'http://www.gnu.org/licenses/lgpl.html', - 'BSD' => 'http://opensource.org/licenses/bsd-license.html', - 'BSD-2-Clause' => 'http://opensource.org/licenses/BSD-2-Clause', - 'BSD-3-Clause' => 'http://opensource.org/licenses/BSD-3-Clause', - 'FreeBSD' => 'http://opensource.org/licenses/BSD-2-Clause', - 'MIT' => 'http://www.opensource.org/licenses/mit-license.php', - 'PHP' => 'http://opensource.org/licenses/PHP-3.0', - 'PHP-3' => 'http://www.php.net/license/3_01.txt', - 'PHP-3.0' => 'http://www.php.net/license/3_0.txt', - 'PHP-3.01' => 'http://www.php.net/license/3_01.txt', - ); - - $dir = dir($this->dir); - $fn = unslashify($dir->path) . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php'; - $info = false; - - if (!class_exists($plugin_name)) - include($fn); - - if (class_exists($plugin_name)) - $info = $plugin_name::info(); - - // fall back to composer.json file - if (!$info) { - $composer = INSTALL_PATH . "/plugins/$plugin_name/composer.json"; - if (file_exists($composer) && ($json = @json_decode(file_get_contents($composer), true))) { - list($info['vendor'], $info['name']) = explode('/', $json['name']); - $info['license'] = $json['license']; - if ($license_uri = $license_uris[$info['license']]) - $info['license_uri'] = $license_uri; - } - - // read local composer.lock file (once) - if (!isset($composer_lock)) { - $composer_lock = @json_decode(@file_get_contents(INSTALL_PATH . "/composer.lock"), true); - if ($composer_lock['packages']) { - foreach ($composer_lock['packages'] as $i => $package) { - $composer_lock['installed'][$package['name']] = $package; - } - } - } - - // load additional information from local composer.lock file - if ($lock = $composer_lock['installed'][$json['name']]) { - $info['version'] = $lock['version']; - $info['uri'] = $lock['homepage'] ? $lock['homepage'] : $lock['source']['uri']; - $info['src_uri'] = $lock['dist']['uri'] ? $lock['dist']['uri'] : $lock['source']['uri']; - } - } - - // fall back to package.xml file - if (!$info) { - $package = INSTALL_PATH . "/plugins/$plugin_name/package.xml"; - if (file_exists($package) && ($file = file_get_contents($package))) { - $doc = new DOMDocument(); - $doc->loadXML($file); - $xpath = new DOMXPath($doc); - $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); - - // XPaths of plugin metadata elements - $metadata = array( - 'name' => 'string(//rc:package/rc:name)', - 'version' => 'string(//rc:package/rc:version/rc:release)', - 'license' => 'string(//rc:package/rc:license)', - 'license_uri' => 'string(//rc:package/rc:license/@uri)', - 'src_uri' => 'string(//rc:package/rc:srcuri)', - 'uri' => 'string(//rc:package/rc:uri)', - ); - - foreach ($metadata as $key => $path) { - $info[$key] = $xpath->evaluate($path); - } - - // dependent required plugins (can be used, but not included in config) - $deps = $xpath->evaluate('//rc:package/rc:dependencies/rc:required/rc:package/rc:name'); - for ($i = 0; $i < $deps->length; $i++) { - $dn = $deps->item($i)->nodeValue; - $info['requires'][] = $dn; - } - } - } - - return $info; - } - - /** * Allows a plugin object to register a callback for a certain hook * * @param string $hook Hook name @@ -491,7 +379,7 @@ class rcube_plugin_api /** * Register this plugin to be responsible for a specific task * - * @param string $task Task name (only characters [a-z0-9_-] are allowed) + * @param string $task Task name (only characters [a-z0-9_.-] are allowed) * @param string $owner Plugin name that registers this action */ public function register_task($task, $owner) @@ -501,7 +389,7 @@ class rcube_plugin_api return true; } - if ($task != asciiwords($task, true)) { + if ($task != asciiwords($task)) { rcube::raise_error(array('code' => 526, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid task name: $task." diff --git a/program/lib/Roundcube/rcube_result_set.php b/program/lib/Roundcube/rcube_result_set.php index a4b070e28..1391e5e4b 100644 --- a/program/lib/Roundcube/rcube_result_set.php +++ b/program/lib/Roundcube/rcube_result_set.php @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2013, The Roundcube Dev Team | + | Copyright (C) 2006-2011, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -17,22 +17,20 @@ */ /** - * Roundcube result set class - * + * Roundcube result set class. * Representing an address directory result set. - * Implenets Iterator and thus be used in foreach() loops. * * @package Framework * @subpackage Addressbook */ -class rcube_result_set implements Iterator +class rcube_result_set { - public $count = 0; - public $first = 0; - public $searchonly = false; - public $records = array(); + var $count = 0; + var $first = 0; + var $current = 0; + var $searchonly = false; + var $records = array(); - private $current = 0; function __construct($c=0, $f=0) { @@ -53,39 +51,18 @@ class rcube_result_set implements Iterator function first() { $this->current = 0; - return $this->records[$this->current]; - } - - function seek($i) - { - $this->current = $i; - } - - /*** PHP 5 Iterator interface ***/ - - function rewind() - { - $this->current = 0; - } - - function current() - { - return $this->records[$this->current]; - } - - function key() - { - return $this->current; + return $this->records[$this->current++]; } + // alias for iterate() function next() { return $this->iterate(); } - function valid() + function seek($i) { - return isset($this->records[$this->current]); + $this->current = $i; } } diff --git a/program/lib/Roundcube/rcube_session.php b/program/lib/Roundcube/rcube_session.php index 67072df41..ee4db6e86 100644 --- a/program/lib/Roundcube/rcube_session.php +++ b/program/lib/Roundcube/rcube_session.php @@ -32,7 +32,6 @@ class rcube_session private $ip; private $start; private $changed; - private $time_diff = 0; private $reloaded = false; private $unsets = array(); private $gc_handlers = array(); @@ -43,7 +42,6 @@ class rcube_session private $secret = ''; private $ip_check = false; private $logging = false; - private $storage; private $memcache; @@ -54,21 +52,18 @@ class rcube_session { $this->db = $db; $this->start = microtime(true); - $this->ip = rcube_utils::remote_addr(); + $this->ip = $_SERVER['REMOTE_ADDR']; $this->logging = $config->get('log_session', false); $lifetime = $config->get('session_lifetime', 1) * 60; $this->set_lifetime($lifetime); // use memcache backend - $this->storage = $config->get('session_storage', 'db'); - if ($this->storage == 'memcache') { + if ($config->get('session_storage', 'db') == 'memcache') { $this->memcache = rcube::get_instance()->get_memcache(); // set custom functions for PHP session management if memcache is available if ($this->memcache) { - ini_set('session.serialize_handler', 'php'); - session_set_save_handler( array($this, 'open'), array($this, 'close'), @@ -84,9 +79,7 @@ class rcube_session true, true); } } - else if ($this->storage != 'php') { - ini_set('session.serialize_handler', 'php'); - + else { // set custom functions for PHP session management session_set_save_handler( array($this, 'open'), @@ -94,23 +87,7 @@ class rcube_session array($this, 'db_read'), array($this, 'db_write'), array($this, 'db_destroy'), - array($this, 'gc')); - } - } - - - /** - * Wrapper for session_start() - */ - public function start() - { - session_start(); - - // copy some session properties to object vars - if ($this->storage == 'php') { - $this->key = session_id(); - $this->ip = $_SESSION['__IP']; - $this->changed = $_SESSION['__MTIME']; + array($this, 'db_gc')); } } @@ -139,25 +116,6 @@ class rcube_session /** - * Wrapper for session_write_close() - */ - public function write_close() - { - if ($this->storage == 'php') { - $_SESSION['__IP'] = $this->ip; - $_SESSION['__MTIME'] = time(); - } - - session_write_close(); - - // write_close() is called on script shutdown, see rcube::shutdown() - // execute cleanup functionality if enabled by session gc handler - // we do this after closing the session for better performance - $this->gc_shutdown(); - } - - - /** * Read session data from database * * @param string Session ID @@ -167,16 +125,14 @@ class rcube_session public function db_read($key) { $sql_result = $this->db->query( - "SELECT vars, ip, changed, " . $this->db->now() . " AS ts" - . " FROM " . $this->db->table_name('session') - . " WHERE sess_id = ?", $key); + "SELECT vars, ip, changed FROM ".$this->db->table_name('session') + ." WHERE sess_id = ?", $key); if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { - $this->time_diff = time() - strtotime($sql_arr['ts']); - $this->changed = strtotime($sql_arr['changed']); - $this->ip = $sql_arr['ip']; - $this->vars = base64_decode($sql_arr['vars']); - $this->key = $key; + $this->changed = strtotime($sql_arr['changed']); + $this->ip = $sql_arr['ip']; + $this->vars = base64_decode($sql_arr['vars']); + $this->key = $key; return !empty($this->vars) ? (string) $this->vars : ''; } @@ -196,9 +152,8 @@ class rcube_session */ public function db_write($key, $vars) { - $now = $this->db->now(); - $table = $this->db->table_name('session'); - $ts = microtime(true); + $ts = microtime(true); + $now = $this->db->fromunixtime((int)$ts); // no session row in DB (db_read() returns false) if (!$this->key) { @@ -216,19 +171,22 @@ class rcube_session $newvars = $this->_fixvars($vars, $oldvars); if ($newvars !== $oldvars) { - $this->db->query("UPDATE $table " - . "SET changed = $now, vars = ? WHERE sess_id = ?", - base64_encode($newvars), $key); + $this->db->query( + sprintf("UPDATE %s SET vars=?, changed=%s WHERE sess_id=?", + $this->db->table_name('session'), $now), + base64_encode($newvars), $key); } - else if ($ts - $this->changed + $this->time_diff > $this->lifetime / 2) { - $this->db->query("UPDATE $table SET changed = $now" - . " WHERE sess_id = ?", $key); + else if ($ts - $this->changed > $this->lifetime / 2) { + $this->db->query("UPDATE ".$this->db->table_name('session') + ." SET changed=$now WHERE sess_id=?", $key); } } else { - $this->db->query("INSERT INTO $table (sess_id, vars, ip, created, changed)" - . " VALUES (?, ?, ?, $now, $now)", - $key, base64_encode($vars), (string)$this->ip); + $this->db->query( + sprintf("INSERT INTO %s (sess_id, vars, ip, created, changed) ". + "VALUES (?, ?, ?, %s, %s)", + $this->db->table_name('session'), $now, $now), + $key, base64_encode($vars), (string)$this->ip); } return true; @@ -288,6 +246,25 @@ class rcube_session /** + * Garbage collecting function + * + * @param string Session lifetime in seconds + * @return boolean True on success + */ + public function db_gc($maxlifetime) + { + // just delete all expired sessions + $this->db->query( + sprintf("DELETE FROM %s WHERE changed < %s", + $this->db->table_name('session'), $this->db->fromunixtime(time() - $maxlifetime))); + + $this->gc(); + + return true; + } + + + /** * Read session data from memcache * * @param string Session ID @@ -363,11 +340,11 @@ class rcube_session /** * Execute registered garbage collector routines */ - public function gc($maxlifetime) + public function gc() { - // move gc execution to the script shutdown function - // see rcube::shutdown() and rcube_session::write_close() - return $this->gc_enabled = $maxlifetime; + foreach ($this->gc_handlers as $fct) { + call_user_func($fct); + } } @@ -389,25 +366,6 @@ class rcube_session /** - * Garbage collector handler to run on script shutdown - */ - protected function gc_shutdown() - { - if ($this->gc_enabled) { - // just delete all expired sessions - if ($this->storage == 'db') { - $this->db->query("DELETE FROM " . $this->db->table_name('session') - . " WHERE changed < " . $this->db->now(-$this->gc_enabled)); - } - - foreach ($this->gc_handlers as $fct) { - call_user_func($fct); - } - } - } - - - /** * Generate and set new session id * * @param boolean $destroy If enabled the current session will be destroyed @@ -480,7 +438,7 @@ class rcube_session public function kill() { $this->vars = null; - $this->ip = rcube_utils::remote_addr(); // update IP (might have changed) + $this->ip = $_SERVER['REMOTE_ADDR']; // update IP (might have changed) $this->destroy(session_id()); rcube_utils::setcookie($this->cookiename, '-del-', time() - 60); } @@ -694,10 +652,10 @@ class rcube_session function check_auth() { $this->cookie = $_COOKIE[$this->cookiename]; - $result = $this->ip_check ? rcube_utils::remote_addr() == $this->ip : true; + $result = $this->ip_check ? $_SERVER['REMOTE_ADDR'] == $this->ip : true; if (!$result) { - $this->log("IP check failed for " . $this->key . "; expected " . $this->ip . "; got " . rcube_utils::remote_addr()); + $this->log("IP check failed for " . $this->key . "; expected " . $this->ip . "; got " . $_SERVER['REMOTE_ADDR']); } if ($result && $this->_mkcookie($this->now) != $this->cookie) { diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 60b1389ea..201e8269e 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -33,8 +33,6 @@ class rcube_smtp // define headers delimiter const SMTP_MIME_CRLF = "\r\n"; - const DEBUG_LINE_LENGTH = 4098; // 4KB + 2B for \r\n - /** * SMTP Connection and authentication @@ -329,12 +327,6 @@ class rcube_smtp */ public function debug_handler(&$smtp, $message) { - if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) { - $diff = $len - self::DEBUG_LINE_LENGTH; - $message = substr($message, 0, self::DEBUG_LINE_LENGTH) - . "... [truncated $diff bytes]"; - } - rcube::write_log('smtp', preg_replace('/\r\n$/', '', $message)); } @@ -441,9 +433,9 @@ class rcube_smtp $recipients = rcube_utils::explode_quoted_string(',', $recipients); reset($recipients); - foreach ($recipients as $recipient) { + while (list($k, $recipient) = each($recipients)) { $a = rcube_utils::explode_quoted_string(' ', $recipient); - foreach ($a as $word) { + while (list($k2, $word) = each($a)) { if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') { $word = preg_replace('/^<|>$/', '', trim($word)); if (in_array($word, $addresses) === false) { diff --git a/program/lib/Roundcube/rcube_spellcheck_atd.php b/program/lib/Roundcube/rcube_spellcheck_atd.php new file mode 100644 index 000000000..9f073f56f --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_atd.php @@ -0,0 +1,204 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Spellchecking backend implementation for afterthedeadline services | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Spellchecking backend implementation to work with an After the Deadline service + * See http://www.afterthedeadline.com/ for more information + * + * @package Framework + * @subpackage Utils + */ +class rcube_spellcheck_atd extends rcube_spellcheck_engine +{ + const SERVICE_HOST = 'service.afterthedeadline.com'; + const SERVICE_PORT = 80; + + private $matches = array(); + private $content; + private $langhosts = array( + 'fr' => 'fr.', + 'de' => 'de.', + 'pt' => 'pt.', + 'es' => 'es.', + ); + + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $langs = array_values($this->langhosts); + $langs[] = 'en'; + return $langs; + } + + /** + * Set content and check spelling + * + * @see rcube_spellcheck_engine::check() + */ + function check($text) + { + $this->content = $text; + + // spell check uri is configured + $rcube = rcube::get_instance(); + $url = $rcube->config->get('spellcheck_uri'); + $key = $rcube->config->get('spellcheck_atd_key'); + + if ($url) { + $a_uri = parse_url($url); + $ssl = ($a_uri['scheme'] == 'https' || $a_uri['scheme'] == 'ssl'); + $port = $a_uri['port'] ? $a_uri['port'] : ($ssl ? 443 : 80); + $host = ($ssl ? 'ssl://' : '') . $a_uri['host']; + $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; + } + else { + $host = self::SERVICE_HOST; + $port = self::SERVICE_PORT; + $path = '/checkDocument'; + + // prefix host for other languages than 'en' + $lang = substr($this->lang, 0, 2); + if ($this->langhosts[$lang]) + $host = $this->langhosts[$lang] . $host; + } + + $postdata = 'data=' . urlencode($text); + + if (!empty($key)) + $postdata .= '&key=' . urlencode($key); + + $response = $headers = ''; + $in_header = true; + if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) { + $out = "POST $path HTTP/1.0\r\n"; + $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n"; + $out .= "Content-Length: " . strlen($postdata) . "\r\n"; + $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $out .= "Connection: Close\r\n\r\n"; + $out .= $postdata; + fwrite($fp, $out); + + while (!feof($fp)) { + if ($in_header) { + $line = fgets($fp, 512); + $headers .= $line; + if (trim($line) == '') + $in_header = false; + } + else { + $response .= fgets($fp, 1024); + } + } + fclose($fp); + } + + // parse HTTP response headers + if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $headers, $m)) { + $http_status = $m[1]; + if ($http_status != '200') + $this->error = 'HTTP ' . $m[1] . $m[2]; + } + + if (!$response) { + $this->error = "Empty result from spelling engine"; + } + + try { + $result = new SimpleXMLElement($response); + } + catch (Exception $e) { + $thid->error = "Unexpected response from server: " . $store; + return array(); + } + + foreach ($result->error as $error) { + if (strval($error->type) == 'spelling') { + $word = strval($error->string); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + continue; + } + + $prefix = strval($error->precontext); + $start = $prefix ? mb_strpos($text, $prefix) : 0; + $pos = mb_strpos($text, $word, $start); + $len = mb_strlen($word); + $num = 0; + + $match = array($word, $pos, $len, null, array()); + foreach ($error->suggestions->option as $option) { + $match[4][] = strval($option); + if (++$num == self::MAX_SUGGESTIONS) + break; + } + $matches[] = $match; + } + } + + $this->matches = $matches; + return $matches; + } + + /** + * Returns suggestions for the specified word + * + * @see rcube_spellcheck_engine::get_words() + */ + function get_suggestions($word) + { + $matches = $word ? $this->check($word) : $this->matches; + + if ($matches[0][4]) { + return $matches[0][4]; + } + + return array(); + } + + /** + * Returns misspelled words + * + * @see rcube_spellcheck_engine::get_suggestions() + */ + function get_words($text = null) + { + if ($text) { + $matches = $this->check($text); + } + else { + $matches = $this->matches; + $text = $this->content; + } + + $result = array(); + + foreach ($matches as $m) { + $result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET); + } + + return $result; + } + +} + diff --git a/program/lib/Roundcube/rcube_spellcheck_enchant.php b/program/lib/Roundcube/rcube_spellcheck_enchant.php new file mode 100644 index 000000000..14d6fff46 --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_enchant.php @@ -0,0 +1,182 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2011-2013, Kolab Systems AG | + | Copyright (C) 20011-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Spellchecking backend implementation to work with Enchant | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Spellchecking backend implementation to work with Pspell + * + * @package Framework + * @subpackage Utils + */ +class rcube_spellcheck_enchant extends rcube_spellcheck_engine +{ + private $enchant_broker; + private $enchant_dictionary; + private $matches = array(); + + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $this->init(); + + $langs = array(); + $dicts = enchant_broker_list_dicts($this->enchant_broker); + foreach ($dicts as $dict) { + $langs[] = preg_replace('/-.*$/', '', $dict['lang_tag']); + } + + return array_unique($langs); + } + + /** + * Initializes Enchant dictionary + */ + private function init() + { + if (!$this->enchant_broker) { + if (!extension_loaded('enchant')) { + $this->error = "Enchant extension not available"; + return; + } + + $this->enchant_broker = enchant_broker_init(); + } + + if (!enchant_broker_dict_exists($this->enchant_broker, $this->lang)) { + $this->error = "Unable to load dictionary for selected language using Enchant"; + return; + } + + $this->enchant_dictionary = enchant_broker_request_dict($this->enchant_broker, $this->lang); + } + + /** + * Set content and check spelling + * + * @see rcube_spellcheck_engine::check() + */ + function check($text) + { + $this->init(); + + if (!$this->enchant_dictionary) { + return array(); + } + + // tokenize + $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); + + $diff = 0; + $matches = array(); + + foreach ($text as $w) { + $word = trim($w[0]); + $pos = $w[1] - $diff; + $len = mb_strlen($word); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + } + else if (!enchant_dict_check($this->enchant_dictionary, $word)) { + $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word); + + if (sizeof($suggestions) > self::MAX_SUGGESTIONS) { + $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); + } + + $matches[] = array($word, $pos, $len, null, $suggestions); + } + + $diff += (strlen($word) - $len); + } + + $this->matches = $matches; + return $matches; + } + + /** + * Returns suggestions for the specified word + * + * @see rcube_spellcheck_engine::get_words() + */ + function get_suggestions($word) + { + $this->init(); + + if (!$this->enchant_dictionary) { + return array(); + } + + $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word); + + if (sizeof($suggestions) > self::MAX_SUGGESTIONS) + $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); + + return is_array($suggestions) ? $suggestions : array(); + } + + /** + * Returns misspelled words + * + * @see rcube_spellcheck_engine::get_suggestions() + */ + function get_words($text = null) + { + $result = array(); + + if ($text) { + // init spellchecker + $this->init(); + + if (!$this->enchant_dictionary) { + return array(); + } + + // With Enchant we don't need to get suggestions to return misspelled words + $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); + + foreach ($text as $w) { + $word = trim($w[0]); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + continue; + } + + if (!enchant_dict_check($this->enchant_dictionary, $word)) { + $result[] = $word; + } + } + + return $result; + } + + foreach ($this->matches as $m) { + $result[] = $m[0]; + } + + return $result; + } + +} + diff --git a/program/lib/Roundcube/rcube_spellcheck_engine.php b/program/lib/Roundcube/rcube_spellcheck_engine.php new file mode 100644 index 000000000..3cb4ca3de --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_engine.php @@ -0,0 +1,91 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2011-2013, Kolab Systems AG | + | Copyright (C) 2008-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Interface class for a spell-checking backend | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Interface class for a spell-checking backend + * + * @package Framework + * @subpackage Utils + */ +abstract class rcube_spellcheck_engine +{ + const MAX_SUGGESTIONS = 10; + + protected $lang; + protected $error; + protected $dictionary; + protected $separator = '/[\s\r\n\t\(\)\/\[\]{}<>\\"]+|[:;?!,\.](?=\W|$)/'; + + /** + * Default constructor + */ + public function __construct($dict, $lang) + { + $this->dictionary = $dict; + $this->lang = $lang; + } + + /** + * Return a list of languages supported by this backend + * + * @return array Indexed list of language codes + */ + abstract function languages(); + + /** + * Set content and check spelling + * + * @param string $text Text content for spellchecking + * + * @return bool True when no mispelling found, otherwise false + */ + abstract function check($text); + + /** + * Returns suggestions for the specified word + * + * @param string $word The word + * + * @return array Suggestions list + */ + abstract function get_suggestions($word); + + /** + * Returns misspelled words + * + * @param string $text The content for spellchecking. If empty content + * used for check() method will be used. + * + * @return array List of misspelled words + */ + abstract function get_words($text = null); + + /** + * Returns error message + * + * @return string Error message + */ + public function error() + { + return $this->error; + } + +} + diff --git a/program/lib/Roundcube/rcube_spellcheck_googie.php b/program/lib/Roundcube/rcube_spellcheck_googie.php new file mode 100644 index 000000000..3777942a6 --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_googie.php @@ -0,0 +1,176 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2008-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Spellchecking backend implementation to work with Googiespell | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Spellchecking backend implementation to work with a Googiespell service + * + * @package Framework + * @subpackage Utils + */ +class rcube_spellcheck_googie extends rcube_spellcheck_engine +{ + const GOOGIE_HOST = 'ssl://spell.roundcube.net'; + const GOOGIE_PORT = 443; + + private $matches = array(); + private $content; + + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + return array('am','ar','ar','bg','br','ca','cs','cy','da', + 'de_CH','de_DE','el','en_GB','en_US', + 'eo','es','et','eu','fa','fi','fr_FR','ga','gl','gl', + 'he','hr','hu','hy','is','it','ku','lt','lv','nl', + 'pl','pt_BR','pt_PT','ro','ru', + 'sk','sl','sv','uk'); + } + + /** + * Set content and check spelling + * + * @see rcube_spellcheck_engine::check() + */ + function check($text) + { + $this->content = $text; + + // spell check uri is configured + $url = rcube::get_instance()->config->get('spellcheck_uri'); + + if ($url) { + $a_uri = parse_url($url); + $ssl = ($a_uri['scheme'] == 'https' || $a_uri['scheme'] == 'ssl'); + $port = $a_uri['port'] ? $a_uri['port'] : ($ssl ? 443 : 80); + $host = ($ssl ? 'ssl://' : '') . $a_uri['host']; + $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; + } + else { + $host = self::GOOGIE_HOST; + $port = self::GOOGIE_PORT; + $path = '/tbproxy/spell?lang=' . $this->lang; + } + + $path .= sprintf('&key=%06d', $_SESSION['user_id']); + + $gtext = '<?xml version="1.0" encoding="utf-8" ?>' + .'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">' + .'<text>' . htmlspecialchars($text, ENT_QUOTES, RCUBE_CHARSET) . '</text>' + .'</spellrequest>'; + + $store = ''; + if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) { + $out = "POST $path HTTP/1.0\r\n"; + $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n"; + $out .= "User-Agent: Roundcube Webmail/" . RCMAIL_VERSION . " (Googiespell Wrapper)\r\n"; + $out .= "Content-Length: " . strlen($gtext) . "\r\n"; + $out .= "Content-Type: text/xml\r\n"; + $out .= "Connection: Close\r\n\r\n"; + $out .= $gtext; + fwrite($fp, $out); + + while (!feof($fp)) + $store .= fgets($fp, 128); + fclose($fp); + } + + // parse HTTP response + if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { + $http_status = $m[1]; + if ($http_status != '200') { + $this->error = 'HTTP ' . $m[1] . $m[2]; + $this->error .= "\n" . $store; + } + } + + if (!$store) { + $this->error = "Empty result from spelling engine"; + } + else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m) && $m[1]) { + $this->error = "Error code $m[1] returned"; + $this->error .= preg_match('/<errortext>([^<]+)/', $store, $m) ? ": " . html_entity_decode($m[1]) : ''; + } + + preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); + + // skip exceptions (if appropriate options are enabled) + foreach ($matches as $idx => $m) { + $word = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET); + // skip exceptions + if ($this->dictionary->is_exception($word)) { + unset($matches[$idx]); + } + } + + $this->matches = $matches; + return $matches; + } + + /** + * Returns suggestions for the specified word + * + * @see rcube_spellcheck_engine::get_words() + */ + function get_suggestions($word) + { + $matches = $word ? $this->check($word) : $this->matches; + + if ($matches[0][4]) { + $suggestions = explode("\t", $matches[0][4]); + if (sizeof($suggestions) > self::MAX_SUGGESTIONS) { + $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); + } + + return $suggestions; + } + + return array(); + } + + /** + * Returns misspelled words + * + * @see rcube_spellcheck_engine::get_suggestions() + */ + function get_words($text = null) + { + if ($text) { + $matches = $this->check($text); + } + else { + $matches = $this->matches; + $text = $this->content; + } + + $result = array(); + + foreach ($matches as $m) { + $result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET); + } + + return $result; + } + +} + diff --git a/program/lib/Roundcube/rcube_spellcheck_pspell.php b/program/lib/Roundcube/rcube_spellcheck_pspell.php new file mode 100644 index 000000000..b12684e43 --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_pspell.php @@ -0,0 +1,189 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2008-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Spellchecking backend implementation to work with Pspell | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Spellchecking backend implementation to work with Pspell + * + * @package Framework + * @subpackage Utils + */ +class rcube_spellcheck_pspell extends rcube_spellcheck_engine +{ + private $plink; + private $matches = array(); + + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $defaults = array('en'); + $langs = array(); + + // get aspell dictionaries + exec('aspell dump dicts', $dicts); + if (!empty($dicts)) { + $seen = array(); + foreach ($dicts as $lang) { + $lang = preg_replace('/-.*$/', '', $lang); + $langc = strlen($lang) == 2 ? $lang.'_'.strtoupper($lang) : $lang; + if (!$seen[$langc]++) + $langs[] = $lang; + } + $langs = array_unique($langs); + } + else { + $langs = $defaults; + } + + return $langs; + } + + /** + * Initializes PSpell dictionary + */ + private function init() + { + if (!$this->plink) { + if (!extension_loaded('pspell')) { + $this->error = "Pspell extension not available"; + return; + } + + $this->plink = pspell_new($this->lang, null, null, RCUBE_CHARSET, PSPELL_FAST); + } + + if (!$this->plink) { + $this->error = "Unable to load Pspell engine for selected language"; + } + } + + /** + * Set content and check spelling + * + * @see rcube_spellcheck_engine::check() + */ + function check($text) + { + $this->init(); + + if (!$this->plink) { + return array(); + } + + // tokenize + $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); + + $diff = 0; + $matches = array(); + + foreach ($text as $w) { + $word = trim($w[0]); + $pos = $w[1] - $diff; + $len = mb_strlen($word); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + } + else if (!pspell_check($this->plink, $word)) { + $suggestions = pspell_suggest($this->plink, $word); + + if (sizeof($suggestions) > self::MAX_SUGGESTIONS) { + $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); + } + + $matches[] = array($word, $pos, $len, null, $suggestions); + } + + $diff += (strlen($word) - $len); + } + + $this->matches = $matches; + return $matches; + } + + /** + * Returns suggestions for the specified word + * + * @see rcube_spellcheck_engine::get_words() + */ + function get_suggestions($word) + { + $this->init(); + + if (!$this->plink) { + return array(); + } + + $suggestions = pspell_suggest($this->plink, $word); + + if (sizeof($suggestions) > self::MAX_SUGGESTIONS) + $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); + + return is_array($suggestions) ? $suggestions : array(); + } + + /** + * Returns misspelled words + * + * @see rcube_spellcheck_engine::get_suggestions() + */ + function get_words($text = null) + { + $result = array(); + + if ($text) { + // init spellchecker + $this->init(); + + if (!$this->plink) { + return array(); + } + + // With PSpell we don't need to get suggestions to return misspelled words + $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); + + foreach ($text as $w) { + $word = trim($w[0]); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + continue; + } + + if (!pspell_check($this->plink, $word)) { + $result[] = $word; + } + } + + return $result; + } + + foreach ($this->matches as $m) { + $result[] = $m[0]; + } + + return $result; + } + +} + diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php index df4365223..672515204 100644 --- a/program/lib/Roundcube/rcube_spellchecker.php +++ b/program/lib/Roundcube/rcube_spellchecker.php @@ -38,7 +38,7 @@ class rcube_spellchecker // default settings - const GOOGLE_HOST = 'ssl://www.google.com'; + const GOOGLE_HOST = 'ssl://spell.roundcube.net'; const GOOGLE_PORT = 443; const MAX_SUGGESTIONS = 10; @@ -84,9 +84,6 @@ class rcube_spellchecker if ($this->engine == 'pspell') { $this->matches = $this->_pspell_check($this->content); } - else if ($this->engine == 'enchant') { - $this->matches = $this->_enchant_check($this->content); - } else { $this->matches = $this->_googie_check($this->content); } @@ -118,9 +115,6 @@ class rcube_spellchecker if ($this->engine == 'pspell') { return $this->_pspell_suggestions($word); } - else if ($this->engine == 'enchant') { - return $this->_enchant_suggestions($word); - } return $this->_googie_suggestions($word); } @@ -139,9 +133,6 @@ class rcube_spellchecker if ($this->engine == 'pspell') { return $this->_pspell_words($text, $is_html); } - else if ($this->engine == 'enchant') { - return $this->_enchant_words($text, $is_html); - } return $this->_googie_words($text, $is_html); } @@ -323,6 +314,11 @@ class rcube_spellchecker if (!$this->plink) { if (!extension_loaded('pspell')) { $this->error = "Pspell extension not available"; + rcube::raise_error(array( + 'code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => $this->error), true, false); + return; } @@ -335,141 +331,6 @@ class rcube_spellchecker } - /** - * Checks the text using enchant - * - * @param string $text Text content for spellchecking - */ - private function _enchant_check($text) - { - // init spellchecker - $this->_enchant_init(); - - if (!$this->enchant_dictionary) { - return array(); - } - - // tokenize - $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); - - $diff = 0; - $matches = array(); - - foreach ($text as $w) { - $word = trim($w[0]); - $pos = $w[1] - $diff; - $len = mb_strlen($word); - - // skip exceptions - if ($this->is_exception($word)) { - } - else if (!enchant_dict_check($this->enchant_dictionary, $word)) { - $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word); - - if (sizeof($suggestions) > self::MAX_SUGGESTIONS) { - $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); - } - - $matches[] = array($word, $pos, $len, null, $suggestions); - } - - $diff += (strlen($word) - $len); - } - - return $matches; - } - - - /** - * Returns the misspelled words - */ - private function _enchant_words($text = null, $is_html=false) - { - $result = array(); - - if ($text) { - // init spellchecker - $this->_enchant_init(); - - if (!$this->enchant_dictionary) { - return array(); - } - - // With Enchant we don't need to get suggestions to return misspelled words - if ($is_html) { - $text = $this->html2text($text); - } - - $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); - - foreach ($text as $w) { - $word = trim($w[0]); - - // skip exceptions - if ($this->is_exception($word)) { - continue; - } - - if (!enchant_dict_check($this->enchant_dictionary, $word)) { - $result[] = $word; - } - } - - return $result; - } - - foreach ($this->matches as $m) { - $result[] = $m[0]; - } - - return $result; - } - - - /** - * Returns suggestions for misspelled word - */ - private function _enchant_suggestions($word) - { - // init spellchecker - $this->_enchant_init(); - - if (!$this->enchant_dictionary) { - return array(); - } - - $suggestions = enchant_dict_suggest($this->enchant_dictionary, $word); - - if (sizeof($suggestions) > self::MAX_SUGGESTIONS) - $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); - - return is_array($suggestions) ? $suggestions : array(); - } - - - /** - * Initializes PSpell dictionary - */ - private function _enchant_init() - { - if (!$this->enchant_broker) { - if (!extension_loaded('enchant')) { - $this->error = "Enchant extension not available"; - return; - } - - $this->enchant_broker = enchant_broker_init(); - } - - if (!enchant_broker_dict_exists($this->enchant_broker, $this->lang)) { - $this->error = "Unable to load dictionary for selected language using Enchant"; - return; - } - - $this->enchant_dictionary = enchant_broker_request_dict($this->enchant_broker, $this->lang); - } - - private function _googie_check($text) { // spell check uri is configured @@ -493,7 +354,7 @@ class rcube_spellchecker $gtext = '<?xml version="1.0" encoding="utf-8" ?>' .'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">' - .'<text>' . $gtext . '</text>' + .'<text>' . htmlspecialchars($gtext) . '</text>' .'</spellrequest>'; $store = ''; @@ -511,19 +372,9 @@ class rcube_spellchecker fclose($fp); } - // parse HTTP response - if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { - $http_status = $m[1]; - if ($http_status != '200') - $this->error = 'HTTP ' . $m[1] . $m[2]; - } - if (!$store) { $this->error = "Empty result from spelling engine"; } - else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m) && $m[1]) { - $this->error = "Error code $m[1] returned"; - } preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index e697b2c73..8193e540c 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -61,6 +61,8 @@ abstract class rcube_storage 'MAIL-FOLLOWUP-TO', 'MAIL-REPLY-TO', 'RETURN-PATH', + 'DELIVERED-TO', + 'ENVELOPE-TO', ); const UNKNOWN = 0; @@ -538,13 +540,12 @@ abstract class rcube_storage /** * Append a mail message (source) to a specific folder. * - * @param string $folder Target folder - * @param string|array $message The message source string or filename - * or array (of strings and file pointers) - * @param string $headers Headers string if $message contains only the body - * @param boolean $is_file True if $message is a filename - * @param array $flags Message flags - * @param mixed $date Message internal date + * @param string $folder Target folder + * @param string $message The message source string or filename + * @param string $headers Headers string if $message contains only the body + * @param boolean $is_file True if $message is a filename + * @param array $flags Message flags + * @param mixed $date Message internal date * * @return int|bool Appended message UID or True on success, False on error */ @@ -806,14 +807,13 @@ abstract class rcube_storage /** - * Returns current status of a folder (compared to the last time use) + * Returns current status of a folder * * @param string $folder Folder name - * @param array $diff Difference data * * @return int Folder status */ - abstract function folder_status($folder = null, &$diff = array()); + abstract function folder_status($folder = null); /** @@ -985,6 +985,6 @@ abstract class rcube_storage /** * Delete outdated cache entries */ - abstract function cache_gc(); + abstract function expunge_cache(); } // end class rcube_storage diff --git a/program/lib/Roundcube/rcube_string_replacer.php b/program/lib/Roundcube/rcube_string_replacer.php index 354b4596d..bd26f8e7d 100644 --- a/program/lib/Roundcube/rcube_string_replacer.php +++ b/program/lib/Roundcube/rcube_string_replacer.php @@ -28,10 +28,9 @@ class rcube_string_replacer public $mailto_pattern; public $link_pattern; private $values = array(); - private $options = array(); - function __construct($options = array()) + function __construct() { // Simplified domain expression for UTF8 characters handling // Support unicode/punycode in top-level domain part @@ -45,8 +44,6 @@ class rcube_string_replacer ."@$utf_domain" // domain-part ."(\?[$url1$url2]+)?" // e.g. ?subject=test... .")/"; - - $this->options = $options; } /** @@ -92,10 +89,10 @@ class rcube_string_replacer if ($url) { $suffix = $this->parse_url_brackets($url); - $attrib = (array)$this->options['link_attribs']; - $attrib['href'] = $url_prefix . $url; - - $i = $this->add(html::a($attrib, rcube::Q($url)) . $suffix); + $i = $this->add(html::a(array( + 'href' => $url_prefix . $url, + 'target' => '_blank' + ), rcube::Q($url)) . $suffix); } // Return valid link for recognized schemes, otherwise diff --git a/program/lib/Roundcube/rcube_user.php b/program/lib/Roundcube/rcube_user.php index 5e9c9af80..505b190d1 100644 --- a/program/lib/Roundcube/rcube_user.php +++ b/program/lib/Roundcube/rcube_user.php @@ -495,9 +495,9 @@ class rcube_user "INSERT INTO ".$dbh->table_name('users'). " (created, last_login, username, mail_host, language)". " VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)", - $data['user'], - $data['host'], - $data['language']); + strip_newlines($data['user']), + strip_newlines($data['host']), + strip_newlines($data['language'])); if ($user_id = $dbh->insert_id('users')) { // create rcube_user instance to make plugin hooks work @@ -517,7 +517,7 @@ class rcube_user if (empty($user_email)) { $user_email = strpos($data['user'], '@') ? $user : sprintf('%s@%s', $data['user'], $mail_domain); } - $email_list[] = $user_email; + $email_list[] = strip_newlines($user_email); } // identities_level check else if (count($email_list) > 1 && $rcube->config->get('identities_level', 0) > 1) { @@ -547,6 +547,7 @@ class rcube_user $record['name'] = $user_name != $record['email'] ? $user_name : ''; } + $record['name'] = strip_newlines($record['name']); $record['user_id'] = $user_id; $record['standard'] = $standard; diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index 1d76ae508..4dadbb8bd 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -400,7 +400,7 @@ class rcube_utils $out = array(); $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); - foreach (array_keys($src) as $key) { + foreach ($src as $key => $value) { $fname = $key[0] == '_' ? substr($key, 1) : $key; if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { $out[$fname] = self::get_input_value($key, $mode); @@ -476,9 +476,9 @@ class rcube_utils // remove html comments and add #container to each tag selector. // also replace body definition because we also stripped off the <body> tag - $styles = preg_replace( + $source = preg_replace( array( - '/(^\s*<!--)|(-->\s*$)/', + '/(^\s*<\!--)|(-->\s*$)/m', '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im', '/'.preg_quote($container_id, '/').'\s+body/i', ), @@ -490,9 +490,9 @@ class rcube_utils $source); // put block contents back in - $styles = $replacements->resolve($styles); + $source = $replacements->resolve($source); - return $styles; + return $source; } @@ -506,24 +506,17 @@ class rcube_utils */ public static function file2class($mimetype, $filename) { - $mimetype = strtolower($mimetype); - $filename = strtolower($filename); - list($primary, $secondary) = explode('/', $mimetype); $classes = array($primary ? $primary : 'unknown'); - if ($secondary) { $classes[] = $secondary; } - - if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) { - if (!in_array($m[1], $classes)) { - $classes[] = $m[1]; - } + if (preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) { + $classes[] = $m[1]; } - return join(" ", $classes); + return strtolower(join(" ", $classes)); } @@ -666,21 +659,6 @@ class rcube_utils /** - * Returns the real remote IP address - * - * @return string Remote IP address - */ - public static function remote_addr() - { - foreach (array('HTTP_X_FORWARDED_FOR','HTTP_X_REAL_IP','REMOTE_ADDR') as $prop) { - if (!empty($_SERVER[$prop])) - return $_SERVER[$prop]; - } - - return ''; - } - - /** * Read a specific HTTP request header. * * @param string $name Header name @@ -761,9 +739,9 @@ class rcube_utils // Clean malformed data $date = preg_replace( array( - '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal - '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters - '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names + '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal + '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters + '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names ), array( '\\1', @@ -771,8 +749,6 @@ class rcube_utils '', ), $date); - $date = trim($date); - // if date parsing fails, we have a date in non-rfc format. // remove token from the end and try again while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { @@ -787,44 +763,6 @@ class rcube_utils return (int) $ts; } - /** - * Date parsing function that turns the given value into a DateTime object - * - * @param string $date Date string - * - * @return object DateTime instance or false on failure - */ - public static function anytodatetime($date) - { - if (is_object($date) && is_a($date, 'DateTime')) { - return $date; - } - - $dt = false; - $date = trim($date); - - // try to parse string with DateTime first - if (!empty($date)) { - try { - $dt = new DateTime($date); - } - catch (Exception $e) { - // ignore - } - } - - // try our advanced strtotime() method - if (!$dt && ($timestamp = self::strtotime($date))) { - try { - $dt = new DateTime("@".$timestamp); - } - catch (Exception $e) { - // ignore - } - } - - return $dt; - } /* * Idn_to_ascii wrapper. diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index d54dc56ad..f76c4f08d 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -47,7 +47,6 @@ class rcube_vcard 'manager' => 'X-MANAGER', 'spouse' => 'X-SPOUSE', 'edit' => 'X-AB-EDIT', - 'groups' => 'CATEGORIES', ); private $typemap = array( 'IPHONE' => 'mobile', @@ -358,8 +357,8 @@ class rcube_vcard case 'birthday': case 'anniversary': - if (($val = rcube_utils::anytodatetime($value)) && ($fn = self::$fieldmap[$field])) { - $this->raw[$fn][] = array(0 => $val->format('Y-m-d'), 'value' => array('date')); + if (($val = rcube_utils::strtotime($value)) && ($fn = self::$fieldmap[$field])) { + $this->raw[$fn][] = array(0 => date('Y-m-d', $val), 'value' => array('date')); } break; @@ -482,7 +481,7 @@ class rcube_vcard $vcard_block = ''; $in_vcard_block = false; - foreach (preg_split("/[\r\n]+/", $data) as $line) { + foreach (preg_split("/[\r\n]+/", $data) as $i => $line) { if ($in_vcard_block && !empty($line)) { $vcard_block .= $line . "\n"; } @@ -612,8 +611,8 @@ class rcube_vcard $enc = null; foreach($regs2[1] as $attrid => $attr) { + $attr = preg_replace('/[\s\t\n\r\0\x0B]/', '', $attr); 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 @@ -757,7 +756,7 @@ class rcube_vcard * * @return string Joined and quoted string */ - public static function vcard_quote($s, $sep = ';') + private static function vcard_quote($s, $sep = ';') { if (is_array($s)) { foreach($s as $part) { @@ -766,7 +765,7 @@ class rcube_vcard return(implode($sep, (array)$r)); } - return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', $sep => '\\'.$sep)); + return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', ',' => '\,', ';' => '\;')); } /** @@ -792,7 +791,7 @@ class rcube_vcard return $result; } - $s = strtr($s, $rep2); + $s = trim(strtr($s, $rep2)); } // some implementations (GMail) use non-standard backslash before colon (#1489085) diff --git a/program/lib/Roundcube/rcube_washtml.php b/program/lib/Roundcube/rcube_washtml.php index 8f7fe9749..f964f8b35 100644 --- a/program/lib/Roundcube/rcube_washtml.php +++ b/program/lib/Roundcube/rcube_washtml.php @@ -410,25 +410,6 @@ class rcube_washtml ); $html = preg_replace($html_search, $html_replace, trim($html)); - //-> Replace all of those weird MS Word quotes and other high characters - $badwordchars=array( - "\xe2\x80\x98", // left single quote - "\xe2\x80\x99", // right single quote - "\xe2\x80\x9c", // left double quote - "\xe2\x80\x9d", // right double quote - "\xe2\x80\x94", // em dash - "\xe2\x80\xa6" // elipses - ); - $fixedwordchars=array( - "'", - "'", - '"', - '"', - '—', - '...' - ); - $html = str_replace($badwordchars,$fixedwordchars, $html); - // PCRE errors handling (#1486856), should we use something like for every preg_* use? if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) { $errstr = "Could not clean up HTML message! PCRE Error: $preg_error."; @@ -448,7 +429,7 @@ class rcube_washtml } // fix (unknown/malformed) HTML tags before "wash" - $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', array($this, 'html_tag_callback'), $html); + $html = preg_replace_callback('/(<(?!\!)[\/]*)([^\s>]+)/', array($this, 'html_tag_callback'), $html); // Remove invalid HTML comments (#1487759) // Don't remove valid conditional comments diff --git a/program/localization/ar_SA/labels.inc b/program/localization/ar_SA/labels.inc index bc1764b0f..af08cc301 100644 --- a/program/localization/ar_SA/labels.inc +++ b/program/localization/ar_SA/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'المسودات'; $labels['sent'] = 'المرسل'; $labels['trash'] = 'المهملات'; $labels['junk'] = 'غير المرغوب'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'الموضوع'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'وضع طريقة السرد'; $labels['folderactions'] = 'إجراءات المجلد...'; $labels['compact'] = 'ضغط'; $labels['empty'] = 'تÙريغ'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'المساØØ© المستخدمة'; $labels['unknown'] = 'مجهول'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'استعادة البØØ« للاÙتراضي'; $labels['searchmod'] = 'أماكن البØØ«'; $labels['msgtext'] = 'كامل الرسالة'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'اÙØªØ ÙÙŠ ناÙذة جديدة'; $labels['emlsave'] = 'تنزيل (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'عرض المجموعة الأخيرة'; $labels['group'] = 'مجموعة'; $labels['groups'] = 'المجموعات'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'العناوين الشخصية'; $labels['searchsave'] = 'ØÙظ البØØ«'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'تجاهل الكلمات التي تØتوي $labels['spellcheckignorecaps'] = 'تجاهل الكلمات التي بها Ø£Øر٠كبيرة'; $labels['addtodict'] = 'إضاÙØ© إلى القامس'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ar_SA/messages.inc b/program/localization/ar_SA/messages.inc index f989867de..9429a3910 100644 --- a/program/localization/ar_SA/messages.inc +++ b/program/localization/ar_SA/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'إزالة التنسيق من الرسالة...'; $messages['messageopenerror'] = 'تعذرت قراءة الرسالة من الخادم'; $messages['fileuploaderror'] = 'Ùشل رÙع الملÙ'; $messages['filesizeerror'] = 'Øجم المل٠الذي تØاول رÙعه أكبر من الØجمالأقصى $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'تم نسخ $nr رسائل بنجاØ'; +$messages['copyerror'] = 'لم يمكن نسخ أية عناوين'; $messages['sourceisreadonly'] = 'لا يمكن تعديل مصدر العنوان هذا'; $messages['errorsavingcontact'] = 'تعذر ØÙظ عنوان المراسل'; $messages['movingmessage'] = 'جاري نقل الرسالة...'; $messages['copyingmessage'] = 'جاري نسخ الرسالة...'; $messages['copyingcontact'] = 'جاري نسخ المÙراسلين...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'جاري Øذ٠الرسائل...'; $messages['markingmessage'] = 'جاري تØديد الرسائل...'; $messages['addingmember'] = 'جاري إضاÙØ© المÙراسلين إلى المجموعة...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'جاري الاستيراد، رجاء انتظر...' $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>تم استيراد $inserted مراسلين بنجاØØŒ وتجاهل$skipped موجودين مسبقاً</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>تم تجاهل $skipped عناصر موجودة</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'العملية ممنوعة!'; $messages['nofromaddress'] = 'عنوان البريد الالكتروني غير Ù…Øدد Ùيالهويّة المنتقاة'; $messages['editorwarning'] = 'يتسبب الانتقال إلى Ù…Øرر النص البسيط بضياع جميع التنسيق. هل تريد الاستمرار؟'; diff --git a/program/localization/ast/labels.inc b/program/localization/ast/labels.inc index 8c1985eef..49f85689b 100644 --- a/program/localization/ast/labels.inc +++ b/program/localization/ast/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Borradores'; $labels['sent'] = 'Unviaos'; $labels['trash'] = 'Papelera'; $labels['junk'] = 'Puxarra'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Asuntu'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compautar'; $labels['empty'] = 'Vaciar'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Espaciu en discu'; $labels['unknown'] = 'desconocÃu'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Anovar la búsqueda'; $labels['searchmod'] = 'Guetar modificadores'; $labels['msgtext'] = 'Mensax completu'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Abrir en una ventana nueva'; $labels['emlsave'] = 'Baxar (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Amosar l\'últimu grupu'; $labels['group'] = 'Group'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Direiciones personales'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ast/messages.inc b/program/localization/ast/messages.inc index 512316c18..9e415b8ec 100644 --- a/program/localization/ast/messages.inc +++ b/program/localization/ast/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Desaniciando\'l formatu del mensaxe...'; $messages['messageopenerror'] = 'Nun soi a baxer el mensaxe del sirvidor'; $messages['fileuploaderror'] = 'Fallu al xubir ficheros'; $messages['filesizeerror'] = 'El ficheru ye más grande de lo permitÃo ($size)'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Copiaronse $nr direiciones correchamente'; +$messages['copyerror'] = 'Nun fui a copiar nenguna direición'; $messages['sourceisreadonly'] = 'Esta direición ye de namái-llectura'; $messages['errorsavingcontact'] = 'Nun fui a guardar la direición del contautu'; $messages['movingmessage'] = 'Moviendo\'l mensaxe...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importando, dame un minutÃn...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Importaronse correchamente $inserted contautos, saltáronse $skipped entrase que yá esistÃen</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Nun tienes permisu pa facelo.'; $messages['nofromaddress'] = 'Perdiose la direición de corréu de la identidá qu\'escoyisti'; $messages['editorwarning'] = 'Si pases a editor en modu testu vas perder tol estilu aplicáu al mensaxe. ¿Tas seguru de que quies facelo?'; diff --git a/program/localization/az_AZ/labels.inc b/program/localization/az_AZ/labels.inc index 129315ec0..0cb4b3e82 100644 --- a/program/localization/az_AZ/labels.inc +++ b/program/localization/az_AZ/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Qaralamalar'; $labels['sent'] = 'GöndÉ™rilÉ™nlÉ™r'; $labels['trash'] = 'SÉ™bÉ™t'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Mövzu'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Görünüş rejimi'; $labels['folderactions'] = 'Qovluq iÅŸlÉ™ri...'; $labels['compact'] = 'Sıx'; $labels['empty'] = 'BoÅŸalt'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk istifadÉ™si'; $labels['unknown'] = 'namÉ™lum'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Axtarışı yenilÉ™'; $labels['searchmod'] = 'Axtarış variantları'; $labels['msgtext'] = 'Bütün mÉ™ktub'; $labels['body'] = 'MÉ™tn'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Yeni pÉ™ncÉ™rÉ™dÉ™ aç'; $labels['emlsave'] = 'Saxla (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Sonuncunu göstÉ™r'; $labels['group'] = 'Qrup'; $labels['groups'] = 'Qruplar'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Şəxsi ünvanlar'; $labels['searchsave'] = 'SorÄŸunu saxla'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'RÉ™qÉ™mlÉ™r ilÉ™ sözlÉ™ri keç'; $labels['spellcheckignorecaps'] = 'Böyük hÉ™rflÉ™ri olan sözlÉ™rdÉ™n keç'; $labels['addtodict'] = 'LüğətÉ™ É™lavÉ™ et'; $labels['mailtoprotohandler'] = 'mailto: keçid üçün protokol qeyd et'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'MÉ™ktubların yönÉ™ldilmÉ™si'; $labels['inline'] = 'mÉ™tndÉ™'; $labels['asattachment'] = 'fayl kimi'; diff --git a/program/localization/az_AZ/messages.inc b/program/localization/az_AZ/messages.inc index 745836e5f..418f270be 100644 --- a/program/localization/az_AZ/messages.inc +++ b/program/localization/az_AZ/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'MÉ™ktubun formatlaÅŸması silinir...'; $messages['messageopenerror'] = 'MÉ™ktubu serverdÉ™n yüklÉ™mÉ™k alınmır'; $messages['fileuploaderror'] = 'Fayl yüklÉ™nilmÉ™di'; $messages['filesizeerror'] = 'YüklÉ™nilÉ™n fayl maksimal ölçüdÉ™n çoxdur - $size'; -$messages['copysuccess'] = '$nr kontaktlar uÄŸurlar kopyalanmışdır.'; -$messages['movesuccess'] = '$nr kontaktlar uÄŸurla köçürülmüşdür.'; -$messages['copyerror'] = 'Heç bir kontaktı kopyalamaq olmur.'; -$messages['moveerror'] = 'Heç bir kontaktı köçürmÉ™k alınmır.'; +$messages['copysuccess'] = '$nr ünvan kopyalandı'; +$messages['copyerror'] = 'Ãœnvanları kopyalamaq alınmır'; $messages['sourceisreadonly'] = 'VerilÉ™n ünvanlar mÉ™nbÉ™yi yalnız oxunmaq üçün'; $messages['errorsavingcontact'] = 'ÆlaqÉ™ni ünvanda saxlamaq mümkün deyil'; $messages['movingmessage'] = 'MÉ™ktub köçürülür...'; $messages['copyingmessage'] = 'MÉ™ktub kopyalanır...'; $messages['copyingcontact'] = 'Kontakt(lar)ın kopyalanması...'; -$messages['movingcontact'] = 'Kontak(lar)ın köçürülmÉ™si...'; $messages['deletingmessage'] = 'MÉ™ktub(lar) silinir...'; $messages['markingmessage'] = 'MÉ™ktub(lar) iÅŸarÉ™lÉ™nir...'; $messages['addingmember'] = 'Kontakt(lar)ın qrupa É™lavÉ™ edilmÉ™si...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Ä°dxal gedir, lütfÉ™n gözlÉ™yin...'; $messages['importformaterror'] = 'Ä°dxal xÉ™tası. YüklÉ™nilÉ™n fayl namÉ™lum mÉ™lumat formatına malikdir.'; $messages['importconfirm'] = '<b>$inserted ünvanlar müvÉ™ffÉ™qiyyÉ™tlÉ™ idxal edildi, mövcud $skipped buraxılıb</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Buraxılmış $skipped mövcud daxillÉ™r</b>'; -$messages['importmessagesuccess'] = '$nr mÉ™ktublar uÄŸurla idxal edildi'; -$messages['importmessageerror'] = 'Ä°dxal alınmadı! YüklÉ™nilmiÅŸ fayl düzgün mÉ™ktub vÉ™ ya poçt faylı deyil'; $messages['opnotpermitted'] = 'ÆmÉ™liyyat qadaÄŸandır!'; $messages['nofromaddress'] = 'SeçilmiÅŸ kimlikdÉ™ e-poçt ünvanları yoxdur'; $messages['editorwarning'] = 'Adi mÉ™tn redaktoruna keçid, bütün mÉ™tn formatlarının itkisinÉ™ gÉ™tirÉ™cÉ™k. Davam edilsin?'; diff --git a/program/localization/be_BE/labels.inc b/program/localization/be_BE/labels.inc index 56339a926..a5489a454 100644 --- a/program/localization/be_BE/labels.inc +++ b/program/localization/be_BE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Чарнавікі'; $labels['sent'] = 'ДаÑланыÑ'; $labels['trash'] = 'Сметніца'; $labels['junk'] = 'Спам'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ТÑма'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compact'; $labels['empty'] = 'Empty'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'unknown'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reset search'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/be_BE/messages.inc b/program/localization/be_BE/messages.inc index c4033dad9..73cdb3ed8 100644 --- a/program/localization/be_BE/messages.inc +++ b/program/localization/be_BE/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/bg_BG/labels.inc b/program/localization/bg_BG/labels.inc index dd5be6e64..6542cfc53 100644 --- a/program/localization/bg_BG/labels.inc +++ b/program/localization/bg_BG/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Чернови'; $labels['sent'] = 'Изпратени'; $labels['trash'] = 'Кошче'; $labels['junk'] = 'Спам'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Заглавие'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Кратък ÑпиÑък'; $labels['folderactions'] = 'ДейÑÑ‚Ð²Ð¸Ñ Ð·Ð° папки...'; $labels['compact'] = 'Свиване'; $labels['empty'] = 'Изпразни'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Използвано мÑÑто'; $labels['unknown'] = 'нÑма информациÑ'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ИзчиÑти Ñ‚ÑŠÑ€Ñенето и покажи Ð²Ñ $labels['searchmod'] = 'ТърÑене във'; $labels['msgtext'] = 'ЦÑлото Ñъобщение'; $labels['body'] = 'ОÑновен текÑÑ‚'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Отвори в нов прозорец'; $labels['emlsave'] = 'Изтегли като .eml'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'ПоÑледна Ñтраница'; $labels['group'] = 'Група'; $labels['groups'] = 'Групи'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Лични адреÑи'; $labels['searchsave'] = 'Запази Ñ‚ÑŠÑ€Ñенето'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Игнорирай думи ÑъдържащР$labels['spellcheckignorecaps'] = 'Игнорирай думи Ñъдържащи единÑтвено главни букви'; $labels['addtodict'] = 'Добави в речника'; $labels['mailtoprotohandler'] = 'РегиÑтриран протокол за mailto: връзките'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Препращане на ÑъобщениÑ'; $labels['inline'] = 'вградено'; $labels['asattachment'] = 'като прикачен файл'; diff --git a/program/localization/bg_BG/messages.inc b/program/localization/bg_BG/messages.inc index 5b6e7a596..219772e74 100644 --- a/program/localization/bg_BG/messages.inc +++ b/program/localization/bg_BG/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Премахване форматирането на $messages['messageopenerror'] = 'ПиÑмото не може да бъде заредено от Ñървъра'; $messages['fileuploaderror'] = 'Грешка при прикачването на файла'; $messages['filesizeerror'] = 'ПрикачениÑÑ‚ файл надвишава лимита от $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'УÑпешно копирани $nr адреÑа'; +$messages['copyerror'] = 'Грешка при копирането на адреÑите'; $messages['sourceisreadonly'] = 'Този източник на адреÑи е Ñамо за четене'; $messages['errorsavingcontact'] = 'Грешка при запиÑването на адреÑа'; $messages['movingmessage'] = 'ПремеÑтване на Ñъобщение...'; $messages['copyingmessage'] = 'Копиране на Ñъобщение(Ñ)...'; $messages['copyingcontact'] = 'Копиране на контакт(и)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Изтриване на Ñъобщение(Ñ)...'; $messages['markingmessage'] = 'Маркиране на Ñъобщение(Ñ)...'; $messages['addingmember'] = 'ДобавÑне на контакт(и) в групата...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Импорт, Ð¼Ð¾Ð»Ñ Ð¸Ð·Ñ‡Ð°ÐºÐ°Ð¹Ñ‚Ðµ...'; $messages['importformaterror'] = 'Импорта пропадна! КачениÑÑ‚ файл не е Ñ Ð²Ð°Ð»Ð¸Ð´Ð½Ð¸ данни.'; $messages['importconfirm'] = '<b>УÑпешно Ñа импортирани $inserted контакта, вече ÑъщеÑтвуващите $skipped контакта Ñа пропуÑнати</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = 'b>СъщеÑтвуващите запиÑи $skipped Ñа пропуÑнати</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'ОперациÑта не е позволена!'; $messages['nofromaddress'] = 'ЛипÑва e-mail Ð°Ð´Ñ€ÐµÑ Ð·Ð° избраната ÑамоличноÑÑ‚'; $messages['editorwarning'] = 'Превключването на редактора в текÑтов режим ще доведе до загуба на форматирането на текÑа. Сигурни ли Ñте, че иÑкате да продължите?'; diff --git a/program/localization/bn_BD/labels.inc b/program/localization/bn_BD/labels.inc index 1273ef192..a0866a3a7 100644 --- a/program/localization/bn_BD/labels.inc +++ b/program/localization/bn_BD/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'খসড়া'; $labels['sent'] = 'পà§à¦°à§‡à¦°à¦¿à¦¤(পাঠানো মেইল)'; $labels['trash'] = 'ডাসà§à¦Ÿà¦¬à¦¿à¦¨'; $labels['junk'] = 'আজেবাজে মেইল'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'বিষয়'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'টাইটকরà§à¦¨'; $labels['empty'] = 'খালিকরà§à¦¨'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ডিসà§à¦• ঠখালি যায়গা'; $labels['unknown'] = 'অজানা'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'নতà§à¦¨à¦•à¦°à§‡ খà§à¦œà§à¦¨'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'নতà§à¦¨ উইনà§à¦¡à§‹ তে দেখà§à¦¨'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'শেষের গà§à¦²à§‹ দেখান'; $labels['group'] = 'Group'; $labels['groups'] = 'গà§à¦°à§à¦ª'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'নিজের ঠিকানা'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/bn_BD/messages.inc b/program/localization/bn_BD/messages.inc index 9de6c38de..44d5fcc60 100644 --- a/program/localization/bn_BD/messages.inc +++ b/program/localization/bn_BD/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'বিনà§à¦¯à¦¾à¦¸ (formatting) সরানো ঠ$messages['messageopenerror'] = 'সারà¦à¦¾à¦° থেকে চিঠি আনা গেলোনা'; $messages['fileuploaderror'] = 'ফাইলটা সারà¦à¦¾à¦°à§‡ উঠানো গেলোনা'; $messages['filesizeerror'] = 'যে ফাইলটা উঠানোর চেষà§à¦Ÿà¦¾ করলেন সেটি সরà§à¦¬à§‹à¦šà§à¦š সাইজ $size à¦à¦° থেকে বেশি'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'ঠিকঠাকমতো $nr ঠিকানা নকল করে নেওয়া গেছে'; +$messages['copyerror'] = 'কোনো ঠিকানা তোলা গেলোনা'; $messages['sourceisreadonly'] = 'à¦à¦‡à¦ িকানাটা খালি পড়ার জনà§à¦¯à§‡'; $messages['errorsavingcontact'] = 'ঠিকানা জমা রাখা গেলোনা'; $messages['movingmessage'] = 'চিঠি সরানো হচà§à¦›à§‡..'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'আমদানি করা হচà§à¦›à§‡à¥¤ à¦à¦ $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>ঠিকমতো $inserted ঠিকানা আমদানি করা গেছে, $skipped ঠিকানা আগের থেকেই ছিলো বলে তাদের টা যা ছিলো তাই রাখা হয়েছে</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'à¦à¦‡ কাজটা করার অনà§à¦®à¦¤à¦¿ নাই আপনার'; $messages['nofromaddress'] = 'বেছে নেওয়া যে পরিচিতিটা, তাতে ই-মেইল নেই'; $messages['editorwarning'] = 'যদি আপনি শà§à¦§à§ লেখার সà§à¦Ÿà¦¾à¦‡à¦²à§‡ যান তাহলে বরà§à¦¤à¦®à¦¾à¦¨à§‡à¦° কোনো বিনà§à¦¯à¦¾à¦¸ হারিয়ে যাবে'; diff --git a/program/localization/br/labels.inc b/program/localization/br/labels.inc index c88fd92a6..537a887df 100644 --- a/program/localization/br/labels.inc +++ b/program/localization/br/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Brouilhedoù'; $labels['sent'] = 'Kaset'; $labels['trash'] = 'Pod-lastez'; $labels['junk'] = 'Stroboù'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Sujed'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Stummaat'; $labels['empty'] = 'Skarzhañ'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Implijadur pladenn'; $labels['unknown'] = 'Dianav'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Aderaouekaat ar glask'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Gwelout ar bajenn diwezhañ'; $labels['group'] = 'Group'; $labels['groups'] = 'Strolladoù'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Chomlec\'h personel'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/br/messages.inc b/program/localization/br/messages.inc index fd1674d80..c1988577d 100644 --- a/program/localization/br/messages.inc +++ b/program/localization/br/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'O tilemel furmaozañ...'; $messages['messageopenerror'] = 'N\'us ket tu da gargañ ar c\'hemennad adalek ar servijer'; $messages['fileuploaderror'] = 'Fazi o treuzkas ar restr'; $messages['filesizeerror'] = 'Re vras eo ar restr treuzkaset $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Kopiañ mat $nr chomlec\'h'; +$messages['copyerror'] = 'Ne c\'hall ket kopiañ chomlec\'hioù'; $messages['sourceisreadonly'] = 'Lenn hepken eo an tarzh chomlec\'h se'; $messages['errorsavingcontact'] = 'Ne c\'haller ket gwarediñ chomlec\'h darempred'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/bs_BA/labels.inc b/program/localization/bs_BA/labels.inc index 61989e6b3..5afdcad1f 100644 --- a/program/localization/bs_BA/labels.inc +++ b/program/localization/bs_BA/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Skice'; $labels['sent'] = 'Poslano'; $labels['trash'] = 'Smeće'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Prikaži prava imena specijalnih foldera'; // message listing $labels['subject'] = 'Naslov'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'NaÄin prikaza liste'; $labels['folderactions'] = 'Akcije za foldere...'; $labels['compact'] = 'Optimiziraj'; $labels['empty'] = 'Isprazni'; -$labels['importmessages'] = 'Uvezi poruke'; $labels['quota'] = 'Zauzeće diska'; $labels['unknown'] = 'nepoznato'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Resetuj pretragu'; $labels['searchmod'] = 'Modifikacija pretrage'; $labels['msgtext'] = 'Cijela poruka'; $labels['body'] = 'Tijelo'; -$labels['type'] = 'Vrsta'; $labels['openinextwin'] = 'Otvori u novom prozoru'; $labels['emlsave'] = 'Preuzmi (.eml)'; @@ -226,7 +223,7 @@ $labels['mailreplyintro'] = '$date, $sender je napisao/la:'; $labels['originalmessage'] = 'Originalna poruka'; $labels['editidents'] = 'Uredi identitete'; -$labels['spellcheck'] = 'Pravopis'; +$labels['spellcheck'] = 'Spelovanje'; $labels['checkspelling'] = 'Provjera pravopisa'; $labels['resumeediting'] = 'Nastavi ureÄ‘ivanje'; $labels['revertto'] = 'Vrati na'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Prikaži zadnju stranicu'; $labels['group'] = 'Grupa'; $labels['groups'] = 'Grupe'; -$labels['listgroup'] = 'Izlistaj Älanove grupe'; $labels['personaladrbook'] = 'LiÄne adrese'; $labels['searchsave'] = 'SaÄuvaj pretragu'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Zanemari rijeÄi sa brojevima'; $labels['spellcheckignorecaps'] = 'Zanemari rijeÄi napisane velikim slovima'; $labels['addtodict'] = 'Dodaj u rjeÄnik'; $labels['mailtoprotohandler'] = 'Registruj upravljaÄ protokola za mailto: linkovi'; -$labels['standardwindows'] = 'Tretiraj popup-ove kao standardne prozore'; $labels['forwardmode'] = 'ProsljeÄ‘ivanje poruka'; $labels['inline'] = 'u istom redu'; $labels['asattachment'] = 'kao prilog'; diff --git a/program/localization/bs_BA/messages.inc b/program/localization/bs_BA/messages.inc index 09e6df19e..7a1b26168 100644 --- a/program/localization/bs_BA/messages.inc +++ b/program/localization/bs_BA/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Uklanjam formatiranje...'; $messages['messageopenerror'] = 'Nije moguće uÄitati poruku sa servera.'; $messages['fileuploaderror'] = 'Dodavanje datoteke nije uspjelo.'; $messages['filesizeerror'] = 'Datoteka je prevelika. Maksimalna veliÄina je $size.'; -$messages['copysuccess'] = 'UspjeÅ¡no kopirano $nr kontakata.'; -$messages['movesuccess'] = 'UspjeÅ¡no premjeÅ¡teno $nr kontakata.'; -$messages['copyerror'] = 'Nije moguće kopirati kontakte.'; -$messages['moveerror'] = 'Nije moguće premjestiti kontakte.'; +$messages['copysuccess'] = 'UspjeÅ¡no kopirano $n adresa.'; +$messages['copyerror'] = 'Nije moguće kopirati adrese.'; $messages['sourceisreadonly'] = 'Ovaj izvor adresa je samo za Äitanje.'; $messages['errorsavingcontact'] = 'Nije moguće saÄuvati kontakt adresu.'; $messages['movingmessage'] = 'PremjeÅ¡tam poruke...'; $messages['copyingmessage'] = 'Kopiram poruke...'; $messages['copyingcontact'] = 'Kopiram kontakte...'; -$messages['movingcontact'] = 'PremjeÅ¡tam kontakte...'; $messages['deletingmessage'] = 'BriÅ¡em poruke...'; $messages['markingmessage'] = 'OznaÄavam poruke...'; $messages['addingmember'] = 'Dodajem kontakte u grupu...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Uvoz u toku, molimo saÄekajte...'; $messages['importformaterror'] = 'Uvoz nije uspio! Dodana datoteka nije u ispravnom formatu za uvoz podataka.'; $messages['importconfirm'] = '<b>UspjeÅ¡no je uvezeno $inserted kontakata</b>'; $messages['importconfirmskipped'] = '<b>PreskoÄeno $skipped postojećih unosa</b>'; -$messages['importmessagesuccess'] = 'UspjeÅ¡no uvezeno $nr poruka'; -$messages['importmessageerror'] = 'Uvoz nije uspio! Dodana datoteke nije ispravna datoteka sa porukama'; $messages['opnotpermitted'] = 'Operacija nije dozvoljena!'; $messages['nofromaddress'] = 'U odabrani identitet nije upisana email adresa.'; $messages['editorwarning'] = 'Prebacivanje u obiÄni tekstualni ureÄ‘ivaÄ Ä‡e prouzrokovati gubljenje formatiranja teksta. Želite li nastaviti?'; diff --git a/program/localization/ca_ES/labels.inc b/program/localization/ca_ES/labels.inc index ca0129de4..3be753b68 100644 --- a/program/localization/ca_ES/labels.inc +++ b/program/localization/ca_ES/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Esborranys'; $labels['sent'] = 'Enviats'; $labels['trash'] = 'Paperera'; $labels['junk'] = 'Correu brossa'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Assumpte'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Mode de vista de llista'; $labels['folderactions'] = 'Accions de carpeta'; $labels['compact'] = 'Compacta'; $labels['empty'] = 'Buida'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Ús del disc'; $labels['unknown'] = 'desconegut'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Neteja cerca'; $labels['searchmod'] = 'Cerca modificadors'; $labels['msgtext'] = 'Missatge sencer'; $labels['body'] = 'Cos'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Obre a una nova finestra'; $labels['emlsave'] = 'Descarrega (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Mostra la darrera pà gina'; $labels['group'] = 'Grup'; $labels['groups'] = 'Grups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Llibreta d\'adreces'; $labels['searchsave'] = 'Desa la cerca'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignora paraules amb números'; $labels['spellcheckignorecaps'] = 'Ignora paraules amb lletres capitalitzades'; $labels['addtodict'] = 'Afegeix al diccionari'; $labels['mailtoprotohandler'] = 'Registra controlador de protocol pels enllaços mailto:'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Reenviament de missatges'; $labels['inline'] = 'en lÃnia'; $labels['asattachment'] = 'com adjunt'; diff --git a/program/localization/ca_ES/messages.inc b/program/localization/ca_ES/messages.inc index 9ee32d54e..70c3fbd0c 100644 --- a/program/localization/ca_ES/messages.inc +++ b/program/localization/ca_ES/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'S\'està traient el format del missatge...'; $messages['messageopenerror'] = 'No s\'ha pogut carregar el missatge del servidor.'; $messages['fileuploaderror'] = 'La pujada del fitxer ha fallat.'; $messages['filesizeerror'] = 'El fitxer pujat excedeix la mida mà xima de $size.'; -$messages['copysuccess'] = 'S\'han copiat $nr contactes correctament.'; -$messages['movesuccess'] = 'S\'han mogut $nr contactes correctament.'; -$messages['copyerror'] = 'No s\'ha pogut copiar cap contacte.'; -$messages['moveerror'] = 'No s\'ha pogut moure cap contacte.'; +$messages['copysuccess'] = 'S\'han copiat $nr adreces correctament.'; +$messages['copyerror'] = 'No s\'ha pogut copiar cap adreça.'; $messages['sourceisreadonly'] = 'Aquesta adreça és només de lectura.'; $messages['errorsavingcontact'] = 'No s\'ha pogut desar l\'adreça de contacte.'; $messages['movingmessage'] = 'S\'està movent missatge(s)...'; $messages['copyingmessage'] = 'S\'està copiant missatge(s)...'; $messages['copyingcontact'] = 'S\'està copiant contacte(s)...'; -$messages['movingcontact'] = 'S\'estan movent els contacte(s)...'; $messages['deletingmessage'] = 'S\'està suprimint missatge(s)...'; $messages['markingmessage'] = 'S\'està marcant missatge(s)...'; $messages['addingmember'] = 'S\'està afegint contacte(s) al grup...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'S\'està important, espereu si us plau...'; $messages['importformaterror'] = 'La importació ha fallat. El fitxer pujat no és un fitxer de dades và lid.'; $messages['importconfirm'] = '<b>S\'han importat $inserted contactes correctament</b>'; $messages['importconfirmskipped'] = '<b>S\'han descartat $skipped entrades ja existents</b>'; -$messages['importmessagesuccess'] = '<b>S\'han importat $nr missatges correctament</b>'; -$messages['importmessageerror'] = 'La importació ha fallat. El fitxer que heu pujat no és un fitxer de missatges và lid o no és un fitxer de bústia.'; $messages['opnotpermitted'] = 'Operació no permesa!'; $messages['nofromaddress'] = 'Falta l\'adreça de correu a la identitat seleccionada.'; $messages['editorwarning'] = 'Si canvieu a l\'editor de text pla perdreu tot el format del text. Voleu continuar?'; diff --git a/program/localization/cs_CZ/labels.inc b/program/localization/cs_CZ/labels.inc index b5cc093d8..8fb7ffade 100644 --- a/program/localization/cs_CZ/labels.inc +++ b/program/localization/cs_CZ/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Rozepsané'; $labels['sent'] = 'Odeslané'; $labels['trash'] = 'KoÅ¡'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Zobrazit skuteÄná jména speciálnÃch složek'; // message listing $labels['subject'] = 'PÅ™edmÄ›t'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Režim zobrazenà seznamu'; $labels['folderactions'] = 'Akce se složkou...'; $labels['compact'] = 'ZmenÅ¡it'; $labels['empty'] = 'Vymazat'; -$labels['importmessages'] = 'Import zpráv'; $labels['quota'] = 'Využità schránky'; $labels['unknown'] = 'neznámý'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ZruÅ¡it vyhledávánÃ'; $labels['searchmod'] = 'Parametry hledánÃ'; $labels['msgtext'] = 'Celá zpráva'; $labels['body'] = 'TÄ›lo'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'OtevÅ™Ãt v novém oknÄ›'; $labels['emlsave'] = 'Stáhnout (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Zobrazit poslednà zprávy'; $labels['group'] = 'Skupina'; $labels['groups'] = 'Skupiny'; -$labels['listgroup'] = ' Seznam Älenů skupiny'; $labels['personaladrbook'] = 'Osobnà kontakty'; $labels['searchsave'] = 'Uložit hledánÃ'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Vytvářet HTML zprávy'; $labels['htmlonreply'] = 'jen pÅ™i odpovÄ›di na HTML zprávy'; $labels['htmlonreplyandforward'] = 'pÅ™i pÅ™eposlánà nebo odpovÄ›di na HTML zprávu'; $labels['htmlsignature'] = 'HTML podpis'; -$labels['showemail'] = 'Zobrazit e-mailovou adresu se skuteÄným jménem'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Zobrazit panel náhledu'; $labels['skin'] = 'Vzhled'; $labels['logoutclear'] = 'Vyprázdnit koÅ¡ pÅ™i odhlášenÃ'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorovat slova obsahujÃcà ÄÃsla'; $labels['spellcheckignorecaps'] = 'Ignorovat slova psaná velkými pÃsmeny'; $labels['addtodict'] = 'PÅ™idat do slovnÃku'; $labels['mailtoprotohandler'] = 'Zaregistrovat handler pro odkazy „mailto:“'; -$labels['standardwindows'] = 'Zacházet s vyskakovacÃmi okny jako se standardnÃmi okny'; $labels['forwardmode'] = 'PÅ™eposlat zprávu'; $labels['inline'] = 'vloženÄ›'; $labels['asattachment'] = 'jako pÅ™Ãlohu'; diff --git a/program/localization/cs_CZ/messages.inc b/program/localization/cs_CZ/messages.inc index 59b2c6bd6..9800b2412 100644 --- a/program/localization/cs_CZ/messages.inc +++ b/program/localization/cs_CZ/messages.inc @@ -24,7 +24,7 @@ $messages['sessionerror'] = 'VaÅ¡e pÅ™ihlášenà je neplatné nebo vyprÅ¡elo'; $messages['storageerror'] = 'PÅ™ipojenà na IMAP server selhalo'; $messages['servererror'] = 'Chyba serveru!'; $messages['servererrormsg'] = 'Chyba serveru: $msg'; -$messages['dberror'] = 'Chyba databáze!'; +$messages['dberror'] = 'Chyba v databázi!'; $messages['requesttimedout'] = 'DoÅ¡lo k vyprÅ¡enà požadavku'; $messages['errorreadonly'] = 'PÅ™Ãkaz nelze provést, složka je urÄena jen ke ÄtenÃ.'; $messages['errornoperm'] = 'PÅ™Ãkaz nelze provést, nemáte oprávnÄ›nÃ.'; @@ -33,7 +33,7 @@ $messages['erroroverquotadelete'] = 'Nenà volné mÃsto na disku. Použijte SHI $messages['invalidrequest'] = 'Nesprávný požadavek. Data nebyla uložena.'; $messages['invalidhost'] = 'Å patné jméno serveru.'; $messages['nomessagesfound'] = 'Ve schránce nebyla nalezena žádná zpráva'; -$messages['loggedout'] = 'Byli jste úspěšnÄ› odhlášeni. Na shledanou!'; +$messages['loggedout'] = 'Byli jste úspěšnÄ› odhlášeni. Nashledanou!'; $messages['mailboxempty'] = 'Schránka je prázdná'; $messages['refreshing'] = 'Obnovuji...'; $messages['loading'] = 'NaÄÃtám...'; @@ -126,8 +126,6 @@ $messages['importwait'] = 'Importuji, prosÃm Äekejte...'; $messages['importformaterror'] = 'Import se nezdaÅ™il! Typ souboru nenà podporován.'; $messages['importconfirm'] = 'ÚspěšnÄ› naimportováno $inserted kontaktů, $skipped existujÃcÃch záznamů pÅ™eskoÄeno: $names'; $messages['importconfirmskipped'] = '<b>PÅ™eskoÄeno $skipped existujÃcÃch položek</b>'; -$messages['importmessagesuccess'] = 'ÚspěšnÄ› naimportováno $nr zpráv'; -$messages['importmessageerror'] = 'Import se nezdaÅ™il! Nahraný soubor nenà platnou zprávou nebo souborem mailboxu'; $messages['opnotpermitted'] = 'Operace nenà povolena!'; $messages['nofromaddress'] = 'ChybÄ›jÃcà e-mailová adresa v oznaÄeném profilu'; $messages['editorwarning'] = 'PÅ™epnutÃm do režimu prostého textu ztratÃte veÅ¡keré formátovánÃ. Chcete pokraÄovat?'; diff --git a/program/localization/cy_GB/labels.inc b/program/localization/cy_GB/labels.inc index ca1f17426..3e4f136bc 100644 --- a/program/localization/cy_GB/labels.inc +++ b/program/localization/cy_GB/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drafftiau'; $labels['sent'] = 'Danfonwyd'; $labels['trash'] = 'Sbwriel'; $labels['junk'] = 'Sothach'; -$labels['show_real_foldernames'] = 'Dangos enwau go-iawn ar gyfer ffolderi arbennig'; // message listing $labels['subject'] = 'Pwnc'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Golwg rhestr'; $labels['folderactions'] = 'Gweithredoedd ffolder...'; $labels['compact'] = 'Crynhoi'; $labels['empty'] = 'Gwagio'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Defnydd'; $labels['unknown'] = 'anhysbys'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Ail-osod chwiliad'; $labels['searchmod'] = 'Addasyddion chwilio'; $labels['msgtext'] = 'Y neges yn llawn'; $labels['body'] = 'Corff'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Agor mewn ffenest newydd'; $labels['emlsave'] = 'Llwytho lawr (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Dangos y set olaf'; $labels['group'] = 'Grŵp'; $labels['groups'] = 'Grwpiau'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Cyfeiriadau Personol'; $labels['searchsave'] = 'Cadw chwiliad'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Ysgrifennu negeseuon HTML'; $labels['htmlonreply'] = 'wrth ateb i neges HTML yn unig'; $labels['htmlonreplyandforward'] = 'wrth ddanfon ymlaen neu ymateb i neges HTML'; $labels['htmlsignature'] = 'Llofnod HTML'; -$labels['showemail'] = 'Dangos cyfeiriad ebost gyda\'r enw gweledig'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Dangos ffenest rhagolwg'; $labels['skin'] = 'Croen rhyngwyneb'; $labels['logoutclear'] = 'Clirio\'r Sbwriel wrth allgofnodi'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Anwybyddu geiriau gyda rhifau'; $labels['spellcheckignorecaps'] = 'Anwybyddu geiriau sy\'n briflythrennau yn gyfangwbl'; $labels['addtodict'] = 'Ychwanegu i\'r geiriadur'; $labels['mailtoprotohandler'] = 'Cofrestru trafodwr protocol ar gyfer dolenni mailto:'; -$labels['standardwindows'] = 'Trin ffenestri naid fel ffenestri arferol'; $labels['forwardmode'] = 'Danfon neges ymlaen'; $labels['inline'] = 'mewnlin'; $labels['asattachment'] = 'fel atodiad'; diff --git a/program/localization/cy_GB/messages.inc b/program/localization/cy_GB/messages.inc index 6323d8c9c..edadc3b45 100644 --- a/program/localization/cy_GB/messages.inc +++ b/program/localization/cy_GB/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Yn cael gwared a\'r fformatio...'; $messages['messageopenerror'] = 'Methwyd llwytho\'r neges o\'r gweinydd'; $messages['fileuploaderror'] = 'Methwyd llwytho\'r ffeil i fyny'; $messages['filesizeerror'] = 'Mae\'r ffeil a lwythyd fyny yn fwy na\'r maint uchaf ganiateir o $size'; -$messages['copysuccess'] = 'Copïwyd $nr cyswllt yn llwyddiannus'; -$messages['movesuccess'] = 'Symudwyd $nr cyswllt yn llwyddiannus.'; -$messages['copyerror'] = 'Methwyd copïo unrhyw gysylltiadau.'; -$messages['moveerror'] = 'Methwyd symud unrhyw gysylltiadau.'; +$messages['copysuccess'] = 'Copïwyd $nr cyfeiriad yn llwyddiannus'; +$messages['copyerror'] = 'Methwyd copïo unrhyw gyfeiriad'; $messages['sourceisreadonly'] = 'Mae ffynhonnell y cyfeiriadau i\'w ddarllen yn unig'; $messages['errorsavingcontact'] = 'Methwyd cadw cyfeiriad y cyswllt'; $messages['movingmessage'] = 'Yn symud neges...'; $messages['copyingmessage'] = 'Yn copïo\'r neges'; $messages['copyingcontact'] = 'Yn copïo cyswllt/cysylltiadau...'; -$messages['movingcontact'] = 'Yn symud cyswllt/cysylltiadau...'; $messages['deletingmessage'] = 'Yn dileu neges(euon)...'; $messages['markingmessage'] = 'Yn marcio neges(euon)...'; $messages['addingmember'] = 'Yn ychwanegu cyswllt/cysylltiadau i\'r grŵp...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Yn mewnforio, arhoswch os gwelwch yn dda...'; $messages['importformaterror'] = 'Methwyd mewnforio! Nid yw\'r ffeil a lwythwyd yn ffeil ddata dilys.'; $messages['importconfirm'] = '<b>Fe mewnforiwyd $inserted cyswllt yn llwyddiannus, anwybyddwyd $skipped cofnod presennol</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Neidiwyd $skipped cofnod oedd yn bodoli</b>'; -$messages['importmessagesuccess'] = 'Mewnforiwyd $nr neges yn llwyddiannus'; -$messages['importmessageerror'] = 'Methwyd mewnforio! Nid yw\'r ffeil a lwythwyd yn ffeil neges neu blwch ebost dilys'; $messages['opnotpermitted'] = 'Ni chaniateir y weithred!'; $messages['nofromaddress'] = 'Cyfeiriad e-bost ar goll yn y personoliaeth a ddewiswyd'; $messages['editorwarning'] = 'Mi fydd newid i\'r golygydd testun plaen yn golygu byddwch chi\'n colli unrhyw arddulliau yn eich testun. Hoffech chi barhau?'; diff --git a/program/localization/da_DK/labels.inc b/program/localization/da_DK/labels.inc index a5b9b3bc8..02d7dd9e3 100644 --- a/program/localization/da_DK/labels.inc +++ b/program/localization/da_DK/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Kladder'; $labels['sent'] = 'Sendt post'; $labels['trash'] = 'Papirkurv'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Emne'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Listevisningsmode'; $labels['folderactions'] = 'Mappehandlinger...'; $labels['compact'] = 'Ryd op'; $labels['empty'] = 'Tøm'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Diskforbrug'; $labels['unknown'] = 'ukendt'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Nulstil søgning'; $labels['searchmod'] = 'Søgeparametre'; $labels['msgtext'] = 'Hele beskeden'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Ã…bn i nyt vindue'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Vis sidste side'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Grupper'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personlige adresser'; $labels['searchsave'] = 'Gem søgning'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Skriv HTML-besked'; $labels['htmlonreply'] = 'kun nÃ¥r jeg besvarer HTML-beskeder'; $labels['htmlonreplyandforward'] = 'ved videresendelse eller besvarelse af HTML beskeder'; $labels['htmlsignature'] = 'HTML-signatur'; -$labels['showemail'] = 'Vis email-adresse med vist navn'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'ForhÃ¥ndsvisning'; $labels['skin'] = 'Brugerflade'; $labels['logoutclear'] = 'Tøm Papirkurv nÃ¥r jeg logger af'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorer ord med tal'; $labels['spellcheckignorecaps'] = 'Ignorer ord hvor alle bogstaver er versaler'; $labels['addtodict'] = 'Tilføj til ordbog'; $labels['mailtoprotohandler'] = 'Registrer hÃ¥ndtering af \'mailto:\' links'; -$labels['standardwindows'] = 'Behandl popups som standardvinduer'; $labels['forwardmode'] = 'Videresendelse af besked'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'som vedhæftning'; diff --git a/program/localization/da_DK/messages.inc b/program/localization/da_DK/messages.inc index 7429fd4e5..9a0b8e4a5 100644 --- a/program/localization/da_DK/messages.inc +++ b/program/localization/da_DK/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Fjerner formatering fra besked...'; $messages['messageopenerror'] = 'Beskeden kunne ikke hentes fra serveren.'; $messages['fileuploaderror'] = 'Upload mislykkedes.'; $messages['filesizeerror'] = 'Den indsatte fil fylder mere end det maksimale pÃ¥ $size.'; -$messages['copysuccess'] = '$nr blev kopieret.'; -$messages['movesuccess'] = '$nr kontakter blev flyttet.'; -$messages['copyerror'] = 'Kunne ikke kopiere nogen kontakter.'; -$messages['moveerror'] = 'Kunne ikke flytte nogen kontakter.'; +$messages['copysuccess'] = 'Det lykkedes at kopiere $nr adresser.'; +$messages['copyerror'] = 'Kunne ikke kopiere adresserne.'; $messages['sourceisreadonly'] = 'Denne adressekilde er kun til læsning.'; $messages['errorsavingcontact'] = 'Kunne ikke gemme kontaktadressen.'; $messages['movingmessage'] = 'Flytter besked(er)...'; $messages['copyingmessage'] = 'Kopierer besked(er)...'; $messages['copyingcontact'] = 'Kopierer kontakt(er)...'; -$messages['movingcontact'] = 'Flytter kontakt(er)...'; $messages['deletingmessage'] = 'Sletter besked(er)...'; $messages['markingmessage'] = 'Markerer besked(er)...'; $messages['addingmember'] = 'Tilføjer kontakt(er) til gruppen...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importerer, vent venligst...'; $messages['importformaterror'] = 'Importering mislykkedes! Den uploadede fil indeholder ikke gyldige data til importering.'; $messages['importconfirm'] = '<b>Importerede $inserted kontakter</b>'; $messages['importconfirmskipped'] = '<b>Sprang over $skipped eksisterende kontakter</b>'; -$messages['importmessagesuccess'] = 'Importerede $nr beskeder'; -$messages['importmessageerror'] = 'Import mislykkedes! Den uploadede fil er ikke en gyldig besked eller mailbox-fil'; $messages['opnotpermitted'] = 'Handlingen er ikke tilladt!'; $messages['nofromaddress'] = 'Der mangler en e-mailadresse i den valgte identitet.'; $messages['editorwarning'] = 'Al formatering af teksten forsvinder, hvis der skiftes til ren tekst. Vil du fortsætte?'; diff --git a/program/localization/de_CH/labels.inc b/program/localization/de_CH/labels.inc index 67d42bb05..e64859d2c 100644 --- a/program/localization/de_CH/labels.inc +++ b/program/localization/de_CH/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Entwürfe'; $labels['sent'] = 'Gesendet'; $labels['trash'] = 'Gelöscht'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Spezialordner nicht übersetzen'; // message listing $labels['subject'] = 'Betreff'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Anzeigemodus'; $labels['folderactions'] = 'Ordneraktionen...'; $labels['compact'] = 'Packen'; $labels['empty'] = 'Leeren'; -$labels['importmessages'] = 'Nachrichten importieren'; $labels['quota'] = 'Verwendeter Speicherplatz'; $labels['unknown'] = 'unbekannt'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Löschen'; $labels['searchmod'] = 'Suchkriterien ändern'; $labels['msgtext'] = 'Ganze Nachricht'; $labels['body'] = 'Inhalt'; -$labels['type'] = 'Typ'; $labels['openinextwin'] = 'In neuem Fenster öffnen'; $labels['emlsave'] = 'Herunterladen (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Letzte Seite'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Gruppen'; -$labels['listgroup'] = 'Gruppenmitglieder anzeigen'; $labels['personaladrbook'] = 'Persönliches Adressbuch'; $labels['searchsave'] = 'Suche speichern'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Wörter mit Ziffern überspringen'; $labels['spellcheckignorecaps'] = 'Wörter überspringen, die nur aus Grossbuchstaben bestehen'; $labels['addtodict'] = 'Zum Wörterbuch hinzufügen'; $labels['mailtoprotohandler'] = 'Als Empfänger für mailto: Links einrichten'; -$labels['standardwindows'] = 'Popups als normale Browserfenster öffnen'; $labels['forwardmode'] = 'Weiterleiten einer Nachricht'; $labels['inline'] = 'eingebettet'; $labels['asattachment'] = 'als Anhang'; diff --git a/program/localization/de_CH/messages.inc b/program/localization/de_CH/messages.inc index 27175be9e..f3697a825 100644 --- a/program/localization/de_CH/messages.inc +++ b/program/localization/de_CH/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Daten werden importiert, bitte warten...'; $messages['importformaterror'] = 'Import fehlgeschlagen! Die hochgeladene Datei enthält keines der unterstützten Datenformate.'; $messages['importconfirm'] = '<b>Es wurden $inserted Adressen erfolgreich importiert</b>'; $messages['importconfirmskipped'] = '<b>$skipped bestehende Einträge wurden übersprungen</b>'; -$messages['importmessagesuccess'] = '$nr Nachricht(n) erfolgreich importiert'; -$messages['importmessageerror'] = 'Import fehlgeschlagen! Die hochgeladene Datei ist keine E-Mail-Nachricht oder Mailbox-Datei.'; $messages['opnotpermitted'] = 'Operation nicht erlaubt!'; $messages['nofromaddress'] = 'Fehlende E-Mail-Adresse in ausgewählter Identität.'; $messages['editorwarning'] = 'Beim Wechseln in den Texteditor gehen alle Textformatierungen verloren. Möchten Sie fortfahren?'; diff --git a/program/localization/de_DE/labels.inc b/program/localization/de_DE/labels.inc index 662ad2c70..d497a6bc6 100644 --- a/program/localization/de_DE/labels.inc +++ b/program/localization/de_DE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Entwürfe'; $labels['sent'] = 'Gesendet'; $labels['trash'] = 'Gelöscht'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Echte Namen für Spezialordner anzeigen'; // message listing $labels['subject'] = 'Betreff'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Anzeigemodus'; $labels['folderactions'] = 'Ordneraktionen...'; $labels['compact'] = 'Packen'; $labels['empty'] = 'Leeren'; -$labels['importmessages'] = 'Nachrichten importieren'; $labels['quota'] = 'Speicherplatz'; $labels['unknown'] = 'unbekannt'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Suche zurücksetzen'; $labels['searchmod'] = 'Suchkriterien ändern'; $labels['msgtext'] = 'Nachricht'; $labels['body'] = 'Inhalt'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'In neuem Fenster öffnen'; $labels['emlsave'] = 'Lokal speichern (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Letzte Seite'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Gruppen'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Persönliches Adressbuch'; $labels['searchsave'] = 'Suchergebnisse speichern'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'HTML-Nachrichten verfassen'; $labels['htmlonreply'] = 'nur Antworten auf HTML-Nachrichten'; $labels['htmlonreplyandforward'] = 'beim Weiterleiten und Beantworten auf HTML-Nachrichten'; $labels['htmlsignature'] = 'HTML-Signatur'; -$labels['showemail'] = 'E-Mail-Adresse mit dem Display Namen anzeigen'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Nachrichtenvorschau anzeigen'; $labels['skin'] = 'Oberflächendesign'; $labels['logoutclear'] = 'Papierkorb beim Abmelden leeren'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Wörter mit Ziffern überspringen'; $labels['spellcheckignorecaps'] = 'Wörter überspringen, die nur aus Großbuchstaben bestehen'; $labels['addtodict'] = 'Zum Wörterbuch hinzufügen'; $labels['mailtoprotohandler'] = 'Als Empfänger für mailto: Links einrichten'; -$labels['standardwindows'] = 'Popups als Standard Windows behandeln'; $labels['forwardmode'] = 'Nachrichtenweiterleitung'; $labels['inline'] = 'eingebettet'; $labels['asattachment'] = 'als Anhang'; diff --git a/program/localization/de_DE/messages.inc b/program/localization/de_DE/messages.inc index 7b6099924..ba0936d28 100644 --- a/program/localization/de_DE/messages.inc +++ b/program/localization/de_DE/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Entferne Formatierungen...'; $messages['messageopenerror'] = 'Die Nachricht konnte nicht vom Server geladen werden.'; $messages['fileuploaderror'] = 'Hochladen der Datei fehlgeschlagen.'; $messages['filesizeerror'] = 'Die hochzuladende Datei überschreitet die Maximalgröße von $size.'; -$messages['copysuccess'] = 'Erfolgreich kopiert $ nr Kontakte.'; -$messages['movesuccess'] = 'Erfolgreich verschoben $ nr Kontakte.'; -$messages['copyerror'] = 'Die Kontakte konnten nicht kopiert werden.'; -$messages['moveerror'] = 'Die Kontakte konnten nicht verschoben werden.'; +$messages['copysuccess'] = '$nr Adressen erfolgreich kopiert.'; +$messages['copyerror'] = 'Die Adressen konnten nicht kopiert werden.'; $messages['sourceisreadonly'] = 'Das Adressverzeichnis kann nicht verändert werden.'; $messages['errorsavingcontact'] = 'Die Änderungen konnten nicht gespeichert werden.'; $messages['movingmessage'] = 'Die E-Mail wird verschoben...'; $messages['copyingmessage'] = 'Kopiere Nachrichten...'; $messages['copyingcontact'] = 'Kontakte werden kopiert...'; -$messages['movingcontact'] = 'Kontakt(e) wird verschoben...'; $messages['deletingmessage'] = 'Lösche Nachricht(en)...'; $messages['markingmessage'] = 'Markiere Nachricht(en)...'; $messages['addingmember'] = 'Füge Kontakte der Gruppe hinzu...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Daten werden importiert, bitte warten...'; $messages['importformaterror'] = 'Import fehlgeschlagen! Die hochgeladene Datei ist keine gültige Importdatei.'; $messages['importconfirm'] = '<b>Es wurden $inserted Adressen erfolgreich importiert.</b>'; $messages['importconfirmskipped'] = '<b>$skipped bestehende Einträge wurden übersprungen.</b>'; -$messages['importmessagesuccess'] = 'Nachrichten $nr erfolgreich importiert'; -$messages['importmessageerror'] = 'Import fehlgeschlagen! Die hochgeladene Datei ist keine gültige Importdatei.'; $messages['opnotpermitted'] = 'Operation nicht erlaubt!'; $messages['nofromaddress'] = 'Fehlende E-Mail-Adresse in ausgewählter Identität.'; $messages['editorwarning'] = 'Beim Wechseln in den Texteditor gehen alle Textformatierungen verloren. Möchten Sie fortfahren?'; diff --git a/program/localization/el_GR/labels.inc b/program/localization/el_GR/labels.inc index d3030e574..9f5d81839 100644 --- a/program/localization/el_GR/labels.inc +++ b/program/localization/el_GR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Î ÏόχειÏα'; $labels['sent'] = 'ΑπεσταλμÎνα'; $labels['trash'] = 'Κάδος ΑποÏÏιμάτων'; $labels['junk'] = 'ΑνεπιθÏμητα'; -$labels['show_real_foldernames'] = 'Εμφάνιση Ï€Ïαγματικών ονομάτων για ειδικοÏÏ‚ φακÎλους'; // message listing $labels['subject'] = 'ΘÎμα'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Î Ïοβολή σε λίστα'; $labels['folderactions'] = 'ΕνÎÏγειες στους φακÎλους'; $labels['compact'] = 'Συμπίεση'; $labels['empty'] = 'Άδειασμα'; -$labels['importmessages'] = 'Εισαγωγή μηνυμάτων'; $labels['quota'] = 'ΧÏήση δίσκου'; $labels['unknown'] = 'άγνωστο'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ΕπαναφοÏά Αναζήτησης'; $labels['searchmod'] = 'Aλλαγή αναζήτησης'; $labels['msgtext'] = 'Σε όλο το μήνυμα'; $labels['body'] = 'Σώμα'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Άνοιγμα σε νÎο παÏάθυÏο'; $labels['emlsave'] = 'Λήψη αÏχείου (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Εμφάνιση της τελευταίας σελ $labels['group'] = 'Ομάδα'; $labels['groups'] = 'Ομάδες'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Î ÏοσωπικÎÏ‚ ΔιυθÏνσεις'; $labels['searchsave'] = 'Αποθήκευση αναζήτησης'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Οι λÎξεις που πεÏιÎχουν Î $labels['spellcheckignorecaps'] = 'Οι λÎξεις γÏαμμÎνες με ΚΕΦΑΛΑΙΑ να αγνοοÏνται'; $labels['addtodict'] = 'Î Ïοσθήκη στο λεξικό'; $labels['mailtoprotohandler'] = 'ΚαταχώÏηση διαχείÏισης Ï€Ïωτοκόλλου δεσμών mailto:'; -$labels['standardwindows'] = 'ΧειÏιστείτε τα αναδυόμενα παÏάθυÏα ως Ï€Ïότυπο των Windows'; $labels['forwardmode'] = 'Î Ïοώθηση μηνυμάτων'; $labels['inline'] = 'με εσνωμάτωση'; $labels['asattachment'] = 'σαν επισÏναψη'; diff --git a/program/localization/el_GR/messages.inc b/program/localization/el_GR/messages.inc index 504baa674..dc2499d8b 100644 --- a/program/localization/el_GR/messages.inc +++ b/program/localization/el_GR/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Μετακίνηση διαμοÏφώσεων κειΠ$messages['messageopenerror'] = 'Η φόÏτωση μηνυμάτων από τον διακομιστή απÎτυχε'; $messages['fileuploaderror'] = 'ΑνÎβασμα αÏχείου απÎτυχε'; $messages['filesizeerror'] = 'Το ανεβασμÎνο αÏχείο ξεπεÏνάει το μÎγιστο μÎγεθος των $size'; -$messages['copysuccess'] = 'Επιτυχής αντιγÏαφή $ επαφών αÏιθ..'; -$messages['movesuccess'] = 'Με επιτυχία μεταφÎÏθηκαν $ αÏιθ. επαφÎÏ‚.'; -$messages['copyerror'] = 'Αποτυχία αντιγÏαφής επαφών.'; -$messages['moveerror'] = 'Δεν μποÏοÏσε να κινηθεί καμία επαφή.'; +$messages['copysuccess'] = 'Επιτυχής αντιγÏαφή $nr διευθÏνσεων'; +$messages['copyerror'] = 'Αποτυχία αντιγÏαφής διευθÏνσεων'; $messages['sourceisreadonly'] = 'Η διεÏθυνση Îχει μόνο δικαίωμα ανάγνωσης'; $messages['errorsavingcontact'] = 'Αποθήκευση επαφής απÎτυχε'; $messages['movingmessage'] = 'Μετακίνηση μηνÏματος...'; $messages['copyingmessage'] = 'ΑντιγÏαφή μηνυμάτων...'; $messages['copyingcontact'] = 'ΑντιγÏαφή επαφών...'; -$messages['movingcontact'] = 'Μετακίνηση επαφής(ων)...'; $messages['deletingmessage'] = 'ΔιαγÏαφή μηνυμάτων...'; $messages['markingmessage'] = 'Σήμανση μηνυμάτων...'; $messages['addingmember'] = 'Î Ïοσθήκη επαφών στην ομάδα...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Εισαγωγή, παÏακαλώ πεÏιμÎνετ $messages['importformaterror'] = 'Η εισαγωγή απÎτυχε! Το αÏχείο δεν είναι ÎγκυÏο εισαγωγής δεδομÎνων.'; $messages['importconfirm'] = '<b>Εισήχθησαν $inserted επαφÎÏ‚ με επιτυχία</b>'; $messages['importconfirmskipped'] = '<b>ΠαÏαλήφθηκαν $skipped υπάÏχοντα αντικείμενα</b>'; -$messages['importmessagesuccess'] = 'Επιτυχής εισαγωγή $nr μηνυμάτων'; -$messages['importmessageerror'] = 'Η εισαγωγή απÎτυχε! Το αÏχείο δεν είναι ÎγκυÏο εισαγωγής δεδομÎνων.'; $messages['opnotpermitted'] = 'Η λειτουÏγία δεν επιτÏÎπεται!'; $messages['nofromaddress'] = 'Στην επιλεγμÎνη ταυτότητα, λείπει η email διεÏθυνση'; $messages['editorwarning'] = 'Η μετάβαση στην επεξεÏγασία Î±Ï€Î»Î¿Ï ÎºÎµÎ¹Î¼Îνου θα Ï€ÏοκαλÎσει κατάÏγηση της μοÏφοποίησης. Είστε βÎβαιοι πως θÎλετε να συνεχίσετε;'; diff --git a/program/localization/en_GB/labels.inc b/program/localization/en_GB/labels.inc index f903b0cf5..275208a98 100644 --- a/program/localization/en_GB/labels.inc +++ b/program/localization/en_GB/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drafts'; $labels['sent'] = 'Sent'; $labels['trash'] = 'Deleted Items'; $labels['junk'] = 'Junk'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Subject'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compact'; $labels['empty'] = 'Empty'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'unknown'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reset search'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last set'; $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalised'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/en_GB/messages.inc b/program/localization/en_GB/messages.inc index bba70b148..e5c873c94 100644 --- a/program/localization/en_GB/messages.inc +++ b/program/localization/en_GB/messages.inc @@ -17,7 +17,7 @@ */ $messages = array(); -$messages['errortitle'] = 'An error occured.'; +$messages['errortitle'] = 'An error occurred.'; $messages['loginfailed'] = 'Login failed.'; $messages['cookiesdisabled'] = 'Your browser does not accept cookies.'; $messages['sessionerror'] = 'Your session is invalid or has expired.'; @@ -101,16 +101,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address book is read-only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; @@ -144,7 +139,7 @@ $messages['smtperror'] = 'SMTP Error: $msg'; $messages['emailformaterror'] = 'Incorrect e-mail address: $email'; $messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.'; $messages['maxgroupmembersreached'] = 'The number of group members exceeds the maximum of $max.'; -$messages['internalerror'] = 'An internal error occured. Please try again.'; +$messages['internalerror'] = 'An internal error occurred. Please try again.'; $messages['contactdelerror'] = 'Could not delete contact(s).'; $messages['contactdeleted'] = 'Contact(s) deleted successfully.'; $messages['contactrestoreerror'] = 'Could not restore deleted contact(s).'; diff --git a/program/localization/en_US/csv2vcard.inc b/program/localization/en_US/csv2vcard.inc index e7b86795b..eb884f59a 100644 --- a/program/localization/en_US/csv2vcard.inc +++ b/program/localization/en_US/csv2vcard.inc @@ -5,7 +5,7 @@ | localization/<lang>/csv2vcard.inc | | | | Localization file of the Roundcube Webmail client | - | Copyright (C) 2005-2013, 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. | @@ -91,20 +91,3 @@ $map['work_phone'] = "Work Phone"; $map['work_address'] = "Work Address"; $map['work_country'] = "Work Country"; $map['work_zipcode'] = "Work ZipCode"; - -// Atmail -$map['date_of_birth'] = "Date of Birth"; -$map['email'] = "Email"; -$map['home_mobile'] = "Home Mobile"; -$map['home_zip'] = "Home Zip"; -$map['info'] = "Info"; -$map['user_photo'] = "User Photo"; -$map['url'] = "URL"; -$map['work_city'] = "Work City"; -$map['work_company'] = "Work Company"; -$map['work_dept'] = "Work Dept"; -$map['work_fax'] = "Work Fax"; -$map['work_mobile'] = "Work Mobile"; -$map['work_state'] = "Work State"; -$map['work_title'] = "Work Title"; -$map['work_zip'] = "Work Zip"; diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 840c9358c..1a753ec12 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -5,7 +5,7 @@ | localization/<lang>/labels.inc | | | | Localization file of the Roundcube Webmail client | - | Copyright (C) 2005-2013, 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. | @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drafts'; $labels['sent'] = 'Sent'; $labels['trash'] = 'Trash'; $labels['junk'] = 'Junk'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Subject'; @@ -65,7 +64,6 @@ $labels['copy'] = 'Copy'; $labels['move'] = 'Move'; $labels['moveto'] = 'Move to...'; $labels['download'] = 'Download'; -$labels['open'] = 'Open'; $labels['showattachment'] = 'Show'; $labels['showanyway'] = 'Show it anyway'; @@ -163,7 +161,6 @@ $labels['currpage'] = 'Current page'; $labels['unread'] = 'Unread'; $labels['flagged'] = 'Flagged'; $labels['unanswered'] = 'Unanswered'; -$labels['withattachment'] = 'With attachment'; $labels['deleted'] = 'Deleted'; $labels['undeleted'] = 'Not deleted'; $labels['invert'] = 'Invert'; @@ -194,7 +191,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compact'; $labels['empty'] = 'Empty'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'unknown'; @@ -205,13 +201,9 @@ $labels['resetsearch'] = 'Reset search'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; -$labels['namex'] = 'Name'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; -$labels['changeformattext'] = 'Display in plain text format'; -$labels['changeformathtml'] = 'Display in HTML format'; // message compose $labels['editasnew'] = 'Edit as new'; @@ -343,8 +335,6 @@ $labels['composeto'] = 'Compose mail to'; $labels['contactsfromto'] = 'Contacts $from to $to of $count'; $labels['print'] = 'Print'; $labels['export'] = 'Export'; -$labels['exportall'] = 'Export all'; -$labels['exportsel'] = 'Export selected'; $labels['exportvcards'] = 'Export contacts in vCard format'; $labels['newcontactgroup'] = 'Create new contact group'; $labels['grouprename'] = 'Rename group'; @@ -358,7 +348,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -367,11 +356,8 @@ $labels['searchdelete'] = 'Delete search'; $labels['import'] = 'Import'; $labels['importcontacts'] = 'Import contacts'; $labels['importfromfile'] = 'Import from file:'; -$labels['importtarget'] = 'Add contacts to'; +$labels['importtarget'] = 'Add new contacts to address book:'; $labels['importreplace'] = 'Replace the entire address book'; -$labels['importgroups'] = 'Import group assignments'; -$labels['importgroupsall'] = 'All (create groups if necessary)'; -$labels['importgroupsexisting'] = 'Only for existing groups'; $labels['importdesc'] = 'You can upload contacts from an existing address book.<br/>We currently support importing addresses from the <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> or CSV (comma-separated) data format.'; $labels['done'] = 'Done'; @@ -410,7 +396,6 @@ $labels['htmleditor'] = 'Compose HTML messages'; $labels['htmlonreply'] = 'on reply to HTML message'; $labels['htmlonreplyandforward'] = 'on forward or reply to HTML message'; $labels['htmlsignature'] = 'HTML signature'; -$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Show preview pane'; $labels['skin'] = 'Interface skin'; $labels['logoutclear'] = 'Clear Trash on logout'; @@ -480,7 +465,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/en_US/labels.inc.orig b/program/localization/en_US/labels.inc.orig new file mode 100644 index 000000000..d49e44b2c --- /dev/null +++ b/program/localization/en_US/labels.inc.orig @@ -0,0 +1,537 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | localization/<lang>/labels.inc | + | | + | Localization file of the Roundcube Webmail client | + | 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. | + | See the README file for a full license statement. | + | | + +-----------------------------------------------------------------------+ + + For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/labels/ +*/ + +$labels = array(); + +// login page +$labels['welcome'] = 'Welcome to $product'; +$labels['username'] = 'Username'; +$labels['password'] = 'Password'; +$labels['server'] = 'Server'; +$labels['login'] = 'Login'; + +// taskbar +$labels['logout'] = 'Logout'; +$labels['mail'] = 'Mail'; +$labels['settings'] = 'Settings'; +$labels['addressbook'] = 'Address Book'; + +// mailbox names +$labels['inbox'] = 'Inbox'; +$labels['drafts'] = 'Drafts'; +$labels['sent'] = 'Sent'; +$labels['trash'] = 'Trash'; +$labels['junk'] = 'Junk'; + +// message listing +$labels['subject'] = 'Subject'; +$labels['from'] = 'From'; +$labels['sender'] = 'Sender'; +$labels['to'] = 'To'; +$labels['cc'] = 'Cc'; +$labels['bcc'] = 'Bcc'; +$labels['replyto'] = 'Reply-To'; +$labels['followupto'] = 'Followup-To'; +$labels['date'] = 'Date'; +$labels['size'] = 'Size'; +$labels['priority'] = 'Priority'; +$labels['organization'] = 'Organization'; +$labels['readstatus'] = 'Read status'; +$labels['listoptions'] = 'List options...'; + +$labels['mailboxlist'] = 'Folders'; +$labels['messagesfromto'] = 'Messages $from to $to of $count'; +$labels['threadsfromto'] = 'Threads $from to $to of $count'; +$labels['messagenrof'] = 'Message $nr of $count'; +$labels['fromtoshort'] = '$from – $to of $count'; + +$labels['copy'] = 'Copy'; +$labels['move'] = 'Move'; +$labels['moveto'] = 'Move to...'; +$labels['download'] = 'Download'; +$labels['showattachment'] = 'Show'; +$labels['showanyway'] = 'Show it anyway'; + +$labels['filename'] = 'File name'; +$labels['filesize'] = 'File size'; + +$labels['addtoaddressbook'] = 'Add to address book'; + +// weekdays short +$labels['sun'] = 'Sun'; +$labels['mon'] = 'Mon'; +$labels['tue'] = 'Tue'; +$labels['wed'] = 'Wed'; +$labels['thu'] = 'Thu'; +$labels['fri'] = 'Fri'; +$labels['sat'] = 'Sat'; + +// weekdays long +$labels['sunday'] = 'Sunday'; +$labels['monday'] = 'Monday'; +$labels['tuesday'] = 'Tuesday'; +$labels['wednesday'] = 'Wednesday'; +$labels['thursday'] = 'Thursday'; +$labels['friday'] = 'Friday'; +$labels['saturday'] = 'Saturday'; + +// months short +$labels['jan'] = 'Jan'; +$labels['feb'] = 'Feb'; +$labels['mar'] = 'Mar'; +$labels['apr'] = 'Apr'; +$labels['may'] = 'May'; +$labels['jun'] = 'Jun'; +$labels['jul'] = 'Jul'; +$labels['aug'] = 'Aug'; +$labels['sep'] = 'Sep'; +$labels['oct'] = 'Oct'; +$labels['nov'] = 'Nov'; +$labels['dec'] = 'Dec'; + +// months long +$labels['longjan'] = 'January'; +$labels['longfeb'] = 'February'; +$labels['longmar'] = 'March'; +$labels['longapr'] = 'April'; +$labels['longmay'] = 'May'; +$labels['longjun'] = 'June'; +$labels['longjul'] = 'July'; +$labels['longaug'] = 'August'; +$labels['longsep'] = 'September'; +$labels['longoct'] = 'October'; +$labels['longnov'] = 'November'; +$labels['longdec'] = 'December'; + +$labels['today'] = 'Today'; + +// toolbar buttons +$labels['refresh'] = 'Refresh'; +$labels['checkmail'] = 'Check for new messages'; +$labels['compose'] = 'Compose'; +$labels['writenewmessage'] = 'Create a new message'; +$labels['reply'] = 'Reply'; +$labels['replytomessage'] = 'Reply to sender'; +$labels['replytoallmessage'] = 'Reply to list or to sender and all recipients'; +$labels['replyall'] = 'Reply all'; +$labels['replylist'] = 'Reply list'; +$labels['forward'] = 'Forward'; +$labels['forwardinline'] = 'Forward inline'; +$labels['forwardattachment'] = 'Forward as attachment'; +$labels['forwardmessage'] = 'Forward the message'; +$labels['deletemessage'] = 'Delete message'; +$labels['movemessagetotrash'] = 'Move message to trash'; +$labels['printmessage'] = 'Print this message'; +$labels['previousmessage'] = 'Show previous message'; +$labels['firstmessage'] = 'Show first message'; +$labels['nextmessage'] = 'Show next message'; +$labels['lastmessage'] = 'Show last message'; +$labels['backtolist'] = 'Back to message list'; +$labels['viewsource'] = 'Show source'; +$labels['mark'] = 'Mark'; +$labels['markmessages'] = 'Mark messages'; +$labels['markread'] = 'As read'; +$labels['markunread'] = 'As unread'; +$labels['markflagged'] = 'As flagged'; +$labels['markunflagged'] = 'As unflagged'; +$labels['moreactions'] = 'More actions...'; +$labels['more'] = 'More'; +$labels['back'] = 'Back'; +$labels['options'] = 'Options'; + +$labels['select'] = 'Select'; +$labels['all'] = 'All'; +$labels['none'] = 'None'; +$labels['currpage'] = 'Current page'; +$labels['unread'] = 'Unread'; +$labels['flagged'] = 'Flagged'; +$labels['unanswered'] = 'Unanswered'; +$labels['deleted'] = 'Deleted'; +$labels['undeleted'] = 'Not deleted'; +$labels['invert'] = 'Invert'; +$labels['filter'] = 'Filter'; +$labels['list'] = 'List'; +$labels['threads'] = 'Threads'; +$labels['expand-all'] = 'Expand All'; +$labels['expand-unread'] = 'Expand Unread'; +$labels['collapse-all'] = 'Collapse All'; +$labels['threaded'] = 'Threaded'; + +$labels['autoexpand_threads'] = 'Expand message threads'; +$labels['do_expand'] = 'all threads'; +$labels['expand_only_unread'] = 'only with unread messages'; +$labels['fromto'] = 'From/To'; +$labels['flag'] = 'Flag'; +$labels['attachment'] = 'Attachment'; +$labels['nonesort'] = 'None'; +$labels['sentdate'] = 'Sent date'; +$labels['arrival'] = 'Arrival date'; +$labels['asc'] = 'ascending'; +$labels['desc'] = 'descending'; +$labels['listcolumns'] = 'List columns'; +$labels['listsorting'] = 'Sorting column'; +$labels['listorder'] = 'Sorting order'; +$labels['listmode'] = 'List view mode'; + +$labels['folderactions'] = 'Folder actions...'; +$labels['compact'] = 'Compact'; +$labels['empty'] = 'Empty'; + +$labels['quota'] = 'Disk usage'; +$labels['unknown'] = 'unknown'; +$labels['unlimited'] = 'unlimited'; + +$labels['quicksearch'] = 'Quick search'; +$labels['resetsearch'] = 'Reset search'; +$labels['searchmod'] = 'Search modifiers'; +$labels['msgtext'] = 'Entire message'; +$labels['body'] = 'Body'; + +$labels['openinextwin'] = 'Open in new window'; +$labels['emlsave'] = 'Download (.eml)'; + +// message compose +$labels['editasnew'] = 'Edit as new'; +$labels['send'] = 'Send'; +$labels['sendmessage'] = 'Send message'; +$labels['savemessage'] = 'Save as draft'; +$labels['addattachment'] = 'Attach a file'; +$labels['charset'] = 'Charset'; +$labels['editortype'] = 'Editor type'; +$labels['returnreceipt'] = 'Return receipt'; +$labels['dsn'] = 'Delivery status notification'; +$labels['mailreplyintro'] = 'On $date, $sender wrote:'; +$labels['originalmessage'] = 'Original Message'; + +$labels['editidents'] = 'Edit identities'; +$labels['spellcheck'] = 'Spell'; +$labels['checkspelling'] = 'Check spelling'; +$labels['resumeediting'] = 'Resume editing'; +$labels['revertto'] = 'Revert to'; + +$labels['attach'] = 'Attach'; +$labels['attachments'] = 'Attachments'; +$labels['upload'] = 'Upload'; +$labels['uploadprogress'] = '$percent ($current from $total)'; +$labels['close'] = 'Close'; +$labels['messageoptions'] = 'Message options...'; + +$labels['low'] = 'Low'; +$labels['lowest'] = 'Lowest'; +$labels['normal'] = 'Normal'; +$labels['high'] = 'High'; +$labels['highest'] = 'Highest'; + +$labels['nosubject'] = '(no subject)'; +$labels['showimages'] = 'Display images'; +$labels['alwaysshow'] = 'Always show images from $sender'; +$labels['isdraft'] = 'This is a draft message.'; +$labels['andnmore'] = '$nr more...'; +$labels['togglemoreheaders'] = 'Show more message headers'; +$labels['togglefullheaders'] = 'Toggle raw message headers'; + +$labels['htmltoggle'] = 'HTML'; +$labels['plaintoggle'] = 'Plain text'; +$labels['savesentmessagein'] = 'Save sent message in'; +$labels['dontsave'] = 'don\'t save'; +$labels['maxuploadsize'] = 'Maximum allowed file size is $size'; + +$labels['addcc'] = 'Add Cc'; +$labels['addbcc'] = 'Add Bcc'; +$labels['addreplyto'] = 'Add Reply-To'; +$labels['addfollowupto'] = 'Add Followup-To'; + +// mdn +$labels['mdnrequest'] = 'The sender of this message has asked to be notified when you read this message. Do you wish to notify the sender?'; +$labels['receiptread'] = 'Return Receipt (read)'; +$labels['yourmessage'] = 'This is a Return Receipt for your message'; +$labels['receiptnote'] = 'Note: This receipt only acknowledges that the message was displayed on the recipient\'s computer. There is no guarantee that the recipient has read or understood the message contents.'; + +// address boook +$labels['name'] = 'Display Name'; +$labels['firstname'] = 'First Name'; +$labels['surname'] = 'Last Name'; +$labels['middlename'] = 'Middle Name'; +$labels['nameprefix'] = 'Prefix'; +$labels['namesuffix'] = 'Suffix'; +$labels['nickname'] = 'Nickname'; +$labels['jobtitle'] = 'Job Title'; +$labels['department'] = 'Department'; +$labels['gender'] = 'Gender'; +$labels['maidenname'] = 'Maiden Name'; +$labels['email'] = 'Email'; +$labels['phone'] = 'Phone'; +$labels['address'] = 'Address'; +$labels['street'] = 'Street'; +$labels['locality'] = 'City'; +$labels['zipcode'] = 'ZIP Code'; +$labels['region'] = 'State/Province'; +$labels['country'] = 'Country'; +$labels['birthday'] = 'Birthday'; +$labels['anniversary'] = 'Anniversary'; +$labels['website'] = 'Website'; +$labels['instantmessenger'] = 'IM'; +$labels['notes'] = 'Notes'; +$labels['male'] = 'male'; +$labels['female'] = 'female'; +$labels['manager'] = 'Manager'; +$labels['assistant'] = 'Assistant'; +$labels['spouse'] = 'Spouse'; +$labels['allfields'] = 'All fields'; +$labels['search'] = 'Search'; +$labels['advsearch'] = 'Advanced Search'; +$labels['advanced'] = 'Advanced'; +$labels['other'] = 'Other'; + +$labels['typehome'] = 'Home'; +$labels['typework'] = 'Work'; +$labels['typeother'] = 'Other'; +$labels['typemobile'] = 'Mobile'; +$labels['typemain'] = 'Main'; +$labels['typehomefax'] = 'Home Fax'; +$labels['typeworkfax'] = 'Work Fax'; +$labels['typecar'] = 'Car'; +$labels['typepager'] = 'Pager'; +$labels['typevideo'] = 'Video'; +$labels['typeassistant'] = 'Assistant'; +$labels['typehomepage'] = 'Home Page'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profile'; + +$labels['addfield'] = 'Add field...'; +$labels['addcontact'] = 'Add new contact'; +$labels['editcontact'] = 'Edit contact'; +$labels['contacts'] = 'Contacts'; +$labels['contactproperties'] = 'Contact properties'; +$labels['personalinfo'] = 'Personal information'; + +$labels['edit'] = 'Edit'; +$labels['cancel'] = 'Cancel'; +$labels['save'] = 'Save'; +$labels['delete'] = 'Delete'; +$labels['rename'] = 'Rename'; +$labels['addphoto'] = 'Add'; +$labels['replacephoto'] = 'Replace'; +$labels['uploadphoto'] = 'Upload photo'; + +$labels['newcontact'] = 'Create new contact card'; +$labels['deletecontact'] = 'Delete selected contacts'; +$labels['composeto'] = 'Compose mail to'; +$labels['contactsfromto'] = 'Contacts $from to $to of $count'; +$labels['print'] = 'Print'; +$labels['export'] = 'Export'; +$labels['exportvcards'] = 'Export contacts in vCard format'; +$labels['newcontactgroup'] = 'Create new contact group'; +$labels['grouprename'] = 'Rename group'; +$labels['groupdelete'] = 'Delete group'; +$labels['groupremoveselected'] = 'Remove selected contacts from group'; + +$labels['previouspage'] = 'Show previous page'; +$labels['firstpage'] = 'Show first page'; +$labels['nextpage'] = 'Show next page'; +$labels['lastpage'] = 'Show last page'; + +$labels['group'] = 'Group'; +$labels['groups'] = 'Groups'; +$labels['personaladrbook'] = 'Personal Addresses'; + +$labels['searchsave'] = 'Save search'; +$labels['searchdelete'] = 'Delete search'; + +$labels['import'] = 'Import'; +$labels['importcontacts'] = 'Import contacts'; +$labels['importfromfile'] = 'Import from file:'; +$labels['importtarget'] = 'Add new contacts to address book:'; +$labels['importreplace'] = 'Replace the entire address book'; +$labels['importdesc'] = 'You can upload contacts from an existing address book.<br/>We currently support importing addresses from the <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> or CSV (comma-separated) data format.'; +$labels['done'] = 'Done'; + +// settings +$labels['settingsfor'] = 'Settings for'; +$labels['about'] = 'About'; +$labels['preferences'] = 'Preferences'; +$labels['userpreferences'] = 'User preferences'; +$labels['editpreferences'] = 'Edit user preferences'; + +$labels['identities'] = 'Identities'; +$labels['manageidentities'] = 'Manage identities for this account'; +$labels['newidentity'] = 'New identity'; + +$labels['newitem'] = 'New item'; +$labels['edititem'] = 'Edit item'; + +$labels['preferhtml'] = 'Display HTML'; +$labels['defaultcharset'] = 'Default Character Set'; +$labels['htmlmessage'] = 'HTML Message'; +<<<<<<< HEAD +$labels['messagepart'] = 'Part'; +$labels['digitalsig'] = 'Digital Signature'; +======= +>>>>>>> parent of be72fb3... Unified attachments filenames handling for message parts without a filename +$labels['dateformat'] = 'Date format'; +$labels['timeformat'] = 'Time format'; +$labels['prettydate'] = 'Pretty dates'; +$labels['setdefault'] = 'Set default'; +$labels['autodetect'] = 'Auto'; +$labels['language'] = 'Language'; +$labels['timezone'] = 'Time zone'; +$labels['pagesize'] = 'Rows per page'; +$labels['signature'] = 'Signature'; +$labels['dstactive'] = 'Daylight saving time'; +$labels['showinextwin'] = 'Open message in a new window'; +$labels['composeextwin'] = 'Compose in a new window'; +$labels['htmleditor'] = 'Compose HTML messages'; +$labels['htmlonreply'] = 'on reply to HTML message'; +$labels['htmlonreplyandforward'] = 'on forward or reply to HTML message'; +$labels['htmlsignature'] = 'HTML signature'; +$labels['previewpane'] = 'Show preview pane'; +$labels['skin'] = 'Interface skin'; +$labels['logoutclear'] = 'Clear Trash on logout'; +$labels['logoutcompact'] = 'Compact Inbox on logout'; +$labels['uisettings'] = 'User Interface'; +$labels['serversettings'] = 'Server Settings'; +$labels['mailboxview'] = 'Mailbox View'; +$labels['mdnrequests'] = 'On request for return receipt'; +$labels['askuser'] = 'ask me'; +$labels['autosend'] = 'send receipt'; +$labels['autosendknown'] = 'send receipt to my contacts, otherwise ask me'; +$labels['autosendknownignore'] = 'send receipt to my contacts, otherwise ignore'; +$labels['ignore'] = 'ignore'; +$labels['readwhendeleted'] = 'Mark the message as read on delete'; +$labels['flagfordeletion'] = 'Flag the message for deletion instead of delete'; +$labels['skipdeleted'] = 'Do not show deleted messages'; +$labels['deletealways'] = 'If moving messages to Trash fails, delete them'; +$labels['deletejunk'] = 'Directly delete messages in Junk'; +$labels['showremoteimages'] = 'Display remote inline images'; +$labels['fromknownsenders'] = 'from known senders'; +$labels['always'] = 'always'; +$labels['showinlineimages'] = 'Display attached images below the message'; +$labels['autosavedraft'] = 'Automatically save draft'; +$labels['everynminutes'] = 'every $n minute(s)'; +$labels['refreshinterval'] = 'Refresh (check for new messages, etc.)'; +$labels['never'] = 'never'; +$labels['immediately'] = 'immediately'; +$labels['messagesdisplaying'] = 'Displaying Messages'; +$labels['messagescomposition'] = 'Composing Messages'; +$labels['mimeparamfolding'] = 'Attachment names'; +$labels['2231folding'] = 'Full RFC 2231 (Thunderbird)'; +$labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; +$labels['2047folding'] = 'Full RFC 2047 (other)'; +$labels['force7bit'] = 'Use MIME encoding for 8-bit characters'; +$labels['advancedoptions'] = 'Advanced options'; +$labels['focusonnewmessage'] = 'Focus browser window on new message'; +$labels['checkallfolders'] = 'Check all folders for new messages'; +$labels['displaynext'] = 'After message delete/move display the next message'; +$labels['defaultfont'] = 'Default font of HTML message'; +$labels['mainoptions'] = 'Main Options'; +$labels['browseroptions'] = 'Browser Options'; +$labels['section'] = 'Section'; +$labels['maintenance'] = 'Maintenance'; +$labels['newmessage'] = 'New Message'; +$labels['signatureoptions'] = 'Signature Options'; +$labels['whenreplying'] = 'When replying'; +$labels['replyempty'] = 'do not quote the original message'; +$labels['replytopposting'] = 'start new message above the quote'; +$labels['replybottomposting'] = 'start new message below the quote'; +$labels['replyremovesignature'] = 'When replying remove original signature from message'; +$labels['autoaddsignature'] = 'Automatically add signature'; +$labels['newmessageonly'] = 'new message only'; +$labels['replyandforwardonly'] = 'replies and forwards only'; +$labels['replysignaturepos'] = 'When replying or forwarding place signature'; +$labels['belowquote'] = 'below the quote'; +$labels['abovequote'] = 'above the quote'; +$labels['insertsignature'] = 'Insert signature'; +$labels['previewpanemarkread'] = 'Mark previewed messages as read'; +$labels['afternseconds'] = 'after $n seconds'; +$labels['reqmdn'] = 'Always request a return receipt'; +$labels['reqdsn'] = 'Always request a delivery status notification'; +$labels['replysamefolder'] = 'Place replies in the folder of the message being replied to'; +$labels['defaultabook'] = 'Default address book'; +$labels['autocompletesingle'] = 'Skip alternative email addresses in autocompletion'; +$labels['listnamedisplay'] = 'List contacts as'; +$labels['spellcheckbeforesend'] = 'Check spelling before sending a message'; +$labels['spellcheckoptions'] = 'Spellcheck Options'; +$labels['spellcheckignoresyms'] = 'Ignore words with symbols'; +$labels['spellcheckignorenums'] = 'Ignore words with numbers'; +$labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; +$labels['addtodict'] = 'Add to dictionary'; +$labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; +$labels['forwardmode'] = 'Messages forwarding'; +$labels['inline'] = 'inline'; +$labels['asattachment'] = 'as attachment'; + +$labels['folder'] = 'Folder'; +$labels['folders'] = 'Folders'; +$labels['foldername'] = 'Folder name'; +$labels['subscribed'] = 'Subscribed'; +$labels['messagecount'] = 'Messages'; +$labels['create'] = 'Create'; +$labels['createfolder'] = 'Create new folder'; +$labels['managefolders'] = 'Manage folders'; +$labels['specialfolders'] = 'Special Folders'; +$labels['properties'] = 'Properties'; +$labels['folderproperties'] = 'Folder properties'; +$labels['parentfolder'] = 'Parent folder'; +$labels['location'] = 'Location'; +$labels['info'] = 'Information'; +$labels['getfoldersize'] = 'Click to get folder size'; +$labels['changesubscription'] = 'Click to change subscription'; +$labels['foldertype'] = 'Folder Type'; +$labels['personalfolder'] = 'Private Folder'; +$labels['otherfolder'] = 'Other User\'s Folder'; +$labels['sharedfolder'] = 'Public Folder'; + +$labels['sortby'] = 'Sort by'; +$labels['sortasc'] = 'Sort ascending'; +$labels['sortdesc'] = 'Sort descending'; +$labels['undo'] = 'Undo'; + +$labels['installedplugins'] = 'Installed plugins'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Version'; +$labels['source'] = 'Source'; +$labels['license'] = 'License'; +$labels['support'] = 'Get support'; + +// units +$labels['B'] = 'B'; +$labels['KB'] = 'KB'; +$labels['MB'] = 'MB'; +$labels['GB'] = 'GB'; + +// character sets +$labels['unicode'] = 'Unicode'; +$labels['english'] = 'English'; +$labels['westerneuropean'] = 'Western European'; +$labels['easterneuropean'] = 'Eastern European'; +$labels['southeasterneuropean'] = 'South-Eastern European'; +$labels['baltic'] = 'Baltic'; +$labels['cyrillic'] = 'Cyrillic'; +$labels['arabic'] = 'Arabic'; +$labels['greek'] = 'Greek'; +$labels['hebrew'] = 'Hebrew'; +$labels['turkish'] = 'Turkish'; +$labels['nordic'] = 'Nordic'; +$labels['thai'] = 'Thai'; +$labels['celtic'] = 'Celtic'; +$labels['vietnamese'] = 'Vietnamese'; +$labels['japanese'] = 'Japanese'; +$labels['korean'] = 'Korean'; +$labels['chinese'] = 'Chinese'; + +?> diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index 47b0f797d..a5e3b4ae2 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -5,7 +5,7 @@ | localization/<lang>/messages.inc | | | | Localization file of the Roundcube Webmail client | - | Copyright (C) 2005-2013, 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. | @@ -28,8 +28,6 @@ $messages['dberror'] = 'Database Error!'; $messages['requesttimedout'] = 'Request timed out'; $messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only.'; $messages['errornoperm'] = 'Unable to perform operation. Permission denied.'; -$messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; -$messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; $messages['invalidrequest'] = 'Invalid request! No data was saved.'; $messages['invalidhost'] = 'Invalid server name.'; $messages['nomessagesfound'] = 'No messages found in this mailbox.'; @@ -56,8 +54,8 @@ $messages['contactnotfound'] = 'The requested contact was not found.'; $messages['contactsearchonly'] = 'Enter some search terms to find contacts'; $messages['sendingfailed'] = 'Failed to send message.'; $messages['senttooquickly'] = 'Please wait $sec sec(s). before sending this message.'; -$messages['errorsavingsent'] = 'An error occured while saving sent message.'; -$messages['errorsaving'] = 'An error occured while saving.'; +$messages['errorsavingsent'] = 'An error occurred while saving sent message.'; +$messages['errorsaving'] = 'An error occurred while saving.'; $messages['errormoving'] = 'Could not move the message(s).'; $messages['errorcopying'] = 'Could not copy the message(s).'; $messages['errordeleting'] = 'Could not delete the message(s).'; @@ -101,16 +99,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +124,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; @@ -144,7 +137,7 @@ $messages['smtperror'] = 'SMTP Error: $msg'; $messages['emailformaterror'] = 'Invalid e-mail address: $email'; $messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.'; $messages['maxgroupmembersreached'] = 'The number of group members exceeds the maximum of $max.'; -$messages['internalerror'] = 'An internal error occured. Please try again.'; +$messages['internalerror'] = 'An internal error occurred. Please try again.'; $messages['contactdelerror'] = 'Could not delete contact(s).'; $messages['contactdeleted'] = 'Contact(s) deleted successfully.'; $messages['contactrestoreerror'] = 'Could not restore deleted contact(s).'; diff --git a/program/localization/eo/labels.inc b/program/localization/eo/labels.inc index 3c2930c89..c088fc50e 100644 --- a/program/localization/eo/labels.inc +++ b/program/localization/eo/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Malnetujo'; $labels['sent'] = 'Senditujo'; $labels['trash'] = 'Rubujo'; $labels['junk'] = 'Spamujo'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Temo'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Dosierujo-agoj'; $labels['compact'] = 'Kompakta'; $labels['empty'] = 'Malplena'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Diskuzo'; $labels['unknown'] = 'nekonata'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Vakigu serĉon'; $labels['searchmod'] = 'Serĉ-opcioj'; $labels['msgtext'] = 'Tuta mesaÄo'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Malfermu en nova fenestro'; $labels['emlsave'] = 'ElÅutu (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Montru lastan'; $labels['group'] = 'Group'; $labels['groups'] = 'Grupoj'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Persona Adresoj'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/eo/messages.inc b/program/localization/eo/messages.inc index a7765e442..4d72fe54b 100644 --- a/program/localization/eo/messages.inc +++ b/program/localization/eo/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Foriganta formatan de mesaÄo...'; $messages['messageopenerror'] = 'Ne povis Åargi mesaÄon de servilo'; $messages['fileuploaderror'] = 'Malsukcesis alÅuti dosieron'; $messages['filesizeerror'] = 'La alÅutita dosiero superas la maksimuman grandon de $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Sukcese kopiis $nr adresojn'; +$messages['copyerror'] = 'Ne povis kopii ajn adreson'; $messages['sourceisreadonly'] = 'Ĉi tiu adres-fonto estas nurlegebla'; $messages['errorsavingcontact'] = 'Ne povis savi la kontakt-adreson'; $messages['movingmessage'] = 'Translokanta mesaÄon...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/es_AR/labels.inc b/program/localization/es_AR/labels.inc index 5bc53f7f0..d9a83be75 100644 --- a/program/localization/es_AR/labels.inc +++ b/program/localization/es_AR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Borradores'; $labels['sent'] = 'Enviados'; $labels['trash'] = 'Papelera'; $labels['junk'] = 'Basura'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Asunto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Acciones de carpeta...'; $labels['compact'] = 'Compactar'; $labels['empty'] = 'Vaciar'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Uso de disco'; $labels['unknown'] = 'desconocido'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reajustar la búsqueda'; $labels['searchmod'] = 'Opciones de búsqueda'; $labels['msgtext'] = 'Mensaje completo'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Abrir en ventana nueva'; $labels['emlsave'] = 'Guardar (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Mostrar último grupo'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Direcciones personales'; $labels['searchsave'] = 'Guardar búsqueda'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/es_AR/messages.inc b/program/localization/es_AR/messages.inc index 1a0240222..1cec9f01d 100644 --- a/program/localization/es_AR/messages.inc +++ b/program/localization/es_AR/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removiendo el formato del mensaje...'; $messages['messageopenerror'] = 'No puedo descargar el mensaje del servidor'; $messages['fileuploaderror'] = 'Error al subir archivos'; $messages['filesizeerror'] = 'El archivo excede el tamaño maximo ($size)'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr direcciones copiadas con éxito'; +$messages['copyerror'] = 'No se pudo copiar ninguna dirección'; $messages['sourceisreadonly'] = 'Esta dirección es de sólo-lectura'; $messages['errorsavingcontact'] = 'No se pudo guardar la dirección de contacto'; $messages['movingmessage'] = 'Moviendo mensaje...'; $messages['copyingmessage'] = 'Copiando mensaje...'; $messages['copyingcontact'] = 'Copiando contacto(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Eliminando contacto(s)...'; $messages['markingmessage'] = 'Marcando mensaje(s)...'; $messages['addingmember'] = 'Agregando contacto(s) al grupo...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importando, aguarde por favor...'; $messages['importformaterror'] = 'Importación fallida! El archivo subido no es un archivo de importación de datos válido.'; $messages['importconfirm'] = '<b>Se importaron $inserted contactos correctamente. $skipped ya existentes fueron ignorados</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Se ignoraron $skipped entradas ya existentes</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operación no permitida!'; $messages['nofromaddress'] = 'El contacto seleccionado no tiene dirección de e-mail'; $messages['editorwarning'] = 'Si cambia a texto plano se perderán todas las opciones de formato. ¿Desea continuar?'; diff --git a/program/localization/es_ES/labels.inc b/program/localization/es_ES/labels.inc index 11d14fa08..03f6b489a 100644 --- a/program/localization/es_ES/labels.inc +++ b/program/localization/es_ES/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Borradores'; $labels['sent'] = 'Enviados'; $labels['trash'] = 'Papelera'; $labels['junk'] = 'SPAM'; -$labels['show_real_foldernames'] = 'Mostrar nombres reales para carpetas especiales'; // message listing $labels['subject'] = 'Asunto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Modo de vista de lista'; $labels['folderactions'] = 'Acciones de bandeja...'; $labels['compact'] = 'Compactar'; $labels['empty'] = 'Vaciar'; -$labels['importmessages'] = 'Importar mensajes'; $labels['quota'] = 'Uso de disco'; $labels['unknown'] = 'desconocido'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reiniciar la búsqueda'; $labels['searchmod'] = 'Opciones de búsqueda'; $labels['msgtext'] = 'Mensaje completo'; $labels['body'] = 'Cuerpo'; -$labels['type'] = 'Tipo'; $labels['openinextwin'] = 'Abrir en nueva ventana'; $labels['emlsave'] = 'Descargar (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Mostrar último grupo'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'Listar miembros del grupo'; $labels['personaladrbook'] = 'Direcciones personales'; $labels['searchsave'] = 'Guardar búsqueda'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Componer mensaje en HTML'; $labels['htmlonreply'] = 'sólo en respuesta a un mensaje HTML'; $labels['htmlonreplyandforward'] = 'en reenvÃo o respuesta al mensaje HTML'; $labels['htmlsignature'] = 'Firma HTML'; -$labels['showemail'] = 'Mostrar dirección de correo electrónico al visualizar el nombre'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Mostrar vista preliminar'; $labels['skin'] = 'Apariencia de la interfaz'; $labels['logoutclear'] = 'Vaciar papelera al cerrar sesión'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorar palabras con números'; $labels['spellcheckignorecaps'] = 'Ignorar palabras con todo mayúsculas'; $labels['addtodict'] = 'Añadir al diccionario'; $labels['mailtoprotohandler'] = 'Registrar controlador de protocolo para enlaces mailto:'; -$labels['standardwindows'] = 'Gestionar ventanas emergentes como ventanas estándar'; $labels['forwardmode'] = 'ReenvÃo de mensajes'; $labels['inline'] = 'en lÃnea'; $labels['asattachment'] = 'como adjunto'; diff --git a/program/localization/es_ES/messages.inc b/program/localization/es_ES/messages.inc index d4bd81402..6c031df29 100644 --- a/program/localization/es_ES/messages.inc +++ b/program/localization/es_ES/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Importando, espere...'; $messages['importformaterror'] = '¡La importación falló! El fichero enviado no es un fichero válido de importación de datos'; $messages['importconfirm'] = '<b>Se han importado $inserted contactos correctamente</b>'; $messages['importconfirmskipped'] = '<b>Ignoradas $skipped entradas existentes</b>'; -$messages['importmessagesuccess'] = '$nr mensajes importados con éxito'; -$messages['importmessageerror'] = '¡Ha fallado la importación! El fichero subido no es un fichero válido de mensaje o buzón de correo'; $messages['opnotpermitted'] = '¡Operación no permitida!'; $messages['nofromaddress'] = 'El contacto seleccionado no tiene dirección de e-mail'; $messages['editorwarning'] = 'Cambiando a texto plano perderá el formato del mensaje. ¿Desea continuar?'; diff --git a/program/localization/et_EE/labels.inc b/program/localization/et_EE/labels.inc index a8bc28403..5d23d4ded 100644 --- a/program/localization/et_EE/labels.inc +++ b/program/localization/et_EE/labels.inc @@ -37,7 +37,7 @@ $labels['drafts'] = 'Mustandid'; $labels['sent'] = 'Saadetud'; $labels['trash'] = 'Prügikast'; $labels['junk'] = 'Rämps'; -$labels['show_real_foldernames'] = 'Näita eriliste kaustade päris nimesid'; +$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Pealkiri'; @@ -194,7 +194,6 @@ $labels['listmode'] = 'Nimekirja vaatamise režiim'; $labels['folderactions'] = 'Kausta tegevused...'; $labels['compact'] = 'Tihenda'; $labels['empty'] = 'Tühjenda'; -$labels['importmessages'] = 'Impordi kirju'; $labels['quota'] = 'Kettakasutus'; $labels['unknown'] = 'teadmata'; @@ -205,7 +204,6 @@ $labels['resetsearch'] = 'Lähtesta otsing'; $labels['searchmod'] = 'Otsingu laiendid'; $labels['msgtext'] = 'Kogu kirjast'; $labels['body'] = 'Keha'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Ava uues aknas'; $labels['emlsave'] = 'Salvesta (.eml)'; @@ -357,7 +355,6 @@ $labels['lastpage'] = 'Näita viimast komplekti'; $labels['group'] = 'Grupp'; $labels['groups'] = 'Grupid'; -$labels['listgroup'] = 'Näita grupi liikmeid'; $labels['personaladrbook'] = 'Isiklikud aadressid'; $labels['searchsave'] = 'Salvesta otsing'; diff --git a/program/localization/et_EE/messages.inc b/program/localization/et_EE/messages.inc index 4d58b0a75..c73d92c48 100644 --- a/program/localization/et_EE/messages.inc +++ b/program/localization/et_EE/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Impordin, palun oota...'; $messages['importformaterror'] = 'Import nurjus! Laaditud fail ei sisalda sobilikke andmeid.'; $messages['importconfirm'] = '<b>Edukalt imporditud $inserted kontakti, $skipped olemasolevat sissekannet vahele jäetud</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b> $skipped olemasolevat kirjet jäeti vahele</b>'; -$messages['importmessagesuccess'] = '$nr kirja edukalt imporditud'; -$messages['importmessageerror'] = 'Import nurjus! Laaditud fail ei ole kirja ega postkasti fail'; $messages['opnotpermitted'] = 'Tegevus pole lubatud!'; $messages['nofromaddress'] = 'Valitud identiteedil puudub e-posti aadress'; $messages['editorwarning'] = 'Klaarteksti redaktorile lülitamine kaotab kogu teksti vorminduse. Soovid jätkata?'; diff --git a/program/localization/eu_ES/labels.inc b/program/localization/eu_ES/labels.inc index fedce7de5..8052d69e8 100644 --- a/program/localization/eu_ES/labels.inc +++ b/program/localization/eu_ES/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Zirriborroak'; $labels['sent'] = 'Bidalitakoak'; $labels['trash'] = 'Zakarrontzia'; $labels['junk'] = 'Zabor-posta'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Gaia'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Trinkotu'; $labels['empty'] = 'Hustu'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disko erabilera'; $labels['unknown'] = 'ezezaguna'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Bilaketa berrabiarazi'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Lehio berrian ireki'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Azken sorta ikusi'; $labels['group'] = 'Group'; $labels['groups'] = 'Taldeak'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Helbide pertsonalak'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/eu_ES/messages.inc b/program/localization/eu_ES/messages.inc index 6dd781530..a3985b233 100644 --- a/program/localization/eu_ES/messages.inc +++ b/program/localization/eu_ES/messages.inc @@ -17,28 +17,28 @@ */ $messages = array(); -$messages['errortitle'] = 'Errore bat gertatu da!'; -$messages['loginfailed'] = 'Saio hasierak huts egin du.'; -$messages['cookiesdisabled'] = 'Zure nabigatzaileak ez ditu cookie-rik onartzen'; +$messages['errortitle'] = 'An error occurred!'; +$messages['loginfailed'] = 'Saio sarrerak huts egin du'; +$messages['cookiesdisabled'] = 'Zure nabigatzaileak ez ditu cookie-ak onartzen'; $messages['sessionerror'] = 'Zure saioa baliogabea da edo iraungita dago'; -$messages['storageerror'] = 'Huts egin du biltegiratze-zerbitzarira konektatzean'; -$messages['servererror'] = 'Zerbitzari-errorea!'; -$messages['servererrormsg'] = 'Zerbitzari-errorea: $msg'; -$messages['dberror'] = 'Datu-basearen errorea!'; -$messages['requesttimedout'] = 'Eskaera denboraz kanpo.'; -$messages['errorreadonly'] = 'Ezin da ekintza burutu. Karpeta soilik irakurtzekoa da.'; -$messages['errornoperm'] = 'Ezin da ekintza burutu. Baimena ukatua.'; -$messages['erroroverquota'] = 'Ezin da ekintza burutu. Diskoan ez dago tokirik.'; -$messages['erroroverquotadelete'] = 'Diskoan ez dago tokirik. Erabili SHIFT+DEL mezua ezabatzeko.'; -$messages['invalidrequest'] = 'Eskaera ez da baliozkoa! Datuak ez dira gorde.'; -$messages['invalidhost'] = 'Zerbitzari-izena ez da baliozkoa.'; +$messages['storageerror'] = 'Huts IMAP zerbitzarira konektatzean'; +$messages['servererror'] = 'Server Error!'; +$messages['servererrormsg'] = 'Server Error: $msg'; +$messages['dberror'] = 'Database Error!'; +$messages['requesttimedout'] = 'Request timed out'; +$messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only.'; +$messages['errornoperm'] = 'Unable to perform operation. Permission denied.'; +$messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; +$messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; +$messages['invalidrequest'] = 'Invalid request! No data was saved.'; +$messages['invalidhost'] = 'Invalid server name.'; $messages['nomessagesfound'] = 'Ez da mezurik aurkitu posta kutxa honetan'; $messages['loggedout'] = 'Saioa behar bezala amaitu duzu. Agur!'; $messages['mailboxempty'] = 'Posta kutxa hutsik dago'; -$messages['refreshing'] = 'Freskatzen...'; +$messages['refreshing'] = 'Refreshing...'; $messages['loading'] = 'Kargatzen...'; -$messages['uploading'] = 'Fitxategia kargatzen...'; -$messages['uploadingmany'] = 'Fitxategiak kargatzen...'; +$messages['uploading'] = 'Uploading file...'; +$messages['uploadingmany'] = 'Uploading files...'; $messages['loadingdata'] = 'Datuak kargatzen...'; $messages['checkingmail'] = 'Mezu berrien bila arakatzen...'; $messages['sendingmessage'] = 'Mezua bidaltzen...'; @@ -48,129 +48,124 @@ $messages['messagesaved'] = 'Mezua zirriborroetan gordea'; $messages['successfullysaved'] = 'Behar bezala gorde da'; $messages['addedsuccessfully'] = 'Txartela behar bezala gehitu da helbide liburura'; $messages['contactexists'] = 'ePosta honetako txartel bat badago dagoeneko'; -$messages['contactnameexists'] = 'Lehendik badago izen hori duen kontaktua.'; +$messages['contactnameexists'] = 'A contact with the same name already exists.'; $messages['blockedimages'] = 'Zure pribazitatea mantentzeko urruneko irudiak blokeatu egin dira.'; $messages['encryptedmessage'] = 'Hau enkriptaturiko mezu bat da eta ezin da bistarazi. Barkatu!'; $messages['nocontactsfound'] = 'Ez da txartelik aurkitu'; $messages['contactnotfound'] = 'Eskatutako txartela ez da aurkitu'; -$messages['contactsearchonly'] = 'Sartu kontaktua aurkitzeko bilaketa daturen bat.'; +$messages['contactsearchonly'] = 'Enter some search terms to find contacts'; $messages['sendingfailed'] = 'Huts mezua bidaltzerakoan'; -$messages['senttooquickly'] = 'Itxaron $sec segundo mezua bidali aurretik, mesedez.'; +$messages['senttooquickly'] = 'Please wait $sec sec(s). before sending this message.'; $messages['errorsavingsent'] = 'Errorea gertatu da bidalitako mezua gordetzean'; $messages['errorsaving'] = 'Errore bat gertatu da gordetzean'; $messages['errormoving'] = 'Ezin da mezua mugitu'; -$messages['errorcopying'] = 'Ezin d(ir)a kopiatu mezua(k).'; +$messages['errorcopying'] = 'Could not copy the message(s).'; $messages['errordeleting'] = 'Ezin da mezua ezabatu'; -$messages['errormarking'] = 'Ezin d(ir)a markatu mezua(k).'; +$messages['errormarking'] = 'Could not mark the message(s).'; $messages['deletecontactconfirm'] = 'Benetan hautaturiko kontaktuak ezabatu nahi dituzula?'; -$messages['deletegroupconfirm'] = 'Seguru zaude hautatutako taldea ezabatu nahi duzula?'; +$messages['deletegroupconfirm'] = 'Do you really want to delete selected group?'; $messages['deletemessagesconfirm'] = 'Benetan hautaturiko mezuak ezabatu nahi dituzula?'; $messages['deletefolderconfirm'] = 'Benetan Karpeta hau ezabatu nahi duzu?'; $messages['purgefolderconfirm'] = 'Benetan karpeta honetako mezu guziak ezabatu nahi dituzu?'; -$messages['contactdeleting'] = 'Kontaktua(k) ezabatzen...'; -$messages['groupdeleting'] = 'Taldea ezabatzen...'; -$messages['folderdeleting'] = 'Karpeta ezabatzen...'; -$messages['foldermoving'] = 'Karpeta mugitzen...'; -$messages['foldersubscribing'] = 'Karpeta harpidetzen...'; -$messages['folderunsubscribing'] = 'Karpetaren harpidetza kentzen...'; +$messages['contactdeleting'] = 'Deleting contact(s)...'; +$messages['groupdeleting'] = 'Deleting group...'; +$messages['folderdeleting'] = 'Deleting folder...'; +$messages['foldermoving'] = 'Moving folder...'; +$messages['foldersubscribing'] = 'Subscribing folder...'; +$messages['folderunsubscribing'] = 'Unsubscribing folder...'; $messages['formincomplete'] = 'Inprimakia ez guztiz bete'; $messages['noemailwarning'] = 'Mesedez idatzi baliozko eposta helbide bat'; $messages['nonamewarning'] = 'Mesedez izen bat idatzi'; $messages['nopagesizewarning'] = 'Mesedez paper tamaina idatzi'; -$messages['nosenderwarning'] = 'Sartu bidaltzailearen helbide elektronikoa, mesedez.'; +$messages['nosenderwarning'] = 'Please enter sender e-mail address.'; $messages['norecipientwarning'] = 'Mesedez behintzat hartzaile bat idatzi'; $messages['nosubjectwarning'] = '"Gaia" eremua hutsik dago. Bat idatzi nahi al duzu?'; $messages['nobodywarning'] = 'Testu gabeko mezu hau bidali?'; $messages['notsentwarning'] = 'Mezua ez da bidali. Mezua ezeztatu nahi al duzu?'; $messages['noldapserver'] = 'Mesedez hautatu bilaketa egiteko LDAP zerbitzari bat'; $messages['nosearchname'] = 'Mesedez idatzi kontaktu izen bat edo eposta helbide bat'; -$messages['notuploadedwarning'] = 'Oraindik ez dira kargatu eranskin guztiak. Itxaron edo ezeztatu karga.'; +$messages['notuploadedwarning'] = 'Not all attachments have been uploaded yet. Please wait or cancel the upload.'; $messages['searchsuccessful'] = '$nr mezu aurkiturik'; -$messages['contactsearchsuccessful'] = '$nr kontaktu aurkitu dira.'; +$messages['contactsearchsuccessful'] = '$nr contacts found.'; $messages['searchnomatch'] = 'Bilaketak ez du emaitzarik itzuli'; $messages['searching'] = 'Bilatzen...'; $messages['checking'] = 'Arakatzen...'; $messages['nospellerrors'] = 'Ez da ortografia errorerik aurkitu'; $messages['folderdeleted'] = 'Karpeta behar bezala ezabatu da'; -$messages['foldersubscribed'] = 'Karpeta ongi harpidetu da.'; -$messages['folderunsubscribed'] = 'Karpetaren harpidetza ongi kendu da.'; -$messages['folderpurged'] = 'Karpeta ongi hustu da.'; -$messages['folderexpunged'] = 'Karpeta ongi trinkotu da.'; +$messages['foldersubscribed'] = 'Folder successfully subscribed.'; +$messages['folderunsubscribed'] = 'Folder successfully unsubscribed.'; +$messages['folderpurged'] = 'Folder has successfully been emptied.'; +$messages['folderexpunged'] = 'Folder has successfully been compacted.'; $messages['deletedsuccessfully'] = 'Behar bezala ezabatu da'; $messages['converting'] = 'Mezuaren formatua ezabatzen'; $messages['messageopenerror'] = 'Ezin da zerbitzaritik mezua kargatu'; $messages['fileuploaderror'] = 'Huts fitxategia eransterakoan'; $messages['filesizeerror'] = 'Erantsi nahi duzun fitxategian $size tamaina muga gainditzen du'; -$messages['copysuccess'] = '$nr kontaktu ongi kopiatu dira.'; -$messages['movesuccess'] = '$nr kontaktu ongi mugitu dira.'; -$messages['copyerror'] = 'Ezin da kontakturik kopiatu.'; -$messages['moveerror'] = 'Ezin da kontakturik mugitu.'; +$messages['copysuccess'] = 'Ondo kopiatu dira $nr helbideak'; +$messages['copyerror'] = 'Ezin da helbiderik kopiatu'; $messages['sourceisreadonly'] = 'Helbide iturburua irakurtzeko soilik da'; $messages['errorsavingcontact'] = 'Ezin da kontaktuaren helbidea gorde'; $messages['movingmessage'] = 'Mezua mugitzen...'; -$messages['copyingmessage'] = 'Mezuak kopiatzen...'; -$messages['copyingcontact'] = 'Kontaktua(k) kopiatzen...'; -$messages['movingcontact'] = 'Kontaktua(k) mugitzen...'; -$messages['deletingmessage'] = 'Mezua(k) ezabatzen...'; -$messages['markingmessage'] = 'Mezua(k) markatzen...'; -$messages['addingmember'] = 'Kontaktua(k) taldera gehitzen...'; -$messages['removingmember'] = 'Kontaktua(k) taldetik ezabatzen...'; +$messages['copyingmessage'] = 'Copying message(s)...'; +$messages['copyingcontact'] = 'Copying contact(s)...'; +$messages['deletingmessage'] = 'Deleting message(s)...'; +$messages['markingmessage'] = 'Marking message(s)...'; +$messages['addingmember'] = 'Adding contact(s) to the group...'; +$messages['removingmember'] = 'Removing contact(s) from the group...'; $messages['receiptsent'] = 'Ondo bidalia irakurritako agiria'; $messages['errorsendingreceipt'] = 'Ezin da agiria bidali'; -$messages['deleteidentityconfirm'] = 'Seguru zaude identitate hau ezabatu nahi duzula?'; +$messages['deleteidentityconfirm'] = 'Do you really want to delete this identity?'; $messages['nodeletelastidentity'] = 'Ezin da izaera hau ezabatu, zure bakarra da'; $messages['forbiddencharacter'] = 'Karpeta izenak debekatutako karaktereak ditu'; -$messages['selectimportfile'] = 'Hautatu kargatzeko fitxategia.'; -$messages['addresswriterror'] = 'Hautatutako helbide-liburua ezin da editatu.'; -$messages['contactaddedtogroup'] = 'Kontaktuak ongi gehitu dira taldera.'; -$messages['contactremovedfromgroup'] = 'Kontaktuak ongi ezabatu dira taldetik.'; -$messages['nogroupassignmentschanged'] = 'Talde-esleipena ez da aldatu.'; -$messages['importwait'] = 'Inportatzen, itxaron mesedez...'; -$messages['importformaterror'] = 'Huts egin du inportatzean. Kargatu duzun fitxategia ez da inportatzeko fitxategi baliozkoa.'; -$messages['importconfirm'] = '<b>Ongi inportatu dira $inserted kontaktu</b>'; -$messages['importconfirmskipped'] = '<b>Saltatu dira $skipped sarrera</b>'; -$messages['importmessagesuccess'] = '$nr mezu ongi inportatu dira.'; -$messages['importmessageerror'] = 'Inportazio akatsa! Kargatutako fitxategia ez da baliozko mezua edo posta-fitxategia.'; -$messages['opnotpermitted'] = 'Ekintza ez baimendua!'; -$messages['nofromaddress'] = 'Helbide elektronikoa falta da hautatutako identitatean.'; -$messages['editorwarning'] = 'Formaturik gabeko testu-editorera pasatzeak ekar dezake testu-formatu guztien galera. Jarraitu nahi duzu?'; -$messages['httpreceivedencrypterror'] = 'Ezarpen akats larria gertatu da. Jarri harremanetan zure administratzailearekin ahalik eta lasterren. <b>Zure mezua ezin da bidali.</b>'; -$messages['smtpconnerror'] = 'SMTP errorea ($code): Zerbitzariarekiko konexioak huts egin du.'; -$messages['smtpautherror'] = 'SMTP errorea ($code): Egiaztapenak huts egin du.'; -$messages['smtpfromerror'] = 'SMTP errorea ($code): "$from" ($msg) bidaltzailearen ezartzeak huts egin du.'; -$messages['smtptoerror'] = 'SMTP errorea ($code): "$to" ($msg) hartzailea gehitzen huts egin du.'; -$messages['smtprecipientserror'] = 'SMTP errorea: Ezin da hartzaileen zerrenda analizatu.'; -$messages['smtperror'] = 'SMTP errorea: $msg'; -$messages['emailformaterror'] = 'Helbide elektronikoa ez da baliozkoa: $email'; -$messages['toomanyrecipients'] = 'Hartzaile gehiegi. Txikitu hartzaile kopura hona $max.'; -$messages['maxgroupmembersreached'] = 'Taldeko partaideen kopurua $max -ko maximoa gainditzen du:'; -$messages['internalerror'] = 'Barne akatsa. Saiatu berriz, mesedez.'; -$messages['contactdelerror'] = 'Ezin d(ir)a kontaktua(k) ezabatu.'; -$messages['contactdeleted'] = 'Kontaktua(k) ongi ezabatu dira.'; -$messages['contactrestoreerror'] = 'Ezin d(ir)a ezabatutako kontaktua(k) leheneratu.'; -$messages['contactrestored'] = 'Kontaktua(k) ongi leheneratu d(ir)a.'; -$messages['groupdeleted'] = 'Taldea ongi ezabatu da.'; -$messages['grouprenamed'] = 'Taldea ongi berrizendatu da.'; -$messages['groupcreated'] = 'Taldea ongi sortu da.'; -$messages['savedsearchdeleted'] = 'Bilaketaren gordetzea ongi ezabatu da.'; -$messages['savedsearchdeleteerror'] = 'Ezin da ezabatu bilaketaren gordeketa.'; -$messages['savedsearchcreated'] = 'Bilaketaren gordeketa ongi sortu da.'; -$messages['savedsearchcreateerror'] = 'Ezin da sortu bilaketaren gordeketa.'; -$messages['messagedeleted'] = 'Mezua(k) ongi ezabatu dira.'; -$messages['messagemoved'] = 'Mezua(k) ongi mugitu d(ir)a.'; -$messages['messagecopied'] = 'Mezua(k) ongi kopiatu d(ir)a'; -$messages['messagemarked'] = 'Mezua(k) ongi markatu d(ir)a'; -$messages['autocompletechars'] = 'Sartu gutxienez $min karaktere osatze automatikorako'; -$messages['autocompletemore'] = 'Bat datozen sarrera gehiago topatu dira. Idatzi karaktere gehiago.'; -$messages['namecannotbeempty'] = 'Izena ezin da hutsik egon.'; -$messages['nametoolong'] = 'Izena luzeegia da.'; -$messages['folderupdated'] = 'Karpeta ongi eguneratu da.'; -$messages['foldercreated'] = 'Karpeta ongi sortu da.'; -$messages['invalidimageformat'] = 'Irudi formatua ez da baliozkoa.'; -$messages['mispellingsfound'] = 'Ortografia akatsak detektatu dira mezuan.'; -$messages['parentnotwritable'] = 'Ezin da karpeta sortu/mugi hautatutako goragoko karpetan. Sartzeko baimenik ez.'; -$messages['messagetoobig'] = 'Mezu-zatia handiegia da prozesatzeko.'; -$messages['attachmentvalidationerror'] = 'KONTUZ! Eranskin hau susmagarria da zeren bere izaera ez dator bat mezuan deklaratutakoarekin. Bidaltzailearekin fidatzen ez bazara ez zenuke nabigatzailean ireki behar eduki maltzurra izan dezakeelako.<br/><br/><em>Deklaratua: $expected; erreala: $detected</em>'; -$messages['noscriptwarning'] = 'Kontuz: web-posta zerbitzu honek Javascript behar du! Erabili nahi baduzu gaitu Javascript zure nabigatzailearen hobespenetan.'; +$messages['selectimportfile'] = 'Please select a file to upload.'; +$messages['addresswriterror'] = 'The selected address book is not writeable.'; +$messages['contactaddedtogroup'] = 'Successfully added the contacts to this group.'; +$messages['contactremovedfromgroup'] = 'Successfully removed contacts from this group.'; +$messages['nogroupassignmentschanged'] = 'No group assignments changed.'; +$messages['importwait'] = 'Importing, please wait...'; +$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; +$messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; +$messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; +$messages['opnotpermitted'] = 'Operation not permitted!'; +$messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; +$messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; +$messages['httpreceivedencrypterror'] = 'A fatal configuration error occurred. Contact your administrator immediately. <b>Your message can not be sent.</b>'; +$messages['smtpconnerror'] = 'SMTP Error ($code): Connection to server failed.'; +$messages['smtpautherror'] = 'SMTP Error ($code): Authentication failed.'; +$messages['smtpfromerror'] = 'SMTP Error ($code): Failed to set sender "$from" ($msg).'; +$messages['smtptoerror'] = 'SMTP Error ($code): Failed to add recipient "$to" ($msg).'; +$messages['smtprecipientserror'] = 'SMTP Error: Unable to parse recipients list.'; +$messages['smtperror'] = 'SMTP Error: $msg'; +$messages['emailformaterror'] = 'Invalid e-mail address: $email'; +$messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.'; +$messages['maxgroupmembersreached'] = 'The number of group members exceeds the maximum of $max.'; +$messages['internalerror'] = 'An internal error occured. Please try again.'; +$messages['contactdelerror'] = 'Could not delete contact(s).'; +$messages['contactdeleted'] = 'Contact(s) deleted successfully.'; +$messages['contactrestoreerror'] = 'Could not restore deleted contact(s).'; +$messages['contactrestored'] = 'Contact(s) restored successfully.'; +$messages['groupdeleted'] = 'Group deleted successfully.'; +$messages['grouprenamed'] = 'Group renamed successfully.'; +$messages['groupcreated'] = 'Group created successfully.'; +$messages['savedsearchdeleted'] = 'Saved search deleted successfully.'; +$messages['savedsearchdeleteerror'] = 'Could not delete saved search.'; +$messages['savedsearchcreated'] = 'Saved search created successfully.'; +$messages['savedsearchcreateerror'] = 'Could not create saved search.'; +$messages['messagedeleted'] = 'Message(s) deleted successfully.'; +$messages['messagemoved'] = 'Message(s) moved successfully.'; +$messages['messagecopied'] = 'Message(s) copied successfully.'; +$messages['messagemarked'] = 'Message(s) marked successfully.'; +$messages['autocompletechars'] = 'Enter at least $min characters for autocompletion.'; +$messages['autocompletemore'] = 'More matching entries found. Please type more characters.'; +$messages['namecannotbeempty'] = 'Name cannot be empty.'; +$messages['nametoolong'] = 'Name is too long.'; +$messages['folderupdated'] = 'Folder updated successfully.'; +$messages['foldercreated'] = 'Folder created successfully.'; +$messages['invalidimageformat'] = 'Not a valid image format.'; +$messages['mispellingsfound'] = 'Spelling errors detected in the message.'; +$messages['parentnotwritable'] = 'Unable to create/move folder into selected parent folder. No access rights.'; +$messages['messagetoobig'] = 'The message part is too big to process it.'; +$messages['attachmentvalidationerror'] = 'WARNING! This attachment is suspicious because its type doesn\'t match the type declared in the message. If you do not trust the sender, you shouldn\'t open it in the browser because it may contain malicious contents.<br/><br/><em>Expected: $expected; found: $detected</em>'; +$messages['noscriptwarning'] = 'Warning: This webmail service requires Javascript! In order to use it please enable Javascript in your browser\'s settings.'; ?> diff --git a/program/localization/fa_AF/labels.inc b/program/localization/fa_AF/labels.inc index 38154c23c..70113bc49 100644 --- a/program/localization/fa_AF/labels.inc +++ b/program/localization/fa_AF/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'نامه های ناتکمیل'; $labels['sent'] = 'ارسال شده'; $labels['trash'] = 'اشغال دانی'; $labels['junk'] = 'بیکاره'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'مضمون'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'خلاصه'; $labels['empty'] = 'خالي'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = '‌طريقه استعمال ديسک'; $labels['unknown'] = 'نامعلوم'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'بازنشاندن جستجو'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'در پینجره ای جدید باز کنید'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'بسته اخير را نشان دهيد'; $labels['group'] = 'Group'; $labels['groups'] = 'گروه ها'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'ادرس های شخصي'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/fa_AF/messages.inc b/program/localization/fa_AF/messages.inc index 51ad5b717..4f3d4be55 100644 --- a/program/localization/fa_AF/messages.inc +++ b/program/localization/fa_AF/messages.inc @@ -17,33 +17,33 @@ */ $messages = array(); -$messages['errortitle'] = 'خطا رخ داد'; -$messages['loginfailed'] = 'خطا در ورود به سیستم'; +$messages['errortitle'] = 'An error occurred!'; +$messages['loginfailed'] = 'داخل شدن به سيستم موÙÙ‚ نه شد'; $messages['cookiesdisabled'] = 'جستجوگر شما cookies را قبول نميکند'; $messages['sessionerror'] = 'جلسه شما وجود ندارد Ùˆ يا هم از زمان معين آن گذشته است'; $messages['storageerror'] = 'وصل شدن به آیمیپ سرور موÙÙ‚ نشد'; $messages['servererror'] = 'Server Error!'; -$messages['servererrormsg'] = 'خطای سرور: $msg'; -$messages['dberror'] = 'خطای پایگاه داده'; -$messages['requesttimedout'] = 'عدم پاسخگویی در زمان مقرر'; +$messages['servererrormsg'] = 'Server Error: $msg'; +$messages['dberror'] = 'Database Error!'; +$messages['requesttimedout'] = 'Request timed out'; $messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only.'; $messages['errornoperm'] = 'Unable to perform operation. Permission denied.'; $messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; $messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; $messages['invalidrequest'] = 'Invalid request! No data was saved.'; -$messages['invalidhost'] = 'نام سرور نامعتبر است'; +$messages['invalidhost'] = 'Invalid server name.'; $messages['nomessagesfound'] = 'هيچ پيغامی در اين صندوق پستي درياÙت نه شد'; $messages['loggedout'] = 'جلسه شما بصورت مکمل Ùسخ شده است خدا ØاÙظ'; $messages['mailboxempty'] = 'صندوق پستي خالي است'; -$messages['refreshing'] = 'دوباره سازی....'; -$messages['loading'] = 'در Øال بارگزاری...'; -$messages['uploading'] = 'در Øال بارگزاری Ùایل...'; -$messages['uploadingmany'] = 'در Øال بارگزاری Ùایل ها...'; -$messages['loadingdata'] = 'در Øال بارگزاری داده'; +$messages['refreshing'] = 'Refreshing...'; +$messages['loading'] = 'در Øال باز شدن ...'; +$messages['uploading'] = 'Uploading file...'; +$messages['uploadingmany'] = 'Uploading files...'; +$messages['loadingdata'] = 'در Øال بار کردن دیتا'; $messages['checkingmail'] = 'پيغام های جديد را بررسي ميکند'; $messages['sendingmessage'] = 'پيغام ها را ارسال ميکند'; $messages['messagesent'] = 'پیام موÙقانه ارسال گردید'; -$messages['savingmessage'] = 'در Øال ذخیره کردن پیام'; +$messages['savingmessage'] = 'در Øال ØÙظ کردن پیام'; $messages['messagesaved'] = 'پيغام را به پیش نويس ØÙظ کرد'; $messages['successfullysaved'] = 'ØÙظ پیام موÙقانه صورت گرÙت'; $messages['addedsuccessfully'] = 'آدرس بصورت مکمل در کتاب ادرس علاوه شد'; @@ -59,23 +59,23 @@ $messages['senttooquickly'] = 'ثانیه منتظر باشید$secلطÙا مد $messages['errorsavingsent'] = 'در جريان ØÙظ کردن پیام ارسال شده يکاشتباه به وجود امد'; $messages['errorsaving'] = 'در جريان ØÙظ کردن يکاشتباه به وجود امد'; $messages['errormoving'] = 'پيغام نقل مکان شده نتوانست'; -$messages['errorcopying'] = 'امکان Ú©Ù¾ÛŒ پیام (ها) وجود ندارد'; +$messages['errorcopying'] = 'Could not copy the message(s).'; $messages['errordeleting'] = 'پيغام Øذ٠شده نتوانست'; -$messages['errormarking'] = 'امکان انتخاب پیام (ها) وجود ندارد'; +$messages['errormarking'] = 'Could not mark the message(s).'; $messages['deletecontactconfirm'] = 'آيا واقعاً شما ميخواهيد Ú©Ù‡ آدرس های انتخاب شده را Øذ٠کنيد؟'; $messages['deletegroupconfirm'] = 'Do you really want to delete selected group?'; $messages['deletemessagesconfirm'] = 'آيا واقعاً شما ميخواهيد Ú©Ù‡ پيغام هاي انتخاب شده را Øذ٠کنيد؟'; $messages['deletefolderconfirm'] = 'آيا واقعاً شما ميخواهيد Ú©Ù‡ اين پوشه را Øذ٠کنيد؟'; $messages['purgefolderconfirm'] = 'آيا واقعاً شما ميخواهيد تمام پيغام های Ú©Ù‡ در اين پوشه وجود دارد Øذ٠کنيد؟'; $messages['contactdeleting'] = 'Deleting contact(s)...'; -$messages['groupdeleting'] = 'در Øال Øذ٠گروه...'; +$messages['groupdeleting'] = 'Deleting group...'; $messages['folderdeleting'] = 'در Øال Øذ٠پوشه'; $messages['foldermoving'] = 'در Øال انتقال پوشه'; $messages['foldersubscribing'] = 'Subscribing folder...'; $messages['folderunsubscribing'] = 'Unsubscribing folder...'; $messages['formincomplete'] = 'Ùورمه بصورت مکمل خانه پري نه شده است'; $messages['noemailwarning'] = 'لطÙاً ÙŠÚ© ايميل ادرس موجود را داخل کنيد'; -$messages['nonamewarning'] = 'لطÙاً ÙŠÚ© نام وارد کنيد'; +$messages['nonamewarning'] = 'لطÙاً ÙŠÚ© نام را داخل کنيد'; $messages['nopagesizewarning'] = 'لطÙاً اندازه ÙŠÚ© صÙØÙ‡ را داخل کنيد'; $messages['nosenderwarning'] = 'لطÙاً ایمیل آدرس ارسال کننده را داخل کنید'; $messages['norecipientwarning'] = 'لطÙاً Ú©Ù… از Ú©Ù… ÙŠÚ© آدرس گيرينده را نوشته / داخل کنيد'; @@ -85,32 +85,29 @@ $messages['notsentwarning'] = 'پيغام ارسال نه شده است آیا $messages['noldapserver'] = 'لطÙاً ÙŠÚ© ايل دپ سرور را بخاطر جستجو انتخاب کنيد'; $messages['nosearchname'] = 'لطÙاً ÙŠÚ© نام تماس Ùˆ يا هم ÙŠÚ© ايميل ادرس را داخل کنيد'; $messages['notuploadedwarning'] = 'Not all attachments have been uploaded yet. Please wait or cancel the upload.'; -$messages['searchsuccessful'] = '$nr پیام یاÙت شد'; -$messages['contactsearchsuccessful'] = '$nr Øساب کاربری یاÙت شد'; +$messages['searchsuccessful'] = '$nr پیام دریاÙت شد'; +$messages['contactsearchsuccessful'] = '$nr contacts found.'; $messages['searchnomatch'] = 'جستجو گر موÙÙ‚ به دریاÙت هیچ گونه اثری نشد'; -$messages['searching'] = 'در Øال جستجو..'; +$messages['searching'] = 'در Øال جستجو'; $messages['checking'] = 'در Øال بررسی'; $messages['nospellerrors'] = 'هيچ اشتباه املايي را درياÙت نه کرد'; $messages['folderdeleted'] = 'پوشه موÙقانه از بين رÙت/ Øذ٠گرديد'; $messages['foldersubscribed'] = 'Folder successfully subscribed.'; $messages['folderunsubscribed'] = 'Folder successfully unsubscribed.'; -$messages['folderpurged'] = 'Ù…Øتوای پوشه ها با موÙقیت پاک شدند'; +$messages['folderpurged'] = 'Folder has successfully been emptied.'; $messages['folderexpunged'] = 'Folder has successfully been compacted.'; -$messages['deletedsuccessfully'] = 'با موÙقیت Øذ٠شد'; -$messages['converting'] = 'در Øال پاک کردن ساختار'; +$messages['deletedsuccessfully'] = 'موÙقانه Øذ٠شد'; +$messages['converting'] = 'در Øال از بین بردن Ø´Ú©Ù„ دهی Ùˆ ساختار (Ùرمت)'; $messages['messageopenerror'] = 'پيغام از سرور جريان کرده نتوانست'; -$messages['fileuploaderror'] = 'بارگزاری Ùايل با خطا مواجه شد.'; +$messages['fileuploaderror'] = 'اپلود کردن Ùايل موÙÙ‚ نه شد.'; $messages['filesizeerror'] = 'تثبیت شده میباشد$size Øجم Ùایل آپلود شده بیشتر از Øجم Ú©Ù„ÛŒ'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'آدرس ها کاپی شد. $nrموÙقانه بع تعداد'; +$messages['copyerror'] = 'هيچ ÙŠÚ© از تماس ها را کاپي کرده نتوانست'; $messages['sourceisreadonly'] = 'اجازه نمامه کود / منبع این آدرس Ù‚ÙØ· خواندنی است'; $messages['errorsavingcontact'] = 'ادرس این پیام را ØÙظکرده نتوانست'; $messages['movingmessage'] = 'ذر Øال انتقال پیام...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'در Øال وارد کردن لطÙا صبر Ú©Ù†ÛŒØ $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts, $skipped existing entries skipped</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'اجازه این عملکرد را ندارید'; $messages['nofromaddress'] = 'بخش ایمیل آدرس در شناخت نامه انتخاب شده Ù…Ùقود است.'; $messages['editorwarning'] = 'استÙاده از تصØÛŒØ Ú©Ù†Ù†Ø¯Ù‡ متن ساده تمام Ùرمت Ùˆ ساختار داده شده را از بین خواهد برد. آیا میخواهید Ú©Ù‡ ادامه بدهید.'; diff --git a/program/localization/fa_IR/labels.inc b/program/localization/fa_IR/labels.inc index 79bfbbe9d..221e4b891 100644 --- a/program/localization/fa_IR/labels.inc +++ b/program/localization/fa_IR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'پیش‌نویس‌ها'; $labels['sent'] = 'Ùرستاده شده'; $labels['trash'] = 'سطل آشغال'; $labels['junk'] = 'بنجل'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'موضوع'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'نوع مشاهده Ùهرست'; $labels['folderactions'] = 'اعمال پوشه...'; $labels['compact'] = 'Ùشرده'; $labels['empty'] = 'خالی'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Ùضای استÙاده شده'; $labels['unknown'] = 'ناشناخته'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'جستجوی دوباره'; $labels['searchmod'] = 'اصلاØات جستجو'; $labels['msgtext'] = 'Ú©Ù„ پیغام'; $labels['body'] = 'بدنه'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'باز کردن در پنجره‌ی جدید'; $labels['emlsave'] = 'بارگیری (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'نمایش صÙØÙ‡ آخر'; $labels['group'] = 'گروه'; $labels['groups'] = 'گروه‌ها'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'نشانی‌های شخصی'; $labels['searchsave'] = 'ذخیره جستجو'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'نادیده گرÙتن کلمات دارای $labels['spellcheckignorecaps'] = 'نادیده گرÙتن کلمات با Øرو٠بزرگ'; $labels['addtodict'] = 'اضاÙÙ‡ کردن به واژه‌نامه'; $labels['mailtoprotohandler'] = 'ثبت نگه‌دارنده پروتوکل برای mailto: پیوندها'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'بازگردانی پیغام'; $labels['inline'] = 'خطی'; $labels['asattachment'] = 'به عنوان پیوست'; diff --git a/program/localization/fa_IR/messages.inc b/program/localization/fa_IR/messages.inc index 3f3f861d6..ff53c650e 100644 --- a/program/localization/fa_IR/messages.inc +++ b/program/localization/fa_IR/messages.inc @@ -21,19 +21,19 @@ $messages['errortitle'] = 'خطایی رخ داد!'; $messages['loginfailed'] = 'ورود ناموÙÙ‚ بود.'; $messages['cookiesdisabled'] = 'مرورگر شما کوکی‌ها را قبول نمی‌کند.'; $messages['sessionerror'] = 'نشست شما معتبر نیست، یا منقضی شده است.'; -$messages['storageerror'] = 'اتصال به سرور مخزن ناموÙÙ‚ بود.'; +$messages['storageerror'] = 'اتصال به سرور انباره ناموÙÙ‚ بود.'; $messages['servererror'] = 'خطای سرور!'; $messages['servererrormsg'] = 'خطای سرور: $msg'; -$messages['dberror'] = 'خطای پایگاه داده'; +$messages['dberror'] = 'خطای پایگاه‌داده'; $messages['requesttimedout'] = 'زمان درخواست تمام شد'; -$messages['errorreadonly'] = ' عمل مورد نظر انجام نشد. پوشه Ùقط خواندنی است.'; -$messages['errornoperm'] = ' عمل مورد نظر انجام نشد. دسترسی وجود ندارد.'; -$messages['erroroverquota'] = 'عملیات انجام نشد. دیسک Ùضای خالی ندارد.'; -$messages['erroroverquotadelete'] = 'دیسک Ùضای خالی ندارد. برای Øذ٠پیغام از SHIFT+DEL استÙاده کنید.'; +$messages['errorreadonly'] = 'ناتوانی در انجام عملیات. پوشه Ùقط خواندنی است.'; +$messages['errornoperm'] = 'ناتوانی در انجام عملیات. دسترسی وجود ندارد.'; +$messages['erroroverquota'] = 'ناتوانی در انجام عملیات. Ùضای دیسک خالی نیست.'; +$messages['erroroverquotadelete'] = 'Ùضای دیسک خالی نیست. برای Øذ٠پیغام از SHIFT+DEL استÙاده کنید.'; $messages['invalidrequest'] = 'درخواست نامعتبر! هیچ داده‌ای ذخیره نشد.'; $messages['invalidhost'] = 'نام سرور غیرمعتبر.'; -$messages['nomessagesfound'] = 'هیچ پیغامی در این صندوق‌پستی پیدا نشد.'; -$messages['loggedout'] = 'شما با موÙقیت نشست را پایان دادید. خدانگهدار!'; +$messages['nomessagesfound'] = 'هیچ پیغامی در این صندوق پیدا نشد.'; +$messages['loggedout'] = 'شما با موÙقیت نشست را پایان دادید. خدا نگه‌دار!'; $messages['mailboxempty'] = 'صندوق‌پستی خالی است.'; $messages['refreshing'] = 'نوسازی...'; $messages['loading'] = 'در Øال بارگذاری...'; @@ -46,131 +46,126 @@ $messages['messagesent'] = 'پیغام با موÙقیت Ùرستاده شد.'; $messages['savingmessage'] = 'درØال ذخیره‌ی پیغام...'; $messages['messagesaved'] = 'پیغام در پیش‌نویس‌ها ذخیره شد'; $messages['successfullysaved'] = 'با موÙقیت ذخیره شد.'; -$messages['addedsuccessfully'] = 'مخاطب با موÙقیت به دÙتر نشانی‌ها اضاÙÙ‡ شد.'; -$messages['contactexists'] = 'یک مخاطب با این ایمیل از قبل وجود دارد.'; -$messages['contactnameexists'] = 'یک مخاطب با این نام از قبل وجود دارد.'; -$messages['blockedimages'] = 'برای ØÙاظت از Øریم شخصی شما، عکس‌های با آدرس خارجی در این پیغام مسدود شده‌اند.'; +$messages['addedsuccessfully'] = 'تماس با موÙقیت به دÙتر نشانی‌ها اضاÙÙ‡ شد'; +$messages['contactexists'] = 'یک تماس با این نشانی ایمیل از قبل وجود دارد.'; +$messages['contactnameexists'] = 'یک تماس با این نام از قبل وجود دارد.'; +$messages['blockedimages'] = 'برای ØÙاظت از Øریم شخصی شما، عکس‌های دوردست از پیغام Øذ٠شد.'; $messages['encryptedmessage'] = '!این یک پیغام رمزنگاری شده است Ùˆ قابل نمایش نیست. ببخشید'; -$messages['nocontactsfound'] = 'هیج مخاطبی پیدا نشد.'; -$messages['contactnotfound'] = 'مخاطب درخواست شده پیدا نشد.'; -$messages['contactsearchonly'] = 'برای یاÙتن مخاطب عبارتی را جستجو کنید'; -$messages['sendingfailed'] = 'ارسال پیغام ناموÙÙ‚ بود.'; -$messages['senttooquickly'] = 'لطÙا قبل از ارسال این پیغام $sec ثانیه صبر کنید.'; -$messages['errorsavingsent'] = 'در Ù„Øظه ذخیره پیغام ارسال شده، مشکلی رخ داد.'; -$messages['errorsaving'] = 'هنگام ذخیره‌سازی، مشکلی رخ داد.'; -$messages['errormoving'] = 'پیغام(ها) منتقل نشدند.'; -$messages['errorcopying'] = 'پیغام(ها) Ú©Ù¾ÛŒ نشدند.'; -$messages['errordeleting'] = 'پیغام(ها) Øذ٠نشدند.'; -$messages['errormarking'] = 'پیغام(ها) نشانه‌گذاری نشدند.'; -$messages['deletecontactconfirm'] = 'آیا واقعاً می‌خواهید مخاطب(های) انتخاب شده را Øذ٠کنید؟'; +$messages['nocontactsfound'] = 'هیج تماسی پیدا نشد.'; +$messages['contactnotfound'] = 'تماس درخواست شده پیدا نشد.'; +$messages['contactsearchonly'] = 'چند عبارات جستجو برای یاÙتن تماس ها وارد نمایید'; +$messages['sendingfailed'] = 'ناموÙÙ‚ در Ùرستادن پیغام.'; +$messages['senttooquickly'] = 'لطÙا قبل از ارسال این پیغام $sec صبر کنید.'; +$messages['errorsavingsent'] = 'در Ù„Øظه ذخیره پیغام ارسال شده، مشکل به وجود آمد.'; +$messages['errorsaving'] = 'هنگام ذخیره‌سازی، اشکالی پیش آمد.'; +$messages['errormoving'] = 'ناتوان در انتقال پیغام(ها).'; +$messages['errorcopying'] = 'ناتوان در رونوشت پیغام(ها).'; +$messages['errordeleting'] = 'ناتوان در Øذ٠پیغام(ها).'; +$messages['errormarking'] = 'ناتوان در نشانه گذاری پیغام(ها).'; +$messages['deletecontactconfirm'] = 'آیا واقعاً می‌خواهید تماس(های) انتخاب شده را Øذ٠کنید؟'; $messages['deletegroupconfirm'] = 'آیا واقعا می‌خواهید گروه انتخاب شده را Øذ٠کنید؟'; $messages['deletemessagesconfirm'] = 'آیا واقعاً می‌خواهید پیغام(های) انتخاب شده را Øذ٠کنید؟'; $messages['deletefolderconfirm'] = 'آیا واقعاً می‌خواهید این پوشه را Øذ٠کنید؟'; $messages['purgefolderconfirm'] = 'آیا واقعاً می‌خواهید همه‌ی پیغام‌های داخل این پوشه را Øذ٠کنید؟'; -$messages['contactdeleting'] = 'Øذ٠مخاطب(ها)...'; +$messages['contactdeleting'] = 'Øذ٠تماس(ها)...'; $messages['groupdeleting'] = 'Øذ٠گروه...'; $messages['folderdeleting'] = 'Øذ٠پوشه...'; $messages['foldermoving'] = 'انتقال پوشه...'; $messages['foldersubscribing'] = 'اشتراک پوشه...'; $messages['folderunsubscribing'] = 'لغو اشتراک پوشه...'; -$messages['formincomplete'] = 'Ùرم کامل پر نشده بود.'; -$messages['noemailwarning'] = 'لطÙا یک پست الکترونیکی معتبر وارد کنید.'; +$messages['formincomplete'] = 'Ùرم کاملاً پر نشده بود.'; +$messages['noemailwarning'] = 'لطÙا یک نشانی پست الکترونیکی معتبر وارد کنید.'; $messages['nonamewarning'] = 'لطÙا یک نام وارد کنید.'; -$messages['nopagesizewarning'] = 'لطÙا اندازه‌ی صÙØÙ‡ را وارد کنید.'; -$messages['nosenderwarning'] = 'لطÙا پست الکترونیکی Ùرستنده را وارد کنید.'; +$messages['nopagesizewarning'] = 'لطÙا اندازه ÛŒ صÙØÙ‡ را وارد کنید.'; +$messages['nosenderwarning'] = 'لطÙا آدرس پست الکترونیکی Ùرستنده را وارد کنید.'; $messages['norecipientwarning'] = 'لطÙاً Øداقل یک گیرنده وارد کنید.'; -$messages['nosubjectwarning'] = 'قسمت "موضوع" خالی است. می‌خواهید اکنون وارد کنید؟'; +$messages['nosubjectwarning'] = 'قسمت "موضوع" خالی است. آیا می‌خواهید اکنون وارد کنید؟'; $messages['nobodywarning'] = 'این پیغام بدون متن ارسال شود؟'; $messages['notsentwarning'] = 'پیغام ارسال نشده است. آیا می‌خواهید پیغام را از بین ببرید؟'; -$messages['noldapserver'] = 'لطÙا یک سرور LDAP برای جست‌و‌جو انتخاب کنید.'; -$messages['nosearchname'] = 'لطÙا نام یک مخاطب یا یک نشانی ایمیل وارد کنید.'; -$messages['notuploadedwarning'] = 'همه پیوست ها هنوز بارگذاری نشده‌اند. لطÙا صبر کرده یا بارگذاری را لغو کنید.'; -$messages['searchsuccessful'] = '$nr پیغام پیدا شد.'; -$messages['contactsearchsuccessful'] = '$nr مخاطب ییدا شد.'; -$messages['searchnomatch'] = 'جست‌و‌جو هیچ نتیجه‌ای نداشت.'; -$messages['searching'] = 'در Øال جست‌و‌جو...'; +$messages['noldapserver'] = 'برای جست Ùˆ جو انتخاب کنید LDAP لطÙا یک سرور.'; +$messages['nosearchname'] = 'لطÙا نام یک تماس Ùˆ یا یک نشانی ایمیل وارد کنید.'; +$messages['notuploadedwarning'] = 'همه پیوست ها هنوز بارگذاری نشده اند. لطÙا صبر کنید یا بارگذاری را لغو کنید.'; +$messages['searchsuccessful'] = '$nr پیغام پیدا شد'; +$messages['contactsearchsuccessful'] = '$nr تماس ییدا شد.'; +$messages['searchnomatch'] = 'جست Ùˆ جو هیچ نتیجه‌ای نداشت.'; +$messages['searching'] = 'در Øال جست Ùˆ جو...'; $messages['checking'] = 'در Øال بررسی...'; $messages['nospellerrors'] = 'هیچ اشکال املایی پیدا نشد.'; $messages['folderdeleted'] = 'پوشه با موÙقیت Øذ٠شد.'; -$messages['foldersubscribed'] = 'اشتراک پوشه با موÙقیت انجام شد.'; +$messages['foldersubscribed'] = 'پوشه با موÙقیت اشتراک شد.'; $messages['folderunsubscribed'] = 'اشتراک پوشه با موÙقیت لغو شد.'; $messages['folderpurged'] = 'پوشه با موÙقیت خالی شد.'; $messages['folderexpunged'] = 'پوشه با موÙقیت Ùشرده شد.'; $messages['deletedsuccessfully'] = 'با موÙقیت Øذ٠شد.'; $messages['converting'] = 'در Øال Øذ٠قالب‌بندی...'; -$messages['messageopenerror'] = 'بارگذاری پیغام از روی سرور انجام نشد.'; +$messages['messageopenerror'] = 'ناتوان در بارگذاری پیغام از روی سرور.'; $messages['fileuploaderror'] = 'بارگذاری پرونده ناموÙÙ‚ بود.'; $messages['filesizeerror'] = 'اندازه‌ی پرونده‌ی بارگذاری شده از بیشینه اندازه‌ی $size بیشتر است.'; -$messages['copysuccess'] = '$nr مخاطب با موÙقیت Ú©Ù¾ÛŒ شد.'; -$messages['movesuccess'] = '$nr مخاطب با موÙقیت جابجا شد.'; -$messages['copyerror'] = 'مخاطب‌ها Ú©Ù¾ÛŒ نشدند.'; -$messages['moveerror'] = 'مخاطب‌ها جابجا نشدند.'; -$messages['sourceisreadonly'] = 'این منبع نشانی Ùقط خواندنی است.'; -$messages['errorsavingcontact'] = 'ذخیره‌ی نشانی مخاطب ناموÙÙ‚ بود.'; +$messages['copysuccess'] = '$nr نشانی با موÙقیت رونوشت‌برداری شدند.'; +$messages['copyerror'] = 'رونوشت‌برداری از نشانی‌ها ناموÙÙ‚ بود.'; +$messages['sourceisreadonly'] = 'این منبع نشانی Ùقط‌خواندنی است.'; +$messages['errorsavingcontact'] = 'ذخیره‌ی نشانی تماس ناموÙÙ‚ بود.'; $messages['movingmessage'] = 'در Øال انتقال پیغام(ها)...'; -$messages['copyingmessage'] = 'در Øال کپی‌برداری از پیغام(ها)...'; -$messages['copyingcontact'] = 'در Øال کپی‌برداری مخاطب(ها)...'; -$messages['movingcontact'] = 'در Øال جابجایی مخاطب(ها)...'; +$messages['copyingmessage'] = 'در Øال رونوشت پیغام(ها)...'; +$messages['copyingcontact'] = 'در Øال رونوشت تماس(ها)...'; $messages['deletingmessage'] = 'در Øال Øذ٠پیغام(ها)...'; $messages['markingmessage'] = 'در Øال نشانه‌گذاری پیغام(ها)...'; -$messages['addingmember'] = 'در Øال اÙزودن مخاطب(ها) به گروه...'; -$messages['removingmember'] = 'در Øال Øذ٠مخاطب(ها) از گروه...'; +$messages['addingmember'] = 'در Øال اÙزودن تماس(ها) به گروه...'; +$messages['removingmember'] = 'در Øال انتقال تماس(ها) از گروه...'; $messages['receiptsent'] = 'رسید خواندن با موÙقیت ارسال شد.'; -$messages['errorsendingreceipt'] = 'ارسال رسید انجام نشد.'; -$messages['deleteidentityconfirm'] = 'آیا از Øذ٠این شناسه مطمئن هستید؟'; -$messages['nodeletelastidentity'] = 'این شناسه را نمی‌توانید Øذ٠کنید، زیرا آخرین شناسه شما است.'; -$messages['forbiddencharacter'] = 'نام پوشه شامل یک کاراکتر غیر مجاز است.'; -$messages['selectimportfile'] = 'لطÙاً پرونده‌ای را برای بارگذاری انتخاب کنید.'; +$messages['errorsendingreceipt'] = 'ناتوان در ارسال رسید.'; +$messages['deleteidentityconfirm'] = 'آیا شما مطمئن به Øذ٠این شناسه هستید.'; +$messages['nodeletelastidentity'] = 'نمی‌توانید این شناسه را Øذ٠کنید، زیرا آخرین شناسه شما است.'; +$messages['forbiddencharacter'] = 'نام پوشه شامل یک Øر٠غیر مجاز است.'; +$messages['selectimportfile'] = 'لطÙاً پرونده ای را برای بارگیری انتخاب کنید.'; $messages['addresswriterror'] = 'دÙترچه آدرس انتخابی قابل نوشتن نیست.'; -$messages['contactaddedtogroup'] = 'مخاطب‌ها با موÙقیت به این گروه اضاÙÙ‡ شدند.'; -$messages['contactremovedfromgroup'] = 'مخاطب‌ها با موÙقیت از این گروه Øذ٠شدند.'; +$messages['contactaddedtogroup'] = 'تماس ها با موÙقیت به این گروه اضاÙÙ‡ شدند.'; +$messages['contactremovedfromgroup'] = 'تماس ها با موÙقیت از این گروه Øذ٠شدند.'; $messages['nogroupassignmentschanged'] = 'هیچ تکلی٠گروهی تغییر نکرده است.'; $messages['importwait'] = 'در Øال وارد کردن، لطÙا صبر کنید...'; $messages['importformaterror'] = 'وارد کردن ناموÙÙ‚! Ùایل بارگذاری شده یک Ùایل اطلاعات معتبر نیست.'; -$messages['importconfirm'] = '<b>$inserted مخاطب با موÙقیت وارد شدند</b>'; -$messages['importconfirmskipped'] = '<b>$skipped ورودی موجود نادیده گرÙته شدند</b>'; -$messages['importmessagesuccess'] = 'با موÙقیت $nr پیغام وارد شد.'; -$messages['importmessageerror'] = 'وارد کردن ناموÙÙ‚! Ùایل بارگذاری شده یک پیغام یا صندوق‌پستی معتبر نیست.'; +$messages['importconfirm'] = '<b>تماس های $inserted با موÙقیت وارد شدند</b>'; +$messages['importconfirmskipped'] = '<b>ورودی های موجود $skipped نادیده گرÙته شدند</b>'; $messages['opnotpermitted'] = 'عملیات مجاز نیست!'; -$messages['nofromaddress'] = 'شناسه انتخاب شده پست الکترونیکی ندارد.'; +$messages['nofromaddress'] = 'آدرس پست الکترونیکی های Ù…Ùقود در شناسه انتخاب شده.'; $messages['editorwarning'] = 'تعویض به ویرایشگر متن ساده باعث از دست رÙتن قالب‌بندی همه متن‌ها می‌شود، آیا می‌خواهید عملیات را ادامه بدهید؟'; -$messages['httpreceivedencrypterror'] = 'یک خطای پیکربندی خطرناک رخ داده است. سریعا با سرپرست یا مسئول خود تماس بگیرید. <b>امکان ارسال پیغام شما وجود ندارد.</b>'; +$messages['httpreceivedencrypterror'] = 'یک خطای تنظیم وخیم رخ داده است. سریعا با سرپرست یا مدیر خود تماس بگیرید. <b>امکان ارسال پیغام شما وجود ندارد.</b>'; $messages['smtpconnerror'] = 'خطای SMTP (%code): اتصال به سرور ناموÙÙ‚ بود.'; $messages['smtpautherror'] = 'خطای SMTP (%code): تصدیق هویت ناموÙÙ‚ بود.'; $messages['smtpfromerror'] = 'خطای SMTP (%code): ناموÙÙ‚ در تنظیم Ùرستنده "$from" ($msg).'; $messages['smtptoerror'] = 'خطای SMTP (%code): نام موÙÙ‚ در اÙزودن گیرنده "$to" ($msg).'; $messages['smtprecipientserror'] = 'خطای SMTP: ناتوان در تجزیه Ùهرست گیرنده‌ها.'; $messages['smtperror'] = 'خطای SMTP: $msg'; -$messages['emailformaterror'] = 'پست الکترونیکی نامعتبر: $email'; -$messages['toomanyrecipients'] = 'گیرنده‌های بیش از اندازه: تعداد گیرنده ها را به $max کاهش دهید.'; -$messages['maxgroupmembersreached'] = 'تعداد اعضای گروه بیشتر از $max است.'; +$messages['emailformaterror'] = 'آدرس پیت الکترونیکی نامعتبر: $email'; +$messages['toomanyrecipients'] = 'گیرنده های خیلی زیاد: تعداد گیرنده ها را به تعداد $max کاهش دهید.'; +$messages['maxgroupmembersreached'] = 'تعداد اعضاء گروه از مقدار بیشینه $max بیشتر است.'; $messages['internalerror'] = 'خطای داخلی رخ داد. لطÙا دوباره امتØان کنید.'; -$messages['contactdelerror'] = 'Øذ٠مخاطب(ها) انجام شد.'; -$messages['contactdeleted'] = 'مخاطب(ها) با موÙقیت Øذ٠شدند.'; -$messages['contactrestoreerror'] = 'مخاطب(های) Øذ٠شده بازگردانی نخواهند شد.'; -$messages['contactrestored'] = 'مخاطب(ها) با موÙقیت بازگردانده شدند.'; +$messages['contactdelerror'] = 'تماس(ها) Øذ٠نخواهند شد.'; +$messages['contactdeleted'] = 'تماس(ها) با موÙقیت Øذ٠شدند.'; +$messages['contactrestoreerror'] = 'تماس(های) Øذ٠شده بازگردانی نخواهند شد.'; +$messages['contactrestored'] = 'تماس(ها) با موÙقیت بازگردانده شدند.'; $messages['groupdeleted'] = 'گروه با موÙقیت Øذ٠شد.'; -$messages['grouprenamed'] = 'نام گروه با موÙقیت تغییر داده شد.'; +$messages['grouprenamed'] = 'گروه با موÙقیت تغییر نام داده شد.'; $messages['groupcreated'] = 'گروه با موÙقیت ایجاد شد.'; -$messages['savedsearchdeleted'] = 'جستجوی ذخیره شده با موÙقیت Øذ٠شد.'; -$messages['savedsearchdeleteerror'] = 'Øذ٠جستجوی ذخیره شده انجام نشد.'; -$messages['savedsearchcreated'] = 'جستجوی Øذ٠شده با موÙقیت ایجاد شد.'; -$messages['savedsearchcreateerror'] = 'ساخت جستجوی ذخیره شده انجام نشد.'; +$messages['savedsearchdeleted'] = 'جستجوی ذخیره شد با موÙقیت Øذ٠شد.'; +$messages['savedsearchdeleteerror'] = 'جستجوی ذخیره شد Øذ٠نخواهد شد.'; +$messages['savedsearchcreated'] = 'جستجوی Øذ٠شده با موÙقیت Øذ٠شد.'; +$messages['savedsearchcreateerror'] = 'جستجوی ذخیره شده اÙزوده نخواهد شد.'; $messages['messagedeleted'] = 'پیغام(ها) با موÙقیت Øذ٠شدند.'; $messages['messagemoved'] = 'پیغام(ها) با موÙقیت منتقل شدند.'; -$messages['messagecopied'] = 'پیغام(ها) با موÙقیت Ú©Ù¾ÛŒ شدند.'; -$messages['messagemarked'] = 'پیغام(ها) با موÙقیت نشانه‌گذاری شدند.'; +$messages['messagecopied'] = 'پیغام(ها) با موÙقیت رونوشت شدند.'; +$messages['messagemarked'] = 'پیغام(ها) با موÙقیت نشانه گذاری شدند.'; $messages['autocompletechars'] = 'Øداقل $min Øر٠برای تکمیل خودکار وارد نمایید.'; -$messages['autocompletemore'] = 'نتایج زیادی یاÙت شد. لطÙا Øرو٠بیشتری وارد نمایید.'; +$messages['autocompletemore'] = 'تعداد ورودی های هماهنگ زیادی یاÙت شد. لطÙا Øرو٠بیشتری وارد نمایید.'; $messages['namecannotbeempty'] = 'نام نمی‌تواند خالی باشد.'; $messages['nametoolong'] = 'نام خیلی طولانی است.'; -$messages['folderupdated'] = 'پوشه با موÙقیت به‌روز شد.'; +$messages['folderupdated'] = 'پوشه با موÙقیت بارگذاری شد.'; $messages['foldercreated'] = 'پوشه با موÙقیت اÙزوده شد.'; -$messages['invalidimageformat'] = 'Ùرمت تصویر نامعتبر است.'; +$messages['invalidimageformat'] = 'Ùرمت تصویر نامعتبر.'; $messages['mispellingsfound'] = 'خطای املایی در پیغام شناسایی شد.'; -$messages['parentnotwritable'] = 'به دلیل نداشتن ØÙ‚ دسترسی، ایجاد/انتقال پوشه به پوشه والد انتخاب شده، انجام نشد.'; -$messages['messagetoobig'] = 'بخش پیغام برای پردازش آن خیلی بزرگ است.'; -$messages['attachmentvalidationerror'] = 'هشدار! این پیوست مشکوک است زیرا نوع آن با نوعی Ú©Ù‡ در پیغام اشاره شده مطابقت ندارد. اگر شما به Ùرستنده اطمینان ندارید، نباید آن را در مرورگر باز نمایید زیرا ممکن است Ú©Ù‡ شامل Ù…Øتوای مخرب باشد.<br><br><em>مورد انتظار: $expected; یاÙت شده: $detected</em>'; -$messages['noscriptwarning'] = 'هشدار: این برنامه به جاوااسکریپت نیاز دارد! برای استÙاده از این برنامه لطÙا جاوااسکریپت را در تنظیمات مرورگر خود Ùعال نمایید.'; +$messages['parentnotwritable'] = 'ناتوانی در ایجاد/انتقال پوشه به پوشه والد انتخاب شده. بدون ØÙ‚ دسترسی.'; +$messages['messagetoobig'] = 'بخش پیغام برای اجرای آن خیلی بزرگ است.'; +$messages['attachmentvalidationerror'] = 'هشدار! این پیوست مشکوک است زیرا نوع آن با نوعی Ú©Ù‡ در پیغام اشاره شده مطابقت ندارد. اگر شما Ùرستنده را تایید نمی‌کنید، شما نباید آن را در مرورگر باز نمایید زیرا ممکن است Ú©Ù‡ شامل Ù…Øتوای مخرب باشد.<br/><br/><em>مورد انتظار: $expected; یاÙت شده: $detected</em>'; +$messages['noscriptwarning'] = 'هشدار: این برنامه به جاوااسکریپت نیاز دارد! برای استÙاده از این لطÙا جاوااسکریپت را در تنظیمات مرورگر خود Ùعال نمایید.'; ?> diff --git a/program/localization/fi_FI/labels.inc b/program/localization/fi_FI/labels.inc index ef0f0bff0..ea856b389 100644 --- a/program/localization/fi_FI/labels.inc +++ b/program/localization/fi_FI/labels.inc @@ -194,7 +194,6 @@ $labels['listmode'] = 'Listausnäkymä'; $labels['folderactions'] = 'Kansiotoiminnot...'; $labels['compact'] = 'Tiivistä'; $labels['empty'] = 'Tyhjennä'; -$labels['importmessages'] = 'Tuo viestejä'; $labels['quota'] = 'Levytila'; $labels['unknown'] = 'tuntematon'; @@ -205,7 +204,6 @@ $labels['resetsearch'] = 'Nollaa haku'; $labels['searchmod'] = 'Hakukriteerit'; $labels['msgtext'] = 'Koko viesti'; $labels['body'] = 'Runko'; -$labels['type'] = 'Tyyppi'; $labels['openinextwin'] = 'Avaa uudessa ikkunassa'; $labels['emlsave'] = 'Tallenna (.eml)'; @@ -357,7 +355,6 @@ $labels['lastpage'] = 'Näytä viimeinen luettelo'; $labels['group'] = 'Ryhmä'; $labels['groups'] = 'Ryhmät'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Henkilökohtaiset osoitteet'; $labels['searchsave'] = 'Tallenna haku'; diff --git a/program/localization/fi_FI/messages.inc b/program/localization/fi_FI/messages.inc index adcb36607..3a8c393d6 100644 --- a/program/localization/fi_FI/messages.inc +++ b/program/localization/fi_FI/messages.inc @@ -28,6 +28,8 @@ $messages['dberror'] = 'Tietokantavirhe!'; $messages['requesttimedout'] = 'Pyyntö aikakatkaistiin'; $messages['errorreadonly'] = 'Toiminnon suoritus ei onnistu, koska hakemisto on vain lukutilassa.'; $messages['errornoperm'] = 'Toimintoa ei voitu suorittaa. Ei oikeuksia.'; +$messages['erroroverquota'] = 'Toiminnon suoritus epäonnistui. Levytila on loppu.'; +$messages['erroroverquotadelete'] = 'Levytila on loppu. Paina SHIFT+DEL poistaaksesi viestin.'; $messages['invalidrequest'] = 'Virheellinen pyyntö! Tietoa ei tallennettu.'; $messages['invalidhost'] = 'Virheellinen palvelinnimi.'; $messages['nomessagesfound'] = 'Kansiossa ei ole sähköpostiviestejä'; @@ -163,7 +165,7 @@ $messages['invalidimageformat'] = 'Virheellinen kuvamuoto.'; $messages['mispellingsfound'] = 'Viestissä havaittiin kielioppivirheitä.'; $messages['parentnotwritable'] = 'Kansiota ei voitu siirtää tai luoda valittuun yläkansioon. Ei käyttöoikeutta.'; $messages['messagetoobig'] = 'Viestiosa on liian suuri prosessoitavaksi.'; -$messages['attachmentvalidationerror'] = 'WARNING! This attachment is suspicious because its type doesn\'t match the type declared in the message. If you do not trust the sender, you shouldn\'t open it in the browser because it may contain malicious contents.<br/><br/><em>Expected: $expected; found: $detected</em>'; +$messages['attachmentvalidationerror'] = 'Varoitus! Tämä liitetiedosto on epäilyttävä, koska se ei vastaa ilmoitettua tiedostotyyppiä. Jos et luoda lähettäjään, älä avaa liitetiedostoa välttääksesi mahdollista vahingollista aineistoa.<br/><br/><em>Odotettu: $expected; löydetty: $detected</em>'; $messages['noscriptwarning'] = 'Varoitus: Tämä verkkopohjainen sähköpostipalvelu vaatii Javascriptin toimiakseen. Ota Javascript käyttöön selaimesi asetuksista.'; ?> diff --git a/program/localization/fr_FR/labels.inc b/program/localization/fr_FR/labels.inc index 2a4f3a169..8331bbb54 100644 --- a/program/localization/fr_FR/labels.inc +++ b/program/localization/fr_FR/labels.inc @@ -194,7 +194,6 @@ $labels['listmode'] = 'Mode d\'affichage de la liste'; $labels['folderactions'] = 'Actions du dossier...'; $labels['compact'] = 'Compacter'; $labels['empty'] = 'Vider'; -$labels['importmessages'] = 'Importer des messages'; $labels['quota'] = 'Occupation disque'; $labels['unknown'] = 'inconnue'; @@ -205,7 +204,6 @@ $labels['resetsearch'] = 'Réinitialiser la recherche'; $labels['searchmod'] = 'Portée de la recherche'; $labels['msgtext'] = 'Message entier'; $labels['body'] = 'Corps'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Ouvrir dans une nouvelle fenêtre'; $labels['emlsave'] = 'Télécharger (.eml)'; @@ -357,7 +355,6 @@ $labels['lastpage'] = 'Voir la dernière page'; $labels['group'] = 'Groupe'; $labels['groups'] = 'Groupes'; -$labels['listgroup'] = 'Liste des membres du groupe'; $labels['personaladrbook'] = 'Adresses personnelles'; $labels['searchsave'] = 'Enregistrer la recherche'; @@ -406,7 +403,7 @@ $labels['htmleditor'] = 'Composer un message au format HTML'; $labels['htmlonreply'] = 'en réponse aux messages HTML uniquement'; $labels['htmlonreplyandforward'] = 'Transférer ou répondre au message HTML'; $labels['htmlsignature'] = 'Signature HTML'; -$labels['showemail'] = 'Montrer l\'adresse de courriel avec le nom complet'; +$labels['showemail'] = 'Montrer l\'adresse mail avec le nom complet'; $labels['previewpane'] = 'Afficher le panneau d\'aperçu'; $labels['skin'] = 'Thème de l\'interface'; $labels['logoutclear'] = 'Vider la corbeille à la déconnexion'; @@ -467,9 +464,9 @@ $labels['reqmdn'] = 'Toujours demander un avis de réception'; $labels['reqdsn'] = 'Toujours demander une notification d\'état de distribution'; $labels['replysamefolder'] = 'Placer les réponses dans le dossier du message auquel il est répondu'; $labels['defaultabook'] = 'Carnet d\'adresses par défaut'; -$labels['autocompletesingle'] = 'Ne pas tenir compte des adresses de courriel alternatives dans l\'autoremplissage'; +$labels['autocompletesingle'] = 'Ne pas tenir compte des adresses emails alternatives dans l\'autoremplissage'; $labels['listnamedisplay'] = 'Lister les contacts comme'; -$labels['spellcheckbeforesend'] = 'Vérifier l’orthographe avant l’envoi d’un message'; +$labels['spellcheckbeforesend'] = 'Vérifier l’orthographe avant l’envoie d’un message'; $labels['spellcheckoptions'] = 'Options du vérificateur d\'orthographe'; $labels['spellcheckignoresyms'] = 'Ignorer les mots avec des symboles'; $labels['spellcheckignorenums'] = 'Ignorer les mots avec des nombres'; diff --git a/program/localization/fr_FR/messages.inc b/program/localization/fr_FR/messages.inc index a736e103e..8de50e9e5 100644 --- a/program/localization/fr_FR/messages.inc +++ b/program/localization/fr_FR/messages.inc @@ -18,150 +18,150 @@ $messages = array(); $messages['errortitle'] = 'Une erreur est survenue !'; -$messages['loginfailed'] = 'L\'authentification a échoué'; -$messages['cookiesdisabled'] = 'Votre navigateur n\'accepte pas les cookies'; -$messages['sessionerror'] = 'Votre session est invalide ou a expiré'; -$messages['storageerror'] = 'Erreur de connexion au serveur IMAP'; +$messages['loginfailed'] = 'L\'authentification a échoué.'; +$messages['cookiesdisabled'] = 'Votre navigateur n\'accepte pas les cookies.'; +$messages['sessionerror'] = 'Votre session est invalide ou a expiré.'; +$messages['storageerror'] = 'Erreur de connexion au serveur IMAP.'; $messages['servererror'] = 'Erreur Serveur !'; -$messages['servererrormsg'] = 'Erreur du serveur: $msg'; -$messages['dberror'] = 'Erreur avec la base de donnée!'; +$messages['servererrormsg'] = 'Erreur du serveur : $msg'; +$messages['dberror'] = 'Erreur avec la base de données !'; $messages['requesttimedout'] = 'Délai de la requête expiré'; -$messages['errorreadonly'] = 'Impossible d\'effectuer cette opération. Le dossier est en lecture seule'; -$messages['errornoperm'] = 'Impossible d\'effectuer cette opération. Permission refusée'; +$messages['errorreadonly'] = 'Impossible d\'effectuer cette opération. Le dossier est en lecture seule.'; +$messages['errornoperm'] = 'Impossible d\'effectuer cette opération. Permission refusée.'; $messages['erroroverquota'] = 'Impossible d\'effectuer cette opération. Plus d\'espace libre.'; $messages['erroroverquotadelete'] = 'Plus d\'espace libre. Utilisez SHIFT+DEL pour supprimer un message.'; $messages['invalidrequest'] = 'Requête invalide ! Aucune donnée n\'a été sauvegardée.'; $messages['invalidhost'] = 'Nom du serveur invalide.'; $messages['nomessagesfound'] = 'Cette boîte aux lettres ne contient aucun message.'; -$messages['loggedout'] = 'Vous venez de vous déconnecter avec succès. Au revoir !'; +$messages['loggedout'] = 'Vous vous êtes correctement déconnecté. Au revoir !'; $messages['mailboxempty'] = 'La boîte aux lettres est vide.'; $messages['refreshing'] = 'Rafraîchissement en cours...'; -$messages['loading'] = 'Chargement...'; -$messages['uploading'] = 'Envoi du fichier...'; -$messages['uploadingmany'] = 'Envoi des fichiers ...'; -$messages['loadingdata'] = 'Chargement des données...'; +$messages['loading'] = 'Chargement en cours...'; +$messages['uploading'] = 'Transfert du fichier en cours...'; +$messages['uploadingmany'] = 'Transfert des fichiers en cours...'; +$messages['loadingdata'] = 'Chargement des données en cours...'; $messages['checkingmail'] = 'Vérification des nouveaux messages...'; -$messages['sendingmessage'] = 'Expédition du message...'; -$messages['messagesent'] = 'Message expédié.'; -$messages['savingmessage'] = 'Sauvegarde du message...'; -$messages['messagesaved'] = 'Message sauvegardé dans Brouillons'; -$messages['successfullysaved'] = 'Sauvegarde effectuée'; -$messages['addedsuccessfully'] = 'Contact ajouté dans le carnet d\'adresses'; -$messages['contactexists'] = 'Cette adresse courriel est utilisée par un autre contact'; +$messages['sendingmessage'] = 'Envoi du message en cours...'; +$messages['messagesent'] = 'Le message a bien été expédié.'; +$messages['savingmessage'] = 'Sauvegarde du message en cours...'; +$messages['messagesaved'] = 'Message sauvegardé dans Brouillons.'; +$messages['successfullysaved'] = 'La sauvegarde a bien été effectuée.'; +$messages['addedsuccessfully'] = 'Le contact a bien été ajouté dans le carnet d\'adresses.'; +$messages['contactexists'] = 'Cette adresse courriel est utilisée par un autre contact.'; $messages['contactnameexists'] = 'Il existe déjà un contact nommé ainsi.'; $messages['blockedimages'] = 'Les images distantes sont bloquées pour protéger votre vie privée.'; $messages['encryptedmessage'] = 'Désolé, ce message est chiffré et ne peut être affiché.'; -$messages['nocontactsfound'] = 'Aucun contact n\'a pu être trouvé'; +$messages['nocontactsfound'] = 'Aucun contact n\'a pu être trouvé.'; $messages['contactnotfound'] = 'Le contact demandé n\'a pas été trouvé.'; -$messages['contactsearchonly'] = 'Entrez un ou plusieurs mots clés pour trouver des contacts'; -$messages['sendingfailed'] = 'L\'envoi du message a échoué'; -$messages['senttooquickly'] = 'Vous devez attendre $sec s. pour envoyer le message'; -$messages['errorsavingsent'] = 'Une erreur est survenue pendant la sauvegarde du message envoyé'; -$messages['errorsaving'] = 'Une erreur a empêché la sauvegarde'; -$messages['errormoving'] = 'Impossible de déplacer le message'; -$messages['errorcopying'] = 'La copie de ce(s) message(s) a échoué.'; -$messages['errordeleting'] = 'Impossible d\'effacer le message'; -$messages['errormarking'] = 'Impossible de marquer le message'; +$messages['contactsearchonly'] = 'Entrez un ou plusieurs mots clés pour trouver des contacts.'; +$messages['sendingfailed'] = 'L\'envoi du message a échoué.'; +$messages['senttooquickly'] = 'Veuillez patienter $sec s. pour envoyer ce message.'; +$messages['errorsavingsent'] = 'Une erreur est survenue pendant la sauvegarde du message envoyé.'; +$messages['errorsaving'] = 'Une erreur est survenue pendant la sauvegarde.'; +$messages['errormoving'] = 'Impossible de déplacer le(s) message(s).'; +$messages['errorcopying'] = 'Impossible de copier le(s) message(s).'; +$messages['errordeleting'] = 'Impossible de supprimer le(s) message(s).'; +$messages['errormarking'] = 'Impossible de marquer le(s) message(s).'; $messages['deletecontactconfirm'] = 'Êtes-vous sûr de vouloir supprimer le(s) contact(s) sélectionné(s) ?'; $messages['deletegroupconfirm'] = 'Êtes-vous sûr de vouloir supprimer le groupe sélectionné ?'; $messages['deletemessagesconfirm'] = 'Êtes-vous sûr de vouloir supprimer le(s) message(s) sélectionné(s) ?'; $messages['deletefolderconfirm'] = 'Êtes-vous sûr de vouloir supprimer ce dossier ?'; $messages['purgefolderconfirm'] = 'Êtes-vous sûr de vouloir supprimer tous les messages de ce dossier ?'; -$messages['contactdeleting'] = 'Suppression de contact(s)...'; -$messages['groupdeleting'] = 'Suppression du groupe ...'; +$messages['contactdeleting'] = 'Suppression de contact(s) en cours...'; +$messages['groupdeleting'] = 'Suppression du groupe...'; $messages['folderdeleting'] = 'Suppression du dossier...'; $messages['foldermoving'] = 'Déplacement du dossier...'; $messages['foldersubscribing'] = 'Inscription du dossier...'; $messages['folderunsubscribing'] = 'Désinscription du dossier...'; -$messages['formincomplete'] = 'Le formulaire n\'a pas été entièrement rempli'; -$messages['noemailwarning'] = 'Veuillez spécifier un courriel valide'; -$messages['nonamewarning'] = 'Veuillez fournir un nom'; -$messages['nopagesizewarning'] = 'Veuillez indiquer une taille de page'; -$messages['nosenderwarning'] = 'Veuillez renseigner l\'adresse d\'expéditeur'; -$messages['norecipientwarning'] = 'Veuillez ajouter au moins un destinataire'; +$messages['formincomplete'] = 'Le formulaire n\'a pas été entièrement rempli.'; +$messages['noemailwarning'] = 'Veuillez spécifier un courriel valide.'; +$messages['nonamewarning'] = 'Veuillez fournir un nom.'; +$messages['nopagesizewarning'] = 'Veuillez indiquer une taille de page.'; +$messages['nosenderwarning'] = 'Veuillez renseigner l\'adresse d\'expéditeur.'; +$messages['norecipientwarning'] = 'Veuillez ajouter au moins un destinataire.'; $messages['nosubjectwarning'] = 'Le champ «Objet» est vide. Souhaitez-vous le renseigner maintenant ?'; $messages['nobodywarning'] = 'Envoyer ce message sans texte ?'; $messages['notsentwarning'] = 'Le message n\'a pas été envoyé. Voulez-vous abandonner ce message ?'; -$messages['noldapserver'] = 'Choisissez un serveur LDAP pour la recherche'; -$messages['nosearchname'] = 'Entrez un nom de contact ou un courriel'; -$messages['notuploadedwarning'] = 'Certaines pièces jointes sont en cours d\'expédition : attendez ou annulez l\'envoi.'; -$messages['searchsuccessful'] = '$nr messages trouvés'; +$messages['noldapserver'] = 'Choisissez un serveur LDAP pour la recherche.'; +$messages['nosearchname'] = 'Entrez un nom de contact ou un courriel.'; +$messages['notuploadedwarning'] = 'Toutes les pièces jointes n\'ont pas encore été transférées. Veuillez patienter ou annuler cette opération.'; +$messages['searchsuccessful'] = '$nr message(s) trouvé(s).'; $messages['contactsearchsuccessful'] = '$nr contact(s) trouvé(s).'; -$messages['searchnomatch'] = 'La recherche ne donne aucun résultat'; -$messages['searching'] = 'En cours de recherche...'; -$messages['checking'] = 'Vérification...'; -$messages['nospellerrors'] = 'Aucune faute trouvée'; -$messages['folderdeleted'] = 'Dossier effacé'; -$messages['foldersubscribed'] = 'Le dossier a bien été inscrit'; -$messages['folderunsubscribed'] = 'Le dossier a bien été désinscrit'; -$messages['folderpurged'] = 'Le dossier a bien été vidé'; -$messages['folderexpunged'] = 'Le dossier a bien été compacté'; -$messages['deletedsuccessfully'] = 'Supprimé(s) avec succès'; +$messages['searchnomatch'] = 'La recherche n\'a donné aucun résultat.'; +$messages['searching'] = 'Recherche en cours...'; +$messages['checking'] = 'Vérification en cours...'; +$messages['nospellerrors'] = 'Aucune faute d\'orthographe trouvée.'; +$messages['folderdeleted'] = 'Le dossier a bien été effacé.'; +$messages['foldersubscribed'] = 'Le dossier a bien été inscrit.'; +$messages['folderunsubscribed'] = 'Le dossier a bien été désinscrit.'; +$messages['folderpurged'] = 'Le dossier a bien été vidé.'; +$messages['folderexpunged'] = 'Le dossier a bien été compacté.'; +$messages['deletedsuccessfully'] = 'Correctement supprimé(s).'; $messages['converting'] = 'Suppression de la mise en forme...'; -$messages['messageopenerror'] = 'Impossible de charger le message depuis serveur'; +$messages['messageopenerror'] = 'Impossible de charger le message depuis serveur.'; $messages['fileuploaderror'] = 'Transfert du fichier échoué'; -$messages['filesizeerror'] = 'Le fichier transféré dépasse la taille maximale de $size'; -$messages['copysuccess'] = 'Succès de la copie des $nr adresses'; -$messages['copyerror'] = 'Ne peut pas copier les adresses'; -$messages['sourceisreadonly'] = 'Cette source d\'adresse est en lecture seule'; -$messages['errorsavingcontact'] = 'Ne peut pas enregistrer l\'adresse du contact'; -$messages['movingmessage'] = 'Déplacement du message...'; -$messages['copyingmessage'] = 'Copie du message ...'; -$messages['copyingcontact'] = 'Copie des contacts ...'; -$messages['deletingmessage'] = 'Suppression des messages...'; -$messages['markingmessage'] = 'Marquage des messages...'; -$messages['addingmember'] = 'Ajout des contacts dans le groupe ...'; -$messages['removingmember'] = 'Suppression des contacts du groupe ...'; -$messages['receiptsent'] = 'L\'accusé de réception a bien été envoyé'; -$messages['errorsendingreceipt'] = 'L\'accusé de réception n\'a pas pu être envoyé'; -$messages['deleteidentityconfirm'] = 'Voulez vous vraiment supprimer cette identités ?'; +$messages['filesizeerror'] = 'Le fichier transféré dépasse la taille maximale de $size.'; +$messages['copysuccess'] = 'Les $nr adresses ont bien été copiées.'; +$messages['copyerror'] = 'Impossible de copier des adresses.'; +$messages['sourceisreadonly'] = 'Cette source d\'adresse est en lecture seule.'; +$messages['errorsavingcontact'] = 'Impossible de sauvegarder l\'adresse du contact.'; +$messages['movingmessage'] = 'Message(s) en cours de déplacement...'; +$messages['copyingmessage'] = 'Message(s) en cours de copie...'; +$messages['copyingcontact'] = 'Contact(s) en cours de copie...'; +$messages['deletingmessage'] = 'Message(s) en cours de suppression...'; +$messages['markingmessage'] = 'Message(s) en cours de marquage...'; +$messages['addingmember'] = 'Contact(s) en cours d\'ajout dans le groupe...'; +$messages['removingmember'] = 'Contact(s) en cours de suppression du groupe...'; +$messages['receiptsent'] = 'L\'accusé de réception a bien été envoyé.'; +$messages['errorsendingreceipt'] = 'Impossible d\'envoyer l\'accusé de réception.'; +$messages['deleteidentityconfirm'] = 'Voulez vous vraiment supprimer cette identité ?'; $messages['nodeletelastidentity'] = 'Vous ne pouvez pas effacer votre seule identité.'; -$messages['forbiddencharacter'] = 'Le nom du dossier contient un caractère interdit'; -$messages['selectimportfile'] = 'Veuillez sélectionner un fichier à envoyer'; -$messages['addresswriterror'] = 'Impossible d\'écrire dans le carnet d\'adresse sélectionné'; -$messages['contactaddedtogroup'] = 'Les contacts ont bien été ajoutés à ce groupe'; -$messages['contactremovedfromgroup'] = 'Les contacts ont bien été supprimés de ce groupe'; +$messages['forbiddencharacter'] = 'Le nom du dossier contient un caractère interdit.'; +$messages['selectimportfile'] = 'Veuillez sélectionner un fichier à transférer.'; +$messages['addresswriterror'] = 'Impossible d\'écrire dans le carnet d\'adresse sélectionné.'; +$messages['contactaddedtogroup'] = 'Les contacts ont bien été ajoutés à ce groupe.'; +$messages['contactremovedfromgroup'] = 'Les contacts ont bien été supprimés de ce groupe.'; $messages['nogroupassignmentschanged'] = 'Appartenance aux groupes inchangée.'; -$messages['importwait'] = 'Importation, veuillez patienter...'; -$messages['importformaterror'] = 'Echec de l\'import ! Le fichier n\'est pas un fichier d\'import de données valide.'; -$messages['importconfirm'] = '<b>$inserted contacts importés avec succès, $skipped entrées existantes ignorées</b>:<p><em>$names</em></p>'; +$messages['importwait'] = 'Import en cours, veuillez patienter...'; +$messages['importformaterror'] = 'L\'import a échoué ! Le fichier transféré n\'est pas un fichier d\'import de données valide.'; +$messages['importconfirm'] = '<b>Les $inserted contacts ont bien été importés</b>'; $messages['importconfirmskipped'] = '<b>$skipped entrée(s) déjà existante(s)</b>'; $messages['opnotpermitted'] = 'Cette opération n\'est pas permise !'; -$messages['nofromaddress'] = 'Il manque une adresse e-mail dans l\'identité sélectionnée'; -$messages['editorwarning'] = 'Passer à l\'éditeur texte seul causera la perte du formatage du texte. Voulez-vous continuer ?'; +$messages['nofromaddress'] = 'Courriel manquant dans l\'identité sélectionnée.'; +$messages['editorwarning'] = 'Passer à l\'éditeur de texte brut causera la perte du formatage du texte. Souhaitez-vous continuer ?'; $messages['httpreceivedencrypterror'] = 'Une erreur fatale de configuration est survenue. Veuillez contacter votre administrateur immédiatement. <b>Votre message n\'a pas pu être envoyé.</b>'; -$messages['smtpconnerror'] = 'Erreur SMTP ($code): Echec de la connexion au serveur'; -$messages['smtpautherror'] = 'Erreur SMTP ($code): Echec de l\'authentification'; -$messages['smtpfromerror'] = 'Erreur SMTP ($code): Impossible de définir l\'expéditeur "$from" ($msg)'; -$messages['smtptoerror'] = 'Erreur SMTP ($code): Impossible d\'ajouter le destinataire "$to" ($msg)'; -$messages['smtprecipientserror'] = 'Erreur SMTP: Impossible de lire la liste des destinataires'; -$messages['smtperror'] = 'Erreur SMTP: $msg'; -$messages['emailformaterror'] = 'Adresse email incorrecte: $email'; +$messages['smtpconnerror'] = 'Erreur SMTP ($code) : Échec de la connexion au serveur.'; +$messages['smtpautherror'] = 'Erreur SMTP ($code) : Échec de l\'authentification.'; +$messages['smtpfromerror'] = 'Erreur SMTP ($code) : Impossible de définir l\'expéditeur "$from" ($msg)'; +$messages['smtptoerror'] = 'Erreur SMTP ($code) : Impossible d\'ajouter le destinataire "$to" ($msg)'; +$messages['smtprecipientserror'] = 'Erreur SMTP : Impossible de lire la liste des destinataires.'; +$messages['smtperror'] = 'Erreur SMTP : $msg'; +$messages['emailformaterror'] = 'Courriel incorrect : $email'; $messages['toomanyrecipients'] = 'Trop de destinataires. Réduisez leur nombre à $max maximum.'; $messages['maxgroupmembersreached'] = 'Le nombre de membres du groupe dépasse le maximum de $max.'; -$messages['internalerror'] = 'Une erreur interne est survenue. Merci de réessayer'; -$messages['contactdelerror'] = 'Les contacts n\'ont pas pu être supprimés'; -$messages['contactdeleted'] = 'Les contacts ont bien été supprimés'; -$messages['contactrestoreerror'] = 'Impossible de restaurer les contacts supprimés.'; -$messages['contactrestored'] = 'Les contacts ont bien été restaurés.'; -$messages['groupdeleted'] = 'Le groupe a bien été supprimé'; -$messages['grouprenamed'] = 'Le groupe a bien été renommé'; -$messages['groupcreated'] = 'Le groupe a bien été créé'; +$messages['internalerror'] = 'Une erreur interne est survenue. Veuillez réessayer.'; +$messages['contactdelerror'] = 'Impossible de supprimer le(s) contact(s).'; +$messages['contactdeleted'] = 'Contact(s) correctement supprimé(s).'; +$messages['contactrestoreerror'] = 'Impossible de restaurer le(s) contact(s) supprimé(s).'; +$messages['contactrestored'] = 'Contact(s) correctement restauré(s).'; +$messages['groupdeleted'] = 'Le groupe a bien été supprimé.'; +$messages['grouprenamed'] = 'Le groupe a bien été renommé.'; +$messages['groupcreated'] = 'Le groupe a bien été créé.'; $messages['savedsearchdeleted'] = 'La recherche enregistrée a bien été supprimée.'; $messages['savedsearchdeleteerror'] = 'Impossible de supprimer la recherche enregistrée.'; -$messages['savedsearchcreated'] = 'La recherche enregistrée a bien été crée.'; +$messages['savedsearchcreated'] = 'La recherche enregistrée a bien été créée.'; $messages['savedsearchcreateerror'] = 'Impossible de créer la recherche enregistrée.'; -$messages['messagedeleted'] = 'Les messages ont bien été supprimés'; -$messages['messagemoved'] = 'Les messages ont bien été déplacés'; -$messages['messagecopied'] = 'Les messages ont bien été copiés'; -$messages['messagemarked'] = 'Les messages ont bien été marqués'; -$messages['autocompletechars'] = 'Entrez au moins $min caractères pour l\'auto-complétion'; -$messages['autocompletemore'] = 'Plusieurs entrées trouvées. Tapez plus de caractères.'; -$messages['namecannotbeempty'] = 'Le nom ne peut pas être vide'; -$messages['nametoolong'] = 'Le nom est trop long'; -$messages['folderupdated'] = 'Le dossier a bien été mis à jour'; -$messages['foldercreated'] = 'Le dossier a bien été créé'; -$messages['invalidimageformat'] = 'Format d\'image invalide'; +$messages['messagedeleted'] = 'Message(s) correctement supprimé(s).'; +$messages['messagemoved'] = 'Message(s) correctement déplacé(s).'; +$messages['messagecopied'] = 'Message(s) correctement copié(s).'; +$messages['messagemarked'] = 'Message(s) correctement marqué(s).'; +$messages['autocompletechars'] = 'Entrez au moins $min caractères pour l\'auto-complétion.'; +$messages['autocompletemore'] = 'Plusieurs entrées trouvées. Veuillez taper plus de caractères.'; +$messages['namecannotbeempty'] = 'Le nom ne peut pas être vide.'; +$messages['nametoolong'] = 'Le nom est trop long.'; +$messages['folderupdated'] = 'Le dossier a bien été mis à jour.'; +$messages['foldercreated'] = 'Le dossier a bien été créé.'; +$messages['invalidimageformat'] = 'Format d\'image invalide.'; $messages['mispellingsfound'] = 'Des fautes d\'orthographe ont été détectées dans le message.'; $messages['parentnotwritable'] = 'Impossible de créer/déplacer le dossier dans le dossier parent sélectionné. Aucun droit d\'accès.'; $messages['messagetoobig'] = 'Le message est trop gros pour être traité.'; diff --git a/program/localization/fy_NL/labels.inc b/program/localization/fy_NL/labels.inc index 5ffd906eb..891371f58 100644 --- a/program/localization/fy_NL/labels.inc +++ b/program/localization/fy_NL/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Konsepten'; $labels['sent'] = 'Stjoerd'; $labels['trash'] = 'Jiskefet'; $labels['junk'] = 'Junk'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Ûnderwerp'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compact'; $labels['empty'] = 'Empty'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'unknown'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reset search'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/fy_NL/messages.inc b/program/localization/fy_NL/messages.inc index 16f4c67bf..1dacf4adc 100644 --- a/program/localization/fy_NL/messages.inc +++ b/program/localization/fy_NL/messages.inc @@ -2,172 +2,15 @@ /* +-----------------------------------------------------------------------+ - | localization/<lang>/messages.inc | + | localization/fy_NL/messages.inc | | | - | Localization file of the Roundcube Webmail client | - | Copyright (C) 2005-2013, The Roundcube Dev Team | - | | - | Licensed under the GNU General Public License version 3 or | - | any later version with exceptions for skins & plugins. | - | See the README file for a full license statement. | + | Language file of the Roundcube Webmail client | + | Copyright (C) 2012, The Roundcube Dev Team | + | Licensed under the GNU General Public License | | | +-----------------------------------------------------------------------+ - - For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/messages/ + | Author: unknown | + +-----------------------------------------------------------------------+ */ -$messages = array(); -$messages['errortitle'] = 'An error occurred!'; -$messages['loginfailed'] = 'Login failed.'; -$messages['cookiesdisabled'] = 'Your browser does not accept cookies.'; -$messages['sessionerror'] = 'Your session is invalid or expired.'; -$messages['storageerror'] = 'Connection to storage server failed.'; -$messages['servererror'] = 'Server Error!'; -$messages['servererrormsg'] = 'Server Error: $msg'; -$messages['dberror'] = 'Database Error!'; -$messages['requesttimedout'] = 'Request timed out'; -$messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only.'; -$messages['errornoperm'] = 'Unable to perform operation. Permission denied.'; -$messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; -$messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; -$messages['invalidrequest'] = 'Invalid request! No data was saved.'; -$messages['invalidhost'] = 'Invalid server name.'; -$messages['nomessagesfound'] = 'No messages found in this mailbox.'; -$messages['loggedout'] = 'You have successfully terminated the session. Good bye!'; -$messages['mailboxempty'] = 'Mailbox is empty.'; -$messages['refreshing'] = 'Refreshing...'; -$messages['loading'] = 'Loading...'; -$messages['uploading'] = 'Uploading file...'; -$messages['uploadingmany'] = 'Uploading files...'; -$messages['loadingdata'] = 'Loading data...'; -$messages['checkingmail'] = 'Checking for new messages...'; -$messages['sendingmessage'] = 'Sending message...'; -$messages['messagesent'] = 'Message sent successfully.'; -$messages['savingmessage'] = 'Saving message...'; -$messages['messagesaved'] = 'Message saved to Drafts.'; -$messages['successfullysaved'] = 'Successfully saved.'; -$messages['addedsuccessfully'] = 'Contact added successfully to address book.'; -$messages['contactexists'] = 'A contact with the same e-mail address already exists.'; -$messages['contactnameexists'] = 'A contact with the same name already exists.'; -$messages['blockedimages'] = 'To protect your privacy, remote images are blocked in this message.'; -$messages['encryptedmessage'] = 'This is an encrypted message and can not be displayed. Sorry!'; -$messages['nocontactsfound'] = 'No contacts found.'; -$messages['contactnotfound'] = 'The requested contact was not found.'; -$messages['contactsearchonly'] = 'Enter some search terms to find contacts'; -$messages['sendingfailed'] = 'Failed to send message.'; -$messages['senttooquickly'] = 'Please wait $sec sec(s). before sending this message.'; -$messages['errorsavingsent'] = 'An error occured while saving sent message.'; -$messages['errorsaving'] = 'An error occured while saving.'; -$messages['errormoving'] = 'Could not move the message(s).'; -$messages['errorcopying'] = 'Could not copy the message(s).'; -$messages['errordeleting'] = 'Could not delete the message(s).'; -$messages['errormarking'] = 'Could not mark the message(s).'; -$messages['deletecontactconfirm'] = 'Do you really want to delete selected contact(s)?'; -$messages['deletegroupconfirm'] = 'Do you really want to delete selected group?'; -$messages['deletemessagesconfirm'] = 'Do you really want to delete selected message(s)?'; -$messages['deletefolderconfirm'] = 'Do you really want to delete this folder?'; -$messages['purgefolderconfirm'] = 'Do you really want to delete all messages in this folder?'; -$messages['contactdeleting'] = 'Deleting contact(s)...'; -$messages['groupdeleting'] = 'Deleting group...'; -$messages['folderdeleting'] = 'Deleting folder...'; -$messages['foldermoving'] = 'Moving folder...'; -$messages['foldersubscribing'] = 'Subscribing folder...'; -$messages['folderunsubscribing'] = 'Unsubscribing folder...'; -$messages['formincomplete'] = 'The form was not completely filled out.'; -$messages['noemailwarning'] = 'Please enter a valid email address.'; -$messages['nonamewarning'] = 'Please enter a name.'; -$messages['nopagesizewarning'] = 'Please enter a page size.'; -$messages['nosenderwarning'] = 'Please enter sender e-mail address.'; -$messages['norecipientwarning'] = 'Please enter at least one recipient.'; -$messages['nosubjectwarning'] = 'The "Subject" field is empty. Would you like to enter one now?'; -$messages['nobodywarning'] = 'Send this message without text?'; -$messages['notsentwarning'] = 'Message has not been sent. Do you want to discard your message?'; -$messages['noldapserver'] = 'Please select an ldap server to search.'; -$messages['nosearchname'] = 'Please enter a contact name or email address.'; -$messages['notuploadedwarning'] = 'Not all attachments have been uploaded yet. Please wait or cancel the upload.'; -$messages['searchsuccessful'] = '$nr messages found.'; -$messages['contactsearchsuccessful'] = '$nr contacts found.'; -$messages['searchnomatch'] = 'Search returned no matches.'; -$messages['searching'] = 'Searching...'; -$messages['checking'] = 'Checking...'; -$messages['nospellerrors'] = 'No spelling errors found.'; -$messages['folderdeleted'] = 'Folder successfully deleted.'; -$messages['foldersubscribed'] = 'Folder successfully subscribed.'; -$messages['folderunsubscribed'] = 'Folder successfully unsubscribed.'; -$messages['folderpurged'] = 'Folder has successfully been emptied.'; -$messages['folderexpunged'] = 'Folder has successfully been compacted.'; -$messages['deletedsuccessfully'] = 'Successfully deleted.'; -$messages['converting'] = 'Removing formatting...'; -$messages['messageopenerror'] = 'Could not load message from server.'; -$messages['fileuploaderror'] = 'File upload failed.'; -$messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr addresses.'; -$messages['copyerror'] = 'Could not copy any addresses.'; -$messages['sourceisreadonly'] = 'This address source is read only.'; -$messages['errorsavingcontact'] = 'Could not save the contact address.'; -$messages['movingmessage'] = 'Moving message(s)...'; -$messages['copyingmessage'] = 'Copying message(s)...'; -$messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['deletingmessage'] = 'Deleting message(s)...'; -$messages['markingmessage'] = 'Marking message(s)...'; -$messages['addingmember'] = 'Adding contact(s) to the group...'; -$messages['removingmember'] = 'Removing contact(s) from the group...'; -$messages['receiptsent'] = 'Successfully sent a read receipt.'; -$messages['errorsendingreceipt'] = 'Could not send the receipt.'; -$messages['deleteidentityconfirm'] = 'Do you really want to delete this identity?'; -$messages['nodeletelastidentity'] = 'You cannot delete this identity, it\'s your last one.'; -$messages['forbiddencharacter'] = 'Folder name contains a forbidden character.'; -$messages['selectimportfile'] = 'Please select a file to upload.'; -$messages['addresswriterror'] = 'The selected address book is not writeable.'; -$messages['contactaddedtogroup'] = 'Successfully added the contacts to this group.'; -$messages['contactremovedfromgroup'] = 'Successfully removed contacts from this group.'; -$messages['nogroupassignmentschanged'] = 'No group assignments changed.'; -$messages['importwait'] = 'Importing, please wait...'; -$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; -$messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; -$messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; -$messages['opnotpermitted'] = 'Operation not permitted!'; -$messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; -$messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; -$messages['httpreceivedencrypterror'] = 'A fatal configuration error occurred. Contact your administrator immediately. <b>Your message can not be sent.</b>'; -$messages['smtpconnerror'] = 'SMTP Error ($code): Connection to server failed.'; -$messages['smtpautherror'] = 'SMTP Error ($code): Authentication failed.'; -$messages['smtpfromerror'] = 'SMTP Error ($code): Failed to set sender "$from" ($msg).'; -$messages['smtptoerror'] = 'SMTP Error ($code): Failed to add recipient "$to" ($msg).'; -$messages['smtprecipientserror'] = 'SMTP Error: Unable to parse recipients list.'; -$messages['smtperror'] = 'SMTP Error: $msg'; -$messages['emailformaterror'] = 'Invalid e-mail address: $email'; -$messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.'; -$messages['maxgroupmembersreached'] = 'The number of group members exceeds the maximum of $max.'; -$messages['internalerror'] = 'An internal error occured. Please try again.'; -$messages['contactdelerror'] = 'Could not delete contact(s).'; -$messages['contactdeleted'] = 'Contact(s) deleted successfully.'; -$messages['contactrestoreerror'] = 'Could not restore deleted contact(s).'; -$messages['contactrestored'] = 'Contact(s) restored successfully.'; -$messages['groupdeleted'] = 'Group deleted successfully.'; -$messages['grouprenamed'] = 'Group renamed successfully.'; -$messages['groupcreated'] = 'Group created successfully.'; -$messages['savedsearchdeleted'] = 'Saved search deleted successfully.'; -$messages['savedsearchdeleteerror'] = 'Could not delete saved search.'; -$messages['savedsearchcreated'] = 'Saved search created successfully.'; -$messages['savedsearchcreateerror'] = 'Could not create saved search.'; -$messages['messagedeleted'] = 'Message(s) deleted successfully.'; -$messages['messagemoved'] = 'Message(s) moved successfully.'; -$messages['messagecopied'] = 'Message(s) copied successfully.'; -$messages['messagemarked'] = 'Message(s) marked successfully.'; -$messages['autocompletechars'] = 'Enter at least $min characters for autocompletion.'; -$messages['autocompletemore'] = 'More matching entries found. Please type more characters.'; -$messages['namecannotbeempty'] = 'Name cannot be empty.'; -$messages['nametoolong'] = 'Name is too long.'; -$messages['folderupdated'] = 'Folder updated successfully.'; -$messages['foldercreated'] = 'Folder created successfully.'; -$messages['invalidimageformat'] = 'Not a valid image format.'; -$messages['mispellingsfound'] = 'Spelling errors detected in the message.'; -$messages['parentnotwritable'] = 'Unable to create/move folder into selected parent folder. No access rights.'; -$messages['messagetoobig'] = 'The message part is too big to process it.'; -$messages['attachmentvalidationerror'] = 'WARNING! This attachment is suspicious because its type doesn\'t match the type declared in the message. If you do not trust the sender, you shouldn\'t open it in the browser because it may contain malicious contents.<br/><br/><em>Expected: $expected; found: $detected</em>'; -$messages['noscriptwarning'] = 'Warning: This webmail service requires Javascript! In order to use it please enable Javascript in your browser\'s settings.'; - -?> +$messages = array();
\ No newline at end of file diff --git a/program/localization/ga_IE/labels.inc b/program/localization/ga_IE/labels.inc index 9fffaf42a..9f0da6550 100755..100644 --- a/program/localization/ga_IE/labels.inc +++ b/program/localization/ga_IE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'DréachtaÃ'; $labels['sent'] = 'Amach'; $labels['trash'] = 'Bosca bruscair'; $labels['junk'] = 'DramhaÃl'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Ãbhair'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Comhbhrúigh'; $labels['empty'] = 'Folmhaigh'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Toilleadh diosca atá athláimhe'; $labels['unknown'] = 'gan aithne'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Athshocraigh an cuardach'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Taispeáin an foireann deireanach'; $labels['group'] = 'Group'; $labels['groups'] = 'GrúpaÃ'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Seoltaà Pearsanta'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ga_IE/messages.inc b/program/localization/ga_IE/messages.inc index b837c9d16..70aa28a36 100755..100644 --- a/program/localization/ga_IE/messages.inc +++ b/program/localization/ga_IE/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Scrios mé formáidithe as an teachtaireacht seo'; $messages['messageopenerror'] = 'Theip orm chun an teachtaireacht seo a tarrtháil as an freastalaÃ'; $messages['fileuploaderror'] = 'Theip an suas-luchtú'; $messages['filesizeerror'] = 'Beigh an comhad ró-mhor. Is ea $size uas-saghas chun admháil léite'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'D\'éirigh mé agus chuir mé $nr seolagh i do Leabhair SeoltaÃ'; +$messages['copyerror'] = 'Theip mé agus nÃor dfhag mé aon seolagh'; $messages['sourceisreadonly'] = 'Tá an foinse seolaigh seo inléite amháin'; $messages['errorsavingcontact'] = 'Theip mé, NÃl an cumas agam an seolagh seo a sábháil'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/gl_ES/labels.inc b/program/localization/gl_ES/labels.inc index c624c462e..5905ea4b9 100644 --- a/program/localization/gl_ES/labels.inc +++ b/program/localization/gl_ES/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Borradores'; $labels['sent'] = 'Enviados'; $labels['trash'] = 'Cubo do lixo'; $labels['junk'] = 'Correo lixo'; -$labels['show_real_foldernames'] = 'Amosar nomes reáis para cartafois especiáis'; // message listing $labels['subject'] = 'Asunto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Modo de vista da lista'; $labels['folderactions'] = 'Accións cos cartafoles'; $labels['compact'] = 'Compactar'; $labels['empty'] = 'Baleirar'; -$labels['importmessages'] = 'Importar mensaxes'; $labels['quota'] = 'Uso de disco'; $labels['unknown'] = 'descoñecido'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Restablecer a busca'; $labels['searchmod'] = 'Modificadores de busca'; $labels['msgtext'] = 'Mensaxe enteira'; $labels['body'] = 'Corpo'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Abrir nunha nova fiestra'; $labels['emlsave'] = 'Gardar (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Amosar o último grupo'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Enderezos persoais'; $labels['searchsave'] = 'Gardar procura'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Redactar mensaxes HTML'; $labels['htmlonreply'] = 'só cando se resposte a unha mensaxe HTML'; $labels['htmlonreplyandforward'] = 'ao reenviar ou respostar a unha mensaxe HTML'; $labels['htmlsignature'] = 'Sinatura HTML'; -$labels['showemail'] = 'Amosar enderezo de correo co nome en pantalla'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Amosar previsualización'; $labels['skin'] = 'Aspecto da interface'; $labels['logoutclear'] = 'Baleirar o cubo do lixo ao saÃr'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorar as palabras con números'; $labels['spellcheckignorecaps'] = 'Ignorar as palabras escritas en maiúsculas'; $labels['addtodict'] = 'Engadir ao diccionario'; $labels['mailtoprotohandler'] = 'Rexistrar o manexador de protocolo para as ligazóns "mailto:"'; -$labels['standardwindows'] = 'Manexar avisos emerxentes como xanelas estándar'; $labels['forwardmode'] = 'Reenvio de mensaxes'; $labels['inline'] = 'inserido'; $labels['asattachment'] = 'coma anexo'; diff --git a/program/localization/gl_ES/messages.inc b/program/localization/gl_ES/messages.inc index 8fc2cb424..207a016a1 100644 --- a/program/localization/gl_ES/messages.inc +++ b/program/localization/gl_ES/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'A importar. Por favor, agarde...'; $messages['importformaterror'] = 'Fallou a importación! O ficheiro cargado non contén datos válidos.'; $messages['importconfirm'] = '<b>Importáronse correctamente $inserted contactos. Ignoráronse $skipped contactos que xa existÃan</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Ignoráronse $skipped existing entradas</b>'; -$messages['importmessagesuccess'] = 'Importados $nr mensaxes con éxito'; -$messages['importmessageerror'] = 'Fallou a importación! O arquivo subido non é unha mensaxe válida ou un ficheiro de caixa de correo'; $messages['opnotpermitted'] = 'Operación non permitida!'; $messages['nofromaddress'] = 'Falta o enderezo de correo electrónico na identidade que escolleu.'; $messages['editorwarning'] = 'Se troca neste intre ao editor de texto plano, vai perder todo o formato do texto. Quere continuar?'; diff --git a/program/localization/he_IL/labels.inc b/program/localization/he_IL/labels.inc index 7ad04ab4a..bfb9e2fef 100644 --- a/program/localization/he_IL/labels.inc +++ b/program/localization/he_IL/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'טיוטות'; $labels['sent'] = '× ×©×œ×—'; $labels['trash'] = '×שפה'; $labels['junk'] = 'זבל'; -$labels['show_real_foldernames'] = 'הצגת שמות ××ž×™×ª×™×™× ×©×œ תיקיות מיוחדות'; // message listing $labels['subject'] = '× ×•×©×'; @@ -194,7 +193,6 @@ $labels['listmode'] = '×ופן הצגת רשימה'; $labels['folderactions'] = 'פעולות על תיקי×'; $labels['compact'] = '×¤×™× ×•×™ שטח ×œ× ×ž× ×•×¦×œ'; $labels['empty'] = 'ריקון'; -$labels['importmessages'] = '×™×™×‘×•× ×”×•×“×¢×•×ª'; $labels['quota'] = '× ×™×¦×•×œ קיבולת'; $labels['unknown'] = '×œ× ×™×“×•×¢'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = '× ×™×§×•×™ תיבת החיפוש'; $labels['searchmod'] = 'מ××¤×™×™× ×™ חיפוש'; $labels['msgtext'] = 'כל ההודעה'; $labels['body'] = 'גוף ההודעה'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'פתיחה בחלון חדש'; $labels['emlsave'] = 'הורדת הודעה בפורמט EML'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'הצגת הקבוצה ×”××—×¨×•× ×”'; $labels['group'] = 'קבוצה'; $labels['groups'] = 'קבוצות'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'כתובות פרטיות'; $labels['searchsave'] = 'שמירת החיפוש'; @@ -478,7 +474,6 @@ $labels['spellcheckignorenums'] = 'התעלמות ×ž×ž×™×œ×™× ×”×ž×›×™×œ×•×ª מ $labels['spellcheckignorecaps'] = 'התעלמות ×ž×ž×™×œ×™× ×¢× ×ותציות ר×שיות'; $labels['addtodict'] = 'הוספה למילון'; $labels['mailtoprotohandler'] = 'קביעת הפרוטוקול לטיפול בקישור מסוג mailto:links'; -$labels['standardwindows'] = '×—×œ×•× ×•×ª ×§×•×¤×¦×™× ×™×˜×•×¤×œ×• ×›×—×œ×•× ×•×ª רגילי×'; $labels['forwardmode'] = '×”×¤× ×™×ª הודעות'; $labels['inline'] = 'חלק מההודעה'; $labels['asattachment'] = 'כצרופה'; diff --git a/program/localization/he_IL/messages.inc b/program/localization/he_IL/messages.inc index 37ebcea01..7d9b87c06 100644 --- a/program/localization/he_IL/messages.inc +++ b/program/localization/he_IL/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'ייבו×, × × ×œ×”×ž×ª×™×Ÿ..'; $messages['importformaterror'] = '×”×™×‘×•× × ×›×©×œ ! הקובץ שהועלה ××™× ×• מת××™×.'; $messages['importconfirm'] = '<b>יוב×ו $inserted ×× ×©×™ קשר, $skipped היו ×§×™×™×ž×™× </b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b> דילוג של $skipped × ×ª×•× ×™× ×§×™×™×ž×™× <b>'; -$messages['importmessagesuccess'] = 'יוב×ו בהצלחה $nr הודעות '; -$messages['importmessageerror'] = '×”×™×‘×•× × ×›×©×œ ! הקובץ שהועלה ××™× ×• הודעה ×ו קובץ הודעות ×‘×ž×‘× ×” מת××™×'; $messages['opnotpermitted'] = 'פעולה ×סורה!'; $messages['nofromaddress'] = 'לזהות ×©× ×‘×—×¨×” חסרה כתובת דו×ר'; $messages['editorwarning'] = 'המעבר לעורך רגיל ×™×’×¨×•× ×œ×יבוד ×ת העריכה הקיימת. ×”×× ×œ×”×ž×©×™×š?'; diff --git a/program/localization/hi_IN/labels.inc b/program/localization/hi_IN/labels.inc index 303e0b5fb..3b8279f71 100644 --- a/program/localization/hi_IN/labels.inc +++ b/program/localization/hi_IN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'डà¥à¤°à¤¾à¤«à¤¼à¤Ÿ'; $labels['sent'] = 'à¤à¥‡à¤œà¤¾ गया'; $labels['trash'] = 'रदà¥à¤¦à¥€'; $labels['junk'] = 'सà¥à¤ªà¥ˆà¤®'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'विशय'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'छोटा करें'; $labels['empty'] = 'मेल रदà¥à¤¦à¥€ में डालें'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'डिसà¥à¤• उपयोग'; $labels['unknown'] = 'अजà¥à¤žà¤¾à¤¤'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'खोज खाली करें'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'आखिरी बनà¥à¤¡à¤² दिखाà¤à¤‚' $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/hi_IN/messages.inc b/program/localization/hi_IN/messages.inc index ffbc6f436..1d55f5c48 100644 --- a/program/localization/hi_IN/messages.inc +++ b/program/localization/hi_IN/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'मेल से फ़ॉरà¥à¤®à¥ˆà¤Ÿà¤¿à¤‚ग ठ$messages['messageopenerror'] = 'सरà¥à¤µà¤° से मेल लोड नहीं हो पाया'; $messages['fileuploaderror'] = 'फ़ाईल अपलोड नहीं हो पाया'; $messages['filesizeerror'] = 'अपलोड के लिये फ़ाईल हद $size से बड़ा है'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/hr_HR/labels.inc b/program/localization/hr_HR/labels.inc index 4578fed2b..506d50f1f 100644 --- a/program/localization/hr_HR/labels.inc +++ b/program/localization/hr_HR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'PredloÅ¡ci'; $labels['sent'] = 'Poslano'; $labels['trash'] = 'Smeće'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Naslov'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Model pregleda listi'; $labels['folderactions'] = 'Akcije mapa'; $labels['compact'] = 'Kompresiranje'; $labels['empty'] = 'Isprazni'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Kvota'; $labels['unknown'] = 'nepoznato'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Prikaži sve poruke'; $labels['searchmod'] = 'Postavke pretrage'; $labels['msgtext'] = 'Cijela poruka'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Otvori u novom prozoru'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Zadnja strana'; $labels['group'] = 'Grupa'; $labels['groups'] = 'Grupe'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Privatna adresa'; $labels['searchsave'] = 'Pohrani pretragu'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignoriraj rijeÄi koje sadrže brojeve'; $labels['spellcheckignorecaps'] = 'Ignoriraj rijeÄi sa sa svim velikim slovima'; $labels['addtodict'] = 'Dodaj u rjeÄnik'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/hr_HR/messages.inc b/program/localization/hr_HR/messages.inc index 0b96c97f2..3e6cc6daf 100644 --- a/program/localization/hr_HR/messages.inc +++ b/program/localization/hr_HR/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Formatiranje poruke'; $messages['messageopenerror'] = 'UÄitavanje poruke nije uspjelo'; $messages['fileuploaderror'] = 'Prijenos datoteke nije uspio'; $messages['filesizeerror'] = 'Datoteka je prevelika. Maksimalna veliÄina je $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'UspjeÅ¡no kopirano $n adresa'; +$messages['copyerror'] = 'Nije uspjelo kopiranje adresa'; $messages['sourceisreadonly'] = 'Ovaj resurs adresa je samo za Äitanje'; $messages['errorsavingcontact'] = 'Nije uspjelo spremanje adrese kontakta'; $messages['movingmessage'] = 'PremjeÅ¡tanje poruke...'; $messages['copyingmessage'] = 'Kopiranje poruke...'; $messages['copyingcontact'] = 'Kopiram kontakt(e)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Brisanje poruke...'; $messages['markingmessage'] = 'OznaÄavanje poruke...'; $messages['addingmember'] = 'Dodajem kontakt(e) u grupu...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Uvozim, molimo saÄekajte...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>UspjeÅ¡no je uvezeno $inserted kontakt(a), preskoÄeno $skipped već postojećih</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>PreskoÄeno $skipped postojećih unosa</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operacija nije dozvoljena!'; $messages['nofromaddress'] = 'Nije upisana e-mail adresa u odabrani identitet'; $messages['editorwarning'] = 'Prebacivanje u Äisti tekstualni ureÄ‘ivaÄ Ä‡e prouzrokovati gubljenje formatiranje teksta. Želite li nastaviti?'; diff --git a/program/localization/hu_HU/labels.inc b/program/localization/hu_HU/labels.inc index abdc7e891..3cc5da1aa 100644 --- a/program/localization/hu_HU/labels.inc +++ b/program/localization/hu_HU/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Piszkozatok'; $labels['sent'] = 'Küldött levelek'; $labels['trash'] = 'Törölt elemek'; $labels['junk'] = 'Kéretlen levelek'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Tárgy'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'MegjelenÃtési mód'; $labels['folderactions'] = 'Mappaműveletek...'; $labels['compact'] = 'TömörÃtés'; $labels['empty'] = 'KiürÃtés'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Helyfoglalás'; $labels['unknown'] = 'ismeretlen'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Alapállapot'; $labels['searchmod'] = 'Keresési opciók'; $labels['msgtext'] = 'Teljes üzenet'; $labels['body'] = 'Törzs'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Megnyitás új ablakban'; $labels['emlsave'] = 'Letöltés (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Utolsó oldal'; $labels['group'] = 'Csoport'; $labels['groups'] = 'Csoportok'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Személyes cÃmjegyzék'; $labels['searchsave'] = 'Keresés mentése'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Számot tartalmazó szavak kihagyása'; $labels['spellcheckignorecaps'] = 'Csak nagybetűt tartalmazó szavak kihagyása'; $labels['addtodict'] = 'Hozzáadás a szótárhoz'; $labels['mailtoprotohandler'] = 'BeállÃtás a mailto: linkek kezelÅ‘jeként'; -$labels['standardwindows'] = 'A felugró ablakok használata szokásos ablakként'; $labels['forwardmode'] = 'Ãœzenet továbbÃtás'; $labels['inline'] = 'beágyazott'; $labels['asattachment'] = 'csatolmányként'; diff --git a/program/localization/hu_HU/messages.inc b/program/localization/hu_HU/messages.inc index d54589f42..6528602a4 100644 --- a/program/localization/hu_HU/messages.inc +++ b/program/localization/hu_HU/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Formázás eltávolÃtása az üzenetbÅ‘l...'; $messages['messageopenerror'] = 'A levelek a szerverrÅ‘l nem tölthetÅ‘k le'; $messages['fileuploaderror'] = 'Feltöltés sikertelen'; $messages['filesizeerror'] = 'A feltöltött fájl mérete meghaladja a maximális $size méretet'; -$messages['copysuccess'] = 'Sikeresen átmásolva $nr kapcsolat.'; -$messages['movesuccess'] = 'Sikeresen átmozgatva $nr kapcsolat.'; -$messages['copyerror'] = 'Nem lehet másolni a kapcsolatokat.'; -$messages['moveerror'] = 'Nem lehet átmozgatni a kapcsolatokat.'; +$messages['copysuccess'] = '$nr cÃm sikeresen másolva'; +$messages['copyerror'] = 'Egyetlen cÃm sem másolható'; $messages['sourceisreadonly'] = 'Ez a cÃmforrás csak olvasható'; $messages['errorsavingcontact'] = 'A kapcsolat cÃme nem menthetÅ‘'; $messages['movingmessage'] = 'Ãœzenet(ek) mozgatása...'; $messages['copyingmessage'] = 'Ãœzenet(ek) másolása...'; $messages['copyingcontact'] = 'Kapcsolat(ok) másolása...'; -$messages['movingcontact'] = 'Kapcsolat(ok) átmozgatása ...'; $messages['deletingmessage'] = 'Ãœzenet(ek) törlése....'; $messages['markingmessage'] = 'Ãœzenet(ek) megjelölése...'; $messages['addingmember'] = 'Kapcsolat(ok) hozzáadása a csoporthoz...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importálás folyamatban, kérem várjon...'; $messages['importformaterror'] = 'Az importálás sikertelen! A feltöltött fájl ismeretlen formátumú.'; $messages['importconfirm'] = '<b>Sikeresen importálásra került $inserted kapcsolat, kihagyva $skipped már létezÅ‘ bejegyzés</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Kihagyva $skipped már létezÅ‘ bejegyzés</b>'; -$messages['importmessagesuccess'] = 'Sikeresen importálva $nr üzenet'; -$messages['importmessageerror'] = 'Sikertelen az importálás. A feltÅ‘ltött file nem értelmezhetÅ‘ üzenetként vagy postafiók (mailbox) fileként.'; $messages['opnotpermitted'] = 'A művelet nem megengedett!'; $messages['nofromaddress'] = 'A kiválasztott azonosÃtónál nincs email beállÃtva.'; $messages['editorwarning'] = 'Az egyszerű szöveges formátumra való váltás az összes formázás elvesztésével jár. Biztosan folytatja?'; diff --git a/program/localization/hy_AM/labels.inc b/program/localization/hy_AM/labels.inc index 8ee9316c4..99cee4ab9 100644 --- a/program/localization/hy_AM/labels.inc +++ b/program/localization/hy_AM/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'ÕÖ‡Õ¡Õ£Ö€Õ¥Ö€'; $labels['sent'] = 'ÕˆÖ‚Õ²Õ¡Ö€Õ¯Õ¾Õ¡Õ®'; $labels['trash'] = 'Ô±Õ²Õ¢Õ¡Ö€Õ¯Õ²'; $labels['junk'] = 'Ô¹Õ¡ÖƒÕ¸Õ¶'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ÕŽÕ¥Ö€Õ¶Õ¡Õ£Õ«Ö€'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Õ‘Õ¸Ö‚ÖÕ¡Õ¯Õ¸Õ¾ Õ¿Õ¥Õ½Ö„Õ« Õ¿Õ¡Ö€Õ¢Õ¥Ö€Õ¡Õ¯Õ¨'; $labels['folderactions'] = 'ÕŠÕ¡Õ¶Õ¡Õ¯Õ« գործողություններ…'; $labels['compact'] = 'ÕÕ¥Õ²Õ´Õ¥Õ¬'; $labels['empty'] = 'Ô´Õ¡Õ¿Õ¡Ö€Õ¯Õ¥Õ¬'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Ô´Õ«Õ½Õ¯Õ¡ÕµÕ«Õ¶ Õ¿Õ¡Ö€Õ¡Õ®Ö„'; $labels['unknown'] = 'Õ¡Õ¶Õ°Õ¡ÕµÕ¿'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ÕŽÕ¥Ö€Õ½Õ¯Õ½Õ¥Õ¬ Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¨'; $labels['searchmod'] = 'ÕˆÖ€Õ¸Õ¶Õ´Õ¡Õ¶ ÖƒÕ¸ÖƒÕ¸ÕÕ«Õ¹Õ¶Õ¥Ö€'; $labels['msgtext'] = 'ÕˆÕ²Õ» Õ°Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Ô²Õ¡ÖÕ¥Õ¬ Õ¶Õ¸Ö€ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¸Ö‚Õ´'; $labels['emlsave'] = 'Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬ (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¾Õ¥Ö€Õ»Õ«Õ¶ Õ§Õ»Õ¨'; $labels['group'] = 'Ô½Õ¸Ö‚Õ´Õ¢'; $labels['groups'] = 'Ô½Õ´Õ¢Õ¥Ö€'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Ô±Õ¶Õ±Õ¶Õ¡Õ¯Õ¡Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€'; $labels['searchsave'] = 'ÕŠÕ¡Õ°ÕºÕ¡Õ¶Õ¥Õ¬ Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¨'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ô±Õ¶Õ¿Õ¥Õ½Õ¥Õ¬ Õ©Õ¾Õ¥Ö€Õ¸Õ¾ Õ¢Õ¡Õ¼Õ¥Ö€Õ¨'; $labels['spellcheckignorecaps'] = 'Ô±Õ¶Õ¿Õ¥Õ½Õ¥Õ¬ Õ¬Ö€Õ«Õ¾ Õ´Õ¥Õ®Õ¡Õ¿Õ¡Õ¼ Õ¢Õ¡Õ¼Õ¥Ö€Õ¨'; $labels['addtodict'] = 'Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ¢Õ¡Õ¼Õ¡Ö€Õ¡Õ¶Õ¸Ö‚Õ´'; $labels['mailtoprotohandler'] = 'mailto: Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ½ÕºÕ¡Õ½Õ¡Ö€Õ¯Õ¸Õ²'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/hy_AM/messages.inc b/program/localization/hy_AM/messages.inc index 2128a188c..6b3f4ebe9 100644 --- a/program/localization/hy_AM/messages.inc +++ b/program/localization/hy_AM/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Õ†Õ¡Õ´Õ¡Õ¯Õ« Õ±Ö‡Õ¡Õ¾Õ¸Ö€Õ´Õ¡Õ¶ Õ°Õ¥Õ¼Õ¡Öում…'; $messages['messageopenerror'] = 'Õ†Õ¡Õ´Õ¡Õ¯Õ« Õ¢Õ¥Õ¼Õ¶Õ¾Õ¸Ö‚Õ´Õ¨ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ«Ö Õ±Õ¡ÕÕ¸Õ²Õ¾Õ¥Ö'; $messages['fileuploaderror'] = 'Õ–Õ¡ÕµÕ¬Õ« Õ¯ÖÕ¸Ö‚Õ´Õ¶ Õ±Õ¡ÕÕ¸Õ²Õ¾Õ¥Ö'; $messages['filesizeerror'] = 'Õ–Õ¡ÕµÕ¬Õ« Õ¹Õ¡ÖƒÕ¨ Õ£Õ¥Ö€Õ¡Õ¦Õ¡Õ¶ÖÕ¸Ö‚Õ´ Õ§ Õ´Õ¡Ö„Õ½Õ«Õ´Õ¡Õ¬Õ¨Õ $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ« Õ¯Ö€Õ¯Õ¶Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ¸Ö‚Õ´Õ¨ Õ¡Õ¾Õ¡Ö€Õ¿Õ¾Õ¡Õ® Õ§'; +$messages['copyerror'] = 'Õ€Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ« Õ¯Ö€Õ¯Õ¶Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ¸Ö‚Õ´Õ¨ Õ±Õ¡ÕÕ¸Õ²Õ¾Õ¥Ö'; $messages['sourceisreadonly'] = 'Ô±ÕµÕ½ Õ°Õ¡Õ½ÖÕ¥Õ¶ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ§'; $messages['errorsavingcontact'] = 'Õ€Õ¡Õ½ÖÕ¥Õ« Õ£Ö€Õ¡Õ¶ÖÕ¸Ö‚Õ´Õ¶ Õ±Õ¡ÕÕ¸Õ²Õ¾Õ¥Ö'; $messages['movingmessage'] = 'Õ†Õ¡Õ´Õ¡Õ¯Õ¨ Õ¿Õ¥Õ²Õ¡ÖƒÕ¸ÕÕ¾Õ¸Ö‚Õ´ է…'; $messages['copyingmessage'] = 'Õ€Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« պատճենում…'; $messages['copyingcontact'] = 'Ô±Õ¶Õ±Õ¡Õ¶Ö ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¸Ö‚Õ´â€¦'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Õ€Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ջնջում…'; $messages['markingmessage'] = 'Õ€Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« նշում…'; $messages['addingmember'] = 'Ô±Õ¶Õ±Õ¡Õ¶Ö Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¸Ö‚Õ´ Õմբին…'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Õ†Õ¥Ö€Õ¯Ö€Õ¸Ö‚Õ´Õ¶ Õ¨Õ¶Õ©Õ¡ÖÖ„Õ« Õ´Õ¥Õ» Õ§...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '$inserted Õ¶Õ¸Ö€ Õ¶Õ¥Ö€Õ¯Ö€Õ¾Õ¡Õ® Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€, $skipped Õ¡Ö€Õ¤Õ¥Õ¶ Õ¡Õ¼Õ¯Õ¡ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ <p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Ô²Õ¡Ö Õ©Õ¸Õ²Õ¶Õ¾Õ¥Ö $skipped Õ¡Õ¼Õ¯Õ¡ Õ£Ö€Õ¡Õ¼Õ¸Ö‚Õ´</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Ô³Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¡Õ¶Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ« Õ§Ö‰'; $messages['nofromaddress'] = 'Õ†Õ·Õ¾Õ¡Õ® Õ¡Õ¶Õ±Õ¨ Õ°Õ¡Õ½ÖÕ¥ Õ¹Õ¸Ö‚Õ¶Õ«Ö‰'; $messages['editorwarning'] = 'Ô´Õ¥ÕºÕ« ÕºÕ¡Ö€Õ¦ Õ¿Õ¥Ö„Õ½Õ¿Õ« ÕÕ´Õ¢Õ¡Õ£Ö€Õ«Õ¹ Õ¡Õ¶ÖÕ´Õ¡Õ¶ Õ¤Õ¥ÕºÖ„Õ¸Ö‚Õ´ Õ¯Õ¯Õ¸Ö€Õ« Õ¿Õ¥Ö„Õ½Õ¿Õ« Õ±Ö‡Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¨Ö‰ Õ‡Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¥ÕžÕ¬Ö‰'; diff --git a/program/localization/ia/labels.inc b/program/localization/ia/labels.inc index 1cd614d35..2a9501168 100644 --- a/program/localization/ia/labels.inc +++ b/program/localization/ia/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drafts'; $labels['sent'] = 'Inviate'; $labels['trash'] = 'Trash'; $labels['junk'] = 'Junk'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Subjecto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Actiones de dossier...'; $labels['compact'] = 'Compacte'; $labels['empty'] = 'Vacue'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'incognite'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reinitialisar cerca'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Message complete'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Aperir in nove fenestra'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'Gruppo'; $labels['groups'] = 'Gruppos'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Adresses personal'; $labels['searchsave'] = 'Salveguardar cerca'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Adder al dictionario'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ia/messages.inc b/program/localization/ia/messages.inc index d6fbba87d..ebc6953d2 100644 --- a/program/localization/ia/messages.inc +++ b/program/localization/ia/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'Incargamento de file falleva.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/id_ID/labels.inc b/program/localization/id_ID/labels.inc index a8d5f4c5b..eea3132cd 100644 --- a/program/localization/id_ID/labels.inc +++ b/program/localization/id_ID/labels.inc @@ -33,11 +33,10 @@ $labels['addressbook'] = 'Buku Alamat'; // mailbox names $labels['inbox'] = 'Kotak Masuk'; -$labels['drafts'] = 'Konsep'; +$labels['drafts'] = 'Daftar tunggu'; $labels['sent'] = 'Terkirim'; $labels['trash'] = 'Surat Terhapus'; $labels['junk'] = 'Sampah'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Judul'; @@ -65,7 +64,7 @@ $labels['copy'] = 'Salin'; $labels['move'] = 'Pindahkan'; $labels['moveto'] = 'Pindahkan ke...'; $labels['download'] = 'Unduh'; -$labels['open'] = 'Buka'; +$labels['open'] = 'Open'; $labels['showattachment'] = 'Tampilkan'; $labels['showanyway'] = 'Tampilkan saja'; @@ -163,7 +162,7 @@ $labels['currpage'] = 'Halaman sekarang'; $labels['unread'] = 'Belum terbaca'; $labels['flagged'] = 'Ditandai'; $labels['unanswered'] = 'Belum terjawab'; -$labels['withattachment'] = 'Dengan lampiran'; +$labels['withattachment'] = 'With attachment'; $labels['deleted'] = 'Terhapus'; $labels['undeleted'] = 'Tidak terhapus'; $labels['invert'] = 'Sebaliknya'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Perlihatkan mode tinjauan'; $labels['folderactions'] = 'Tindakan pada folder...'; $labels['compact'] = 'Rampingkan'; $labels['empty'] = 'Kosong'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Penggunaan ruang'; $labels['unknown'] = 'Tidak dikenal'; @@ -205,13 +203,11 @@ $labels['resetsearch'] = 'Atur ulang pencarian'; $labels['searchmod'] = 'Peubah pencarian'; $labels['msgtext'] = 'Seluruh pesan'; $labels['body'] = 'Badan'; -$labels['type'] = 'Tipe'; -$labels['namex'] = 'Nama'; $labels['openinextwin'] = 'Buka dalam jendela baru'; $labels['emlsave'] = 'Unduh (.eml)'; -$labels['changeformattext'] = 'Tampilkan dalam format text biasa'; -$labels['changeformathtml'] = 'Tampilkan dalam format HTML'; +$labels['changeformattext'] = 'Display in plain text format'; +$labels['changeformathtml'] = 'Display in HTML format'; // message compose $labels['editasnew'] = 'Sunting sebagai pesan baru'; @@ -358,7 +354,6 @@ $labels['lastpage'] = 'Perlihatkan himpunan terakhir'; $labels['group'] = 'Kelompok'; $labels['groups'] = 'Kelompok'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Alamat pribadi'; $labels['searchsave'] = 'Simpan pencarian'; @@ -430,7 +425,7 @@ $labels['showremoteimages'] = 'Tampilkan remote inline images'; $labels['fromknownsenders'] = 'dari pengirim yang dikenal'; $labels['always'] = 'selalu'; $labels['showinlineimages'] = 'Tampilkan gambar terlampir dibawah pesan'; -$labels['autosavedraft'] = 'Otomatis menyimpan konsep'; +$labels['autosavedraft'] = 'Otomatis menyimpan pesan tertunda'; $labels['everynminutes'] = 'setiap $n menit'; $labels['refreshinterval'] = 'Refresh (memeriksa pesan baru, dsb)'; $labels['never'] = 'tidak pernah'; @@ -477,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Abaikan kata-kata yang bernomor'; $labels['spellcheckignorecaps'] = 'Abaikan kata-kata dengan huruf besar semua'; $labels['addtodict'] = 'Tambahkan ke kamus'; $labels['mailtoprotohandler'] = 'Daftarkan pengampu protokol untuk link mailto:'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Meneruskan pesan'; $labels['inline'] = 'dalam surat'; $labels['asattachment'] = 'sebagai sisipan'; diff --git a/program/localization/id_ID/messages.inc b/program/localization/id_ID/messages.inc index a81b2ab01..04d8242ad 100644 --- a/program/localization/id_ID/messages.inc +++ b/program/localization/id_ID/messages.inc @@ -44,7 +44,7 @@ $messages['checkingmail'] = 'Memeriksa pesan baru...'; $messages['sendingmessage'] = 'Mengirim pesan...'; $messages['messagesent'] = 'Pesan berhasil dikirim.'; $messages['savingmessage'] = 'Menyimpan pesan...'; -$messages['messagesaved'] = 'Pesan tersimpan kedalam Konsep'; +$messages['messagesaved'] = 'Menyimpan pesan ke daftar tunggu'; $messages['successfullysaved'] = 'Berhasil disimpan'; $messages['addedsuccessfully'] = 'Kontak berhasil ditambahkan ke buku alamat'; $messages['contactexists'] = 'Kontak dengan alamat e-mail ini sudah ada.'; @@ -101,16 +101,13 @@ $messages['converting'] = 'Mengembalikan pesan ke format awal...'; $messages['messageopenerror'] = 'Tidak dapat mengambil pesan dari server'; $messages['fileuploaderror'] = 'Gagal mengunggah berkas'; $messages['filesizeerror'] = 'Berkas terunggah mencapai ukuran maksimal dari $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Berhasil menyalin $nr alamat'; +$messages['copyerror'] = 'Tidak bisa menyalin alamat manapun'; $messages['sourceisreadonly'] = 'Sumber dari alamat ini hanya dapat dibaca'; $messages['errorsavingcontact'] = 'Tidak bisa menyimpan alamat kontak'; $messages['movingmessage'] = 'Memindahkan pesan...'; $messages['copyingmessage'] = 'Menyalin pesan...'; $messages['copyingcontact'] = 'Menyalin kontak...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Menghapus pesan...'; $messages['markingmessage'] = 'Menandai Pesan...'; $messages['addingmember'] = 'Menambahkan kontak ke grup...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Sedang mengimpor, harap menunggu...'; $messages['importformaterror'] = 'Proses import gagal. File yang di upload bukan file import yang valid.'; $messages['importconfirm'] = '<b>Berhasil mengimpor $inserted kontak</b>'; $messages['importconfirmskipped'] = '<b>$skipped entri yang sudah ada dilewatkan</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operasi tidak diperbolehkan!'; $messages['nofromaddress'] = 'kekurangan alamat e-mail pada identitas terpilih'; $messages['editorwarning'] = 'Beralih pada editor teks murni akan mengakibatkan semua pemformatan teks hilang. Lanjutkan?'; diff --git a/program/localization/index.inc b/program/localization/index.inc index 4b848dc49..bfb770cac 100644 --- a/program/localization/index.inc +++ b/program/localization/index.inc @@ -70,7 +70,6 @@ $rcube_languages = array( 'ku' => 'Kurdish (Kurmancî)', 'lv_LV' => 'Latvian (LatvieÅ¡u)', 'lt_LT' => 'Lithuanian (LietuviÅ¡kai)', - 'lb_LU' => 'Luxembourgish (Lëtzebuergesch)', 'mk_MK' => 'Macedonian (МакедонÑки)', 'ms_MY' => 'Malay (Bahasa Melayu)', 'ml_IN' => 'Malayalam (മലയാളം)', @@ -134,7 +133,6 @@ $rcube_language_aliases = array( 'kh' => 'km_KH', 'kh_KH' => 'km_KH', 'km' => 'km_KH', - 'lb' => 'lb_LU', 'ne' => 'ne_NP', 'no' => 'nn_NO', 'ms' => 'ms_MY', diff --git a/program/localization/is_IS/labels.inc b/program/localization/is_IS/labels.inc index c2859ce75..80443dd3a 100644 --- a/program/localization/is_IS/labels.inc +++ b/program/localization/is_IS/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drög'; $labels['sent'] = 'Sent'; $labels['trash'] = 'Rusl'; $labels['junk'] = 'Ruslpóstur'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Titill'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Listayfirlit'; $labels['folderactions'] = 'Möppuaðgerðir...'; $labels['compact'] = 'Pakka'; $labels['empty'] = 'Tæma'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Gagnamagn'; $labels['unknown'] = 'óþekkt'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Tæma leit'; $labels['searchmod'] = 'Leitarskilyrði'; $labels['msgtext'] = 'Allt skeytið'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Opna à nýjum glugga'; $labels['emlsave'] = 'Niðurhlaða (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Sýna sÃðustu sÃðu'; $labels['group'] = 'Hópur'; $labels['groups'] = 'Hópar'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Persónuleg heimilisföng'; $labels['searchsave'] = 'Vista leit'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Hunsa orð með tölum'; $labels['spellcheckignorecaps'] = 'Hunsa orð sem eru à hástöfum'; $labels['addtodict'] = 'Bæta við orðalista'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/is_IS/messages.inc b/program/localization/is_IS/messages.inc index 731a19791..6e9f35af3 100644 --- a/program/localization/is_IS/messages.inc +++ b/program/localization/is_IS/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/it_IT/labels.inc b/program/localization/it_IT/labels.inc index 55cd432f7..75a24c5fd 100644 --- a/program/localization/it_IT/labels.inc +++ b/program/localization/it_IT/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Bozze'; $labels['sent'] = 'Inviata'; $labels['trash'] = 'Cestino'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Oggetto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Modalità di visualizzazione'; $labels['folderactions'] = 'Operazioni cartella'; $labels['compact'] = 'Compatta'; $labels['empty'] = 'Svuota'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Spazio utilizzato'; $labels['unknown'] = 'sconosciuto'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Annulla ricerca'; $labels['searchmod'] = 'Ambito di ricerca'; $labels['msgtext'] = 'Intero messaggio'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Apri in una nuova finestra'; $labels['emlsave'] = 'Scarica (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Ultima pagina'; $labels['group'] = 'Gruppo'; $labels['groups'] = 'Gruppi'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Rubrica Personale'; $labels['searchsave'] = 'Salva ricerca'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignora le parole contenenti numeri'; $labels['spellcheckignorecaps'] = 'Ignora le parole con tutte le lettere maiuscole'; $labels['addtodict'] = 'Aggiungi al dizionario'; $labels['mailtoprotohandler'] = 'Registra gestore per mailto:'; -$labels['standardwindows'] = 'Gestisci i popup come finestre standard'; $labels['forwardmode'] = 'Inoltro messaggi'; $labels['inline'] = 'In linea'; $labels['asattachment'] = 'come allegato'; diff --git a/program/localization/it_IT/messages.inc b/program/localization/it_IT/messages.inc index 502ecba25..80395b551 100644 --- a/program/localization/it_IT/messages.inc +++ b/program/localization/it_IT/messages.inc @@ -17,7 +17,7 @@ */ $messages = array(); -$messages['errortitle'] = 'Si è verificato un errore!'; +$messages['errortitle'] = 'C\'è stato qualche errore'; $messages['loginfailed'] = 'Impossibile accedere. Utente o password non corretti'; $messages['cookiesdisabled'] = 'Il tuo browser non accetta i cookies'; $messages['sessionerror'] = 'Sessione non valida o scaduta'; @@ -101,16 +101,13 @@ $messages['converting'] = 'Rimozione della formattazione dal messaggio...'; $messages['messageopenerror'] = 'Impossibile caricare il messaggio dal server'; $messages['fileuploaderror'] = 'Errore durante il caricamento del file'; $messages['filesizeerror'] = 'Il file da caricare supera il limite massimo di $size'; -$messages['copysuccess'] = 'Copiati correttamente $nr contatti.'; -$messages['movesuccess'] = '$nr contatti spostati correttamente.'; -$messages['copyerror'] = 'Impossibile copiare i contatti.'; -$messages['moveerror'] = 'Impossibile spostare i contatti.'; +$messages['copysuccess'] = 'Copiati $nr indirizzi'; +$messages['copyerror'] = 'Impossibile copiare gli indirizzi'; $messages['sourceisreadonly'] = 'La rubrica è in sola lettura'; $messages['errorsavingcontact'] = 'Impossibile salvare il contatto'; $messages['movingmessage'] = 'Spostamento del messaggio...'; $messages['copyingmessage'] = 'Copia del messaggio...'; $messages['copyingcontact'] = 'Copia del contatto...'; -$messages['movingcontact'] = 'Spostamento contatto(i)'; $messages['deletingmessage'] = 'Cancellazione messaggio...'; $messages['markingmessage'] = 'Marca messaggio...'; $messages['addingmember'] = 'Aggiunta contatto al gruppo...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importazione in corso, attendere...'; $messages['importformaterror'] = 'Importazione fallita! Il file caricato non è un file valido per l\'importazione.'; $messages['importconfirm'] = '<b>$inserted contatti importati con successo</p>'; $messages['importconfirmskipped'] = '<b>$skipped ignorati perché esistono già </b>'; -$messages['importmessagesuccess'] = 'Importati correttamente $nr messaggi'; -$messages['importmessageerror'] = 'Importazione fallita! Il file caricato non è un messaggio o una casella postale valida.'; $messages['opnotpermitted'] = 'Operazione non consentita!'; $messages['nofromaddress'] = 'Indirizzo e-mail mancante nell\'identità selezionata'; $messages['editorwarning'] = 'Passare all\'editor testuale farà perdere tutte le informazioni di formattazione. Sicuro di voler continuare?'; diff --git a/program/localization/ja_JP/labels.inc b/program/localization/ja_JP/labels.inc index 767aff23a..6998f0623 100644 --- a/program/localization/ja_JP/labels.inc +++ b/program/localization/ja_JP/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = '下書ã'; $labels['sent'] = 'é€ä¿¡æ¸ˆã¿'; $labels['trash'] = 'ã”ã¿ç®±'; $labels['junk'] = '迷惑メール'; -$labels['show_real_foldernames'] = '特殊フォルダーã®å®Ÿéš›ã®åå‰ã‚’表示'; // message listing $labels['subject'] = '件å'; @@ -194,7 +193,6 @@ $labels['listmode'] = '一覧表示モード'; $labels['folderactions'] = 'フォルダーã®æ“作...'; $labels['compact'] = '圧縮'; $labels['empty'] = '空'; -$labels['importmessages'] = 'メッセージをインãƒãƒ¼ãƒˆ'; $labels['quota'] = 'ディスクã®ä½¿ç”¨çŠ¶æ³'; $labels['unknown'] = 'ä¸æ˜Ž'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = '検索を解除'; $labels['searchmod'] = '検索ã®æ¡ä»¶'; $labels['msgtext'] = 'メッセージ全体'; $labels['body'] = '本文'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'æ–°ã—ã„ウィンドウã§é–‹ã'; $labels['emlsave'] = 'ダウンãƒãƒ¼ãƒ‰(.emlå½¢å¼)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = '最後ã®ãƒšãƒ¼ã‚¸ã‚’表示'; $labels['group'] = 'グループ'; $labels['groups'] = 'グループ'; -$labels['listgroup'] = 'グループã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’一覧'; $labels['personaladrbook'] = '個人ã®ä½æ‰€'; $labels['searchsave'] = 'æ¤œç´¢æƒ…å ±ã‚’ä¿å˜'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'æ•°å—ã‚’å«ã‚€å˜èªžã‚’無視'; $labels['spellcheckignorecaps'] = 'ã™ã¹ã¦å¤§æ–‡å—ã®å˜èªžã‚’無視'; $labels['addtodict'] = '辞書ã«è¿½åŠ '; $labels['mailtoprotohandler'] = 'mailto: ã®ãƒªãƒ³ã‚¯ã‚’扱ã†ãƒ—ãƒãƒˆã‚³ãƒ«å‡¦ç†ã®ç™»éŒ²'; -$labels['standardwindows'] = 'ãƒãƒƒãƒ—アップを通常ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¨ã—ã¦å‡¦ç†'; $labels['forwardmode'] = 'メッセージã®è»¢é€å½¢å¼'; $labels['inline'] = 'インライン'; $labels['asattachment'] = '添付ファイル'; diff --git a/program/localization/ja_JP/messages.inc b/program/localization/ja_JP/messages.inc index 820b52d96..f4dd0fceb 100644 --- a/program/localization/ja_JP/messages.inc +++ b/program/localization/ja_JP/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'メールã‹ã‚‰æ›¸å¼ã‚’削除ä¸...'; $messages['messageopenerror'] = 'サーãƒãƒ¼ã‹ã‚‰ãƒ¡ãƒ¼ãƒ«ã‚’èªã¿è¾¼ã‚ã¾ã›ã‚“。'; $messages['fileuploaderror'] = 'ファイルをアップãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚'; $messages['filesizeerror'] = 'アップãƒãƒ¼ãƒ‰ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã®ã‚µã‚¤ã‚ºãŒä¸Šé™($size)を超ãˆã¾ã—ãŸã€‚'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr件ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’コピーã—ã¾ã—ãŸã€‚'; +$messages['copyerror'] = 'ã©ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚‚コピーã§ãã¾ã›ã‚“ã§ã—ãŸã€‚'; $messages['sourceisreadonly'] = 'ã“ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚½ãƒ¼ã‚¹ã¯èªã¿è¾¼ã¿å°‚用ã§ã™ã€‚'; $messages['errorsavingcontact'] = '連絡先ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’ä¿å˜ã§ãã¾ã›ã‚“。'; $messages['movingmessage'] = 'メッセージを移動ä¸...'; $messages['copyingmessage'] = 'メッセージをコピーä¸...'; $messages['copyingcontact'] = '連絡先をコピーä¸...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'メッセージを削除ä¸...'; $messages['markingmessage'] = 'メッセージã«ãƒžãƒ¼ã‚¯ã‚’è¨å®šä¸...'; $messages['addingmember'] = 'グループã«é€£çµ¡å…ˆã‚’コピーä¸...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'インãƒãƒ¼ãƒˆä¸ã§ã™ã€‚ã—ã°ã‚‰ããŠå¾…ã¡ãã $messages['importformaterror'] = 'インãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸ! アップãƒãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã¯æ£ã—ã„データをインãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã§ã¯ã‚ã‚Šã¾ã›ã‚“。'; $messages['importconfirm'] = '<b>$inserted件ã®é€£çµ¡å…ˆã‚’インãƒãƒ¼ãƒˆã—ã¾ã—ãŸã€‚</b>'; $messages['importconfirmskipped'] = '<b>$skipped件ã®æ—¢å˜ã™ã‚‹é …目を飛ã°ã—ãŸã€‚</b>'; -$messages['importmessagesuccess'] = '$nr件ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’インãƒãƒ¼ãƒˆã—ã¾ã—ãŸã€‚'; -$messages['importmessageerror'] = 'インãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸ! アップãƒãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã¯æœ‰åŠ¹ãªãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚„メールボックスã®ãƒ•ã‚¡ã‚¤ãƒ«ã§ã¯ã‚ã‚Šã¾ã›ã‚“。'; $messages['opnotpermitted'] = '許å¯ã•ã‚Œã¦ã„ãªã„æ“作ã§ã™ã€‚'; $messages['nofromaddress'] = 'é¸æŠžã—ã¦ã„ã‚‹è˜åˆ¥æƒ…å ±ã«é›»åメールアドレスãŒæŠœã‘ã¦ã„ã¾ã™ã€‚'; $messages['editorwarning'] = 'テã‚ストエディターã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã¨ã€ã™ã¹ã¦ã®æ›¸å¼ã¯ãªããªã‚Šã¾ã™ã€‚本当ã«ç¶šã‘ã¾ã™ã‹?'; diff --git a/program/localization/ka_GE/labels.inc b/program/localization/ka_GE/labels.inc index b0126c44e..3ab3b6e63 100755..100644 --- a/program/localization/ka_GE/labels.inc +++ b/program/localization/ka_GE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'დრáƒáƒ”ბითი'; $labels['sent'] = 'გáƒáƒ’ზáƒáƒ•áƒœáƒ˜áƒšáƒ˜'; $labels['trash'] = 'წáƒáƒ¨áƒšáƒ˜áƒšáƒ˜'; $labels['junk'] = 'სპáƒáƒ›áƒ˜'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'სáƒáƒ—áƒáƒ£áƒ ი'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'შეკუმშვáƒ'; $labels['empty'] = 'გáƒáƒªáƒáƒ იელებáƒ'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'შეზღუდვáƒ'; $labels['unknown'] = 'უცნáƒáƒ‘ი'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ძიების გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”ბáƒ' $labels['searchmod'] = 'ძებნის ვáƒáƒ იáƒáƒœáƒ¢áƒ”ბი'; $labels['msgtext'] = 'ყველრშეტყáƒáƒ‘ინებáƒ'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'გáƒáƒ®áƒ¡áƒœáƒ áƒáƒ®áƒáƒš ფáƒáƒœáƒ¯áƒáƒ áƒáƒ¨áƒ˜'; $labels['emlsave'] = 'გáƒáƒ“მáƒáƒ¬áƒ”რრ(.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'ბáƒáƒšáƒáƒ¡ ჩვენებáƒ'; $labels['group'] = 'ჯგუფი'; $labels['groups'] = 'ჯგუფები'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'პერსáƒáƒœáƒáƒšáƒ£áƒ ი მისáƒáƒ›áƒáƒ თები'; $labels['searchsave'] = 'ძებნის შენáƒáƒ®áƒ•áƒ'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'ლექსიკáƒáƒœáƒ¨áƒ˜ დáƒáƒ›áƒáƒ¢áƒ”ბáƒ'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ka_GE/messages.inc b/program/localization/ka_GE/messages.inc index c0cdd98f0..754343fac 100755..100644 --- a/program/localization/ka_GE/messages.inc +++ b/program/localization/ka_GE/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'შეტყáƒáƒ‘ინების ფáƒáƒ მáƒá $messages['messageopenerror'] = 'შეტყáƒáƒ‘ინებრვერჩáƒáƒ˜áƒ¢áƒ•áƒ˜áƒ თრსერვერიდáƒáƒœ'; $messages['fileuploaderror'] = 'ფáƒáƒ˜áƒšáƒ˜ ვერáƒáƒ˜áƒ¢áƒ•áƒ˜áƒ თáƒ'; $messages['filesizeerror'] = 'áƒáƒ¢áƒ•áƒ˜áƒ თული ფáƒáƒ˜áƒšáƒ˜áƒ¡ ზáƒáƒ›áƒ მეტირდáƒáƒ¡áƒáƒ¨áƒ•áƒ”ბ ფáƒáƒ˜áƒšáƒ˜áƒ¡ მáƒáƒ¥áƒ¡áƒ˜áƒ›áƒáƒšáƒ£áƒ ზáƒáƒ›áƒáƒ–ე ($size)'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'წáƒáƒ მáƒáƒ¢áƒ”ბით დáƒáƒ™áƒáƒžáƒ˜áƒ დრ$nr მისáƒáƒ›áƒáƒ თი'; +$messages['copyerror'] = 'ვერცერთი მისáƒáƒ›áƒáƒ თი ვერდáƒáƒ™áƒáƒžáƒ˜áƒ დáƒ'; $messages['sourceisreadonly'] = 'áƒáƒ¦áƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ˜ მისáƒáƒ›áƒáƒ თის მხáƒáƒšáƒáƒ“ წáƒáƒ™áƒ˜áƒ—ხვáƒáƒ შესáƒáƒ«áƒšáƒ”ბელი'; $messages['errorsavingcontact'] = 'სáƒáƒ™áƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ მისáƒáƒ›áƒáƒ თის შენáƒáƒ®áƒ•áƒ შეუძლებელიáƒ'; $messages['movingmessage'] = 'შეტყáƒáƒ‘ინების გáƒáƒ“áƒáƒ¢áƒáƒœáƒ...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'გთხáƒáƒ•áƒ— მáƒáƒ˜áƒªáƒáƒ“áƒáƒ—, მირ$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>წáƒáƒ მáƒáƒ¢áƒ”ბით დáƒáƒ¡áƒ ულდრ$inserted კáƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ”ბის შემáƒáƒ¢áƒáƒœáƒ, $skipped áƒáƒ სებულის გáƒáƒ›áƒáƒ¢áƒáƒ•áƒ”ბáƒ</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'áƒáƒžáƒ”რáƒáƒªáƒ˜áƒ შეზღუდულიáƒ'; $messages['nofromaddress'] = 'ელ–ფáƒáƒ¡áƒ¢áƒ˜áƒ¡ მისáƒáƒ›áƒáƒ თი გáƒáƒ›áƒáƒ¢áƒáƒ•áƒ”ბულიáƒ'; $messages['editorwarning'] = 'რედáƒáƒ¥áƒ¢áƒáƒ ის გáƒáƒ“áƒáƒ თვრტექსტურრეჟიმში გáƒáƒ›áƒáƒ˜áƒ¬áƒ•áƒ”ვს áƒáƒ სებული ტექსტის ფáƒáƒ მáƒáƒ¢áƒ˜áƒ¡ დáƒáƒ™áƒáƒ გვáƒáƒ¡. გსურთ გáƒáƒ’რძელებáƒ?'; diff --git a/program/localization/km_KH/labels.inc b/program/localization/km_KH/labels.inc index bc2836a53..7b10b5f7f 100644 --- a/program/localization/km_KH/labels.inc +++ b/program/localization/km_KH/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'សំបុážáŸ’រពង្រៀង'; $labels['sent'] = 'សំបុážáŸ’រដែលបានបញ្ជូន'; $labels['trash'] = 'ធុងសំរាម'; $labels['junk'] = 'សំបុážáŸ’រមិនល្អ'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ចំណងជើង'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'បង្ហាញជាážáž¶ážšáž¶áž„'; $labels['folderactions'] = 'មុážáž„ារážáž'; $labels['compact'] = 'បង្រួម'; $labels['empty'] = 'áž‘áž‘áŸážš'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ទំហំសំបុážáŸ’រទាំងអស់ដែលមាន'; $labels['unknown'] = 'មិនស្គាល់'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'កំណážáŸ‹áž›áž€áŸ’ážážáŸážŽáŸ’ឌស្វ០$labels['searchmod'] = 'កែសំរួលលក្ážážáŸážŽáŸ’ឌស្វែងរក'; $labels['msgtext'] = 'សំបុážáŸ’រទាំងមូល'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'បើកក្នុងវីនដូវážáŸ’មី'; $labels['emlsave'] = 'រក្សាទុកទិន្ននáŸáž™áž‡áž¶áž¯áž€ážŸáž¶ážšáž”្រភáŸáž‘(.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'ទំពáŸážšáž…ុងក្រោយ'; $labels['group'] = 'ក្រុម'; $labels['groups'] = 'ក្រុម'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'អាសយដ្ឋានផ្ទាល់ážáŸ’លួន'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/km_KH/messages.inc b/program/localization/km_KH/messages.inc index 35bb10244..1f629fa6c 100644 --- a/program/localization/km_KH/messages.inc +++ b/program/localization/km_KH/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'កំពុងលុបការរចនាចោហ$messages['messageopenerror'] = 'មិនអាចទាញយកសំបុážáŸ’រពីម៉ាស៊ីនមáŸáž”ានទáŸ'; $messages['fileuploaderror'] = 'មិនអាចបញ្ជូលភ្ជាប់ឯកសារ'; $messages['filesizeerror'] = 'ទំហំឯកសារážáŸ’រូវបញ្ជូនលើសចំណុះទំហំធំបំផុážáž‚ឺ $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'បានចំលងអាសយដ្ឋានចំនួន $nrដោយជោគជáŸáž™'; +$messages['copyerror'] = 'មិនអាចចំលងអាសយដ្ឋានណាមួយឡើយ'; $messages['sourceisreadonly'] = 'លោកអ្នកមានសិទ្ធážáŸ’រឹមážáŸ‚មើលប្រភពនៃអាសយដ្ឋាននáŸáŸ‡'; $messages['errorsavingcontact'] = 'មិនអាចរក្សាអាសយដ្ឋានបានទáŸ'; $messages['movingmessage'] = 'កំពុកផ្ážáŸážšážŸáŸ†áž”áž»ážáŸ’ážš...'; $messages['copyingmessage'] = 'កំពុងចំលងសំបុážáŸ’ážš...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'កំពុងលុបសំបុážáŸ’ážš...'; $messages['markingmessage'] = 'កំពុងកំណážáŸ‹ážŸáŸ†áž‚ាល់សំបុážáŸ’ážš...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'សូមមáŸážáŸ’ážáž¶ážšáž„់ចាំកំហ$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>áž–áŸážáŸŒáž˜áž¶áž“ទំនាក់ទំនង $insertedបានបញ្ចូលដោយជោគជáŸáž™,ហើយបានរំលងចោលពážáŸŒáž˜áž¶áž“ដែលមានស្រាប់$skipped </b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'ប្រážáž·áŸ’ážáž”ážáŸ’ážáž·áž€áž¶ážšážáŸ’រូវបានគáŸáž ាមឃាážáŸ‹!'; $messages['nofromaddress'] = 'ážáŸ’វះអាសយដ្ឋានអ៊ីមែលក្នុងអážáŸ’ážážŸáž‰áŸ’ណាណមួយនáŸáŸ‡'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/ko_KR/labels.inc b/program/localization/ko_KR/labels.inc index 60a9275ac..950928767 100644 --- a/program/localization/ko_KR/labels.inc +++ b/program/localization/ko_KR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'ìž„ì‹œ 보관함'; $labels['sent'] = '보낸 편지함'; $labels['trash'] = '휴지통'; $labels['junk'] = '스팸 편지함'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ì œëª©'; @@ -194,7 +193,6 @@ $labels['listmode'] = '화면 모드 ëª©ë¡ ë³´ê¸°'; $labels['folderactions'] = 'í´ë” ëª…ë ¹'; $labels['compact'] = '간단하게'; $labels['empty'] = '비어 있ìŒ'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ë””ìŠ¤í¬ ì‚¬ìš©ëŸ‰'; $labels['unknown'] = 'ì•Œ 수 ì—†ìŒ'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = '검색 ìž¬ì„¤ì •'; $labels['searchmod'] = 'ìˆ˜ì •ìž ê²€ìƒ‰'; $labels['msgtext'] = 'ì „ì²´ 메시지'; $labels['body'] = '본문'; -$labels['type'] = 'Type'; $labels['openinextwin'] = '새 ì°½ì—ì„œ 열기'; $labels['emlsave'] = '다운로드(.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = '마지막 페ì´ì§€ 보기'; $labels['group'] = '그룹'; $labels['groups'] = '그룹'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'ê°œì¸ ì£¼ì†Œ'; $labels['searchsave'] = '검색 ì €ìž¥'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = '숫ìžê°€ í¬í•¨ëœ 단어 무시'; $labels['spellcheckignorecaps'] = 'ëª¨ë‘ ëŒ€ë¬¸ìžë¡œ í‘œê¸°ëœ ë‹¨ì–´ 무시'; $labels['addtodict'] = 'ì‚¬ì „ì— ì¶”ê°€'; $labels['mailtoprotohandler'] = 'mailto: ë§í¬ì˜ í”„ë¡œí† ì½œ ì²˜ë¦¬ìž ë“±ë¡'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = '메시지 ì „ë‹¬'; $labels['inline'] = '본문 내용으로'; $labels['asattachment'] = '첨부파ì¼ë¡œ'; diff --git a/program/localization/ko_KR/messages.inc b/program/localization/ko_KR/messages.inc index ace6dc8d7..bf42c9c89 100644 --- a/program/localization/ko_KR/messages.inc +++ b/program/localization/ko_KR/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'ì„œì‹ ì„¤ì • ì‚ì œ 중...'; $messages['messageopenerror'] = '서버ì—ì„œ 메시지를 불러올 수 ì—†ìŒ.'; $messages['fileuploaderror'] = 'íŒŒì¼ ì—…ë¡œë“œë¥¼ 실패함.'; $messages['filesizeerror'] = 'ì—…ë¡œë“œëœ íŒŒì¼ì´ 최대 í¬ê¸°ì¸ $size를 초과하였습니다.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nrê°œì˜ ì£¼ì†Œë¥¼ 성공ì 으로 복사함.'; +$messages['copyerror'] = 'ëª¨ë“ ì£¼ì†Œë¥¼ ë³µì‚¬í• ìˆ˜ ì—†ìŒ.'; $messages['sourceisreadonly'] = 'ì´ ì£¼ì†Œì˜ ì†ŒìŠ¤ëŠ” ì½ê¸° ì „ìš©ìž…ë‹ˆë‹¤.'; $messages['errorsavingcontact'] = 'ì—°ë½ì²˜ì˜ 주소를 ì €ìž¥í• ìˆ˜ ì—†ìŒ.'; $messages['movingmessage'] = '메시지를 ì´ë™í•˜ëŠ” 중...'; $messages['copyingmessage'] = '메시지 복사하는 중...'; $messages['copyingcontact'] = 'ì—°ë½ì²˜ 복사하는 중...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = '메시지 ì‚ì œí•˜ëŠ” 중...'; $messages['markingmessage'] = 'ë©”ì‹œì§€ì— í‘œì‹œí•˜ëŠ” 중...'; $messages['addingmember'] = 'ê·¸ë£¹ì— ì—°ë½ì²˜ë¥¼ 추가하는 중...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'ê°€ì ¸ì˜¤ëŠ” 중, ê¸°ë‹¤ë ¤ì£¼ì‹œê¸° ë°”ëžë‹ˆë‹¤...' $messages['importformaterror'] = 'ê°€ì ¸ì˜¤ê¸°ë¥¼ 실패함! ì—…ë¡œë“œëœ íŒŒì¼ì€ ìœ íš¨í•˜ì§€ ì•Šì€ ê°€ì ¸ì˜¤ê¸° ë°ì´í„° 파ì¼ìž…니다.'; $messages['importconfirm'] = '<b>$inserted ì—°ë½ì²˜ë¥¼ 성공ì 으로 ê°€ì ¸ì˜´<b>'; $messages['importconfirmskipped'] = '<b>기존 기재사í•ì¸ $skippedì„(를) 건너뜀</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'ìž‘ì—…ì´ í—ˆê°€ë˜ì§€ ì•ŠìŒ!'; $messages['nofromaddress'] = 'ì„ íƒëœ ì‹ ì›ì— ì´ë©”ì¼ ì£¼ì†Œ ê°€ 누ë½ë¨.'; $messages['editorwarning'] = 'ì¼ë°˜ í…스트 편집기로 바꾸면 ëª¨ë“ í…스트 ì„œì‹ì´ 사ë¼ì§‘니다. 계ì†í•˜ì‹œê² 습니까?'; diff --git a/program/localization/ku/labels.inc b/program/localization/ku/labels.inc index 6a3c16a5f..a4f6cb568 100644 --- a/program/localization/ku/labels.inc +++ b/program/localization/ku/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Hilanînî'; $labels['sent'] = 'Åžandî'; $labels['trash'] = 'Çop'; $labels['junk'] = 'Biikêrnehatî'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Mijar'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Kompakt'; $labels['empty'] = 'Vala Bike'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Bikaranîna dîskê'; $labels['unknown'] = 'nayê zanîn'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Lêgerînê reset bike'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Seta dawî nîşan bide'; $labels['group'] = 'Group'; $labels['groups'] = 'Kom'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Navnîşanên Takekesî'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ku/messages.inc b/program/localization/ku/messages.inc index b3c716466..9d219cbf5 100644 --- a/program/localization/ku/messages.inc +++ b/program/localization/ku/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Formatkirin ji peyamê tê birin...'; $messages['messageopenerror'] = 'Peyam ji pêşkêşkar nehat barkirin'; $messages['fileuploaderror'] = 'Barkirina pelê têk çû'; $messages['filesizeerror'] = 'Pel pir mezin e. Herî zêde divê $size be'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr navnîşan hat(in) jibergirtin'; +$messages['copyerror'] = 'Tu navnîşan nehat jibergirtin'; $messages['sourceisreadonly'] = 'Çavkaniya vê navnîşanê tenê-xwendin e'; $messages['errorsavingcontact'] = 'Navnîşana têkiliyê nehat barkirin'; $messages['movingmessage'] = 'Ciyê peyamê tê guhertin...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/lb_LU/labels.inc b/program/localization/lb_LU/labels.inc index 1dff3a9e7..cbd5a12a8 100644 --- a/program/localization/lb_LU/labels.inc +++ b/program/localization/lb_LU/labels.inc @@ -15,31 +15,21 @@ For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/labels/ */ - -$labels = array(); - -// login page $labels['welcome'] = 'Wëllkomm bei $product'; $labels['username'] = 'Benotzernumm'; $labels['password'] = 'Passwuert'; $labels['server'] = 'Server'; $labels['login'] = 'Aloggen'; - -// taskbar $labels['logout'] = 'Ausloggen'; $labels['mail'] = 'Mailen'; $labels['settings'] = 'Astellungen'; $labels['addressbook'] = 'Adressbuch'; - -// mailbox names $labels['inbox'] = 'Mailbox'; $labels['drafts'] = 'Brouillonen'; $labels['sent'] = 'Verschéckt'; $labels['trash'] = 'Poubelle'; $labels['junk'] = 'Spam'; $labels['show_real_foldernames'] = 'Richteg Nimm vu de speziellen Dossieren uweisen'; - -// message listing $labels['subject'] = 'Sujet'; $labels['from'] = 'Vun'; $labels['sender'] = 'Geschéckt vun'; @@ -54,13 +44,11 @@ $labels['priority'] = 'Prioritéit'; $labels['organization'] = 'Organisatioun'; $labels['readstatus'] = 'Lies-Status'; $labels['listoptions'] = 'Optiounen oplëschten'; - $labels['mailboxlist'] = 'Dossieren'; $labels['messagesfromto'] = 'Messagen $from bis $to vun $count'; $labels['threadsfromto'] = 'Diskussiounen $from bis $to vun $count'; $labels['messagenrof'] = 'Message $nr vun $count'; $labels['fromtoshort'] = '$from bis $to vun $count'; - $labels['copy'] = 'Kopéieren'; $labels['move'] = 'Réckelen'; $labels['moveto'] = 'Réckelen an...'; @@ -68,13 +56,9 @@ $labels['download'] = 'Eroflueden'; $labels['open'] = 'Opmaachen'; $labels['showattachment'] = 'Weisen'; $labels['showanyway'] = 'Trotzdeem weisen'; - $labels['filename'] = 'Numm vum Fichier'; $labels['filesize'] = 'Gréisst vum Fichier'; - $labels['addtoaddressbook'] = 'An d\'Adressbuch setzen'; - -// weekdays short $labels['sun'] = 'Son'; $labels['mon'] = 'Méi'; $labels['tue'] = 'Dën'; @@ -82,8 +66,6 @@ $labels['wed'] = 'Don'; $labels['thu'] = 'Fre'; $labels['fri'] = 'Sam'; $labels['sat'] = 'Son'; - -// weekdays long $labels['sunday'] = 'Sonndeg'; $labels['monday'] = 'Méindeg'; $labels['tuesday'] = 'Dënschdeg'; @@ -91,8 +73,6 @@ $labels['wednesday'] = 'Mëttwoch'; $labels['thursday'] = 'Donneschdeg'; $labels['friday'] = 'Freideg'; $labels['saturday'] = 'Samschdeg'; - -// months short $labels['jan'] = 'Jan'; $labels['feb'] = 'Feb'; $labels['mar'] = 'Mäe'; @@ -105,8 +85,6 @@ $labels['sep'] = 'Sep'; $labels['oct'] = 'Okt'; $labels['nov'] = 'Nov'; $labels['dec'] = 'Dez'; - -// months long $labels['longjan'] = 'Januar'; $labels['longfeb'] = 'Februar'; $labels['longmar'] = 'Mäerz'; @@ -119,10 +97,7 @@ $labels['longsep'] = 'September'; $labels['longoct'] = 'Oktober'; $labels['longnov'] = 'November'; $labels['longdec'] = 'Dezember'; - $labels['today'] = 'Haut'; - -// toolbar buttons $labels['refresh'] = 'Nei lueden'; $labels['checkmail'] = 'Nei Messagen ofruffen'; $labels['compose'] = 'Schreiwen'; @@ -155,7 +130,6 @@ $labels['moreactions'] = 'Mei Aktiounen...'; $labels['more'] = 'Méi'; $labels['back'] = 'Zréck'; $labels['options'] = 'Optiounen'; - $labels['select'] = 'Auswielen'; $labels['all'] = 'All'; $labels['none'] = 'Keng'; @@ -174,7 +148,6 @@ $labels['expand-all'] = 'All opfächeren'; $labels['expand-unread'] = 'Ongelies opfächeren'; $labels['collapse-all'] = 'All zesummefächeren'; $labels['threaded'] = 'Diskussiounen zesummefaassen'; - $labels['autoexpand_threads'] = 'Diskussiounen auserneefächeren'; $labels['do_expand'] = 'All d\'Diskussiounen'; $labels['expand_only_unread'] = 'just ongeliese Messagen'; @@ -190,16 +163,13 @@ $labels['listcolumns'] = 'Kolonnen oplëschten'; $labels['listsorting'] = 'Kolonne sortéieren'; $labels['listorder'] = 'Sortéier-Reiefolleg'; $labels['listmode'] = 'Oplëschtungs-Modus'; - $labels['folderactions'] = 'Dossiers-Aktiounen...'; $labels['compact'] = 'Kompaktéieren'; $labels['empty'] = 'Eidel'; $labels['importmessages'] = 'Messagen importéieren'; - $labels['quota'] = 'Plazverbrauch'; $labels['unknown'] = 'onbekannt'; $labels['unlimited'] = 'onlimitéiert'; - $labels['quicksearch'] = 'Séier Sich'; $labels['resetsearch'] = 'Sich zerécksetzen'; $labels['searchmod'] = 'Sich-Parameter'; @@ -207,13 +177,10 @@ $labels['msgtext'] = 'Ganze Message'; $labels['body'] = 'Kierper'; $labels['type'] = 'Typ'; $labels['namex'] = 'Numm'; - $labels['openinextwin'] = 'An enger neier Fënster opmaachen'; $labels['emlsave'] = 'Eroflueden (.eml)'; $labels['changeformattext'] = 'Als Text ouni Formatéierungen uweisen'; $labels['changeformathtml'] = 'Als formatéierten Text uweisen'; - -// message compose $labels['editasnew'] = 'Als nei editéieren'; $labels['send'] = 'Schécken'; $labels['sendmessage'] = 'Message schécken'; @@ -225,26 +192,30 @@ $labels['returnreceipt'] = 'Empfanksbestätegung'; $labels['dsn'] = 'Empfanks-Status-Meldung'; $labels['mailreplyintro'] = 'Den $date, $sender schreift:'; $labels['originalmessage'] = 'Original-Message'; - $labels['editidents'] = 'Identitéiten editéieren'; $labels['spellcheck'] = 'Orthographie'; $labels['checkspelling'] = 'Orthographie kontrolléieren'; $labels['resumeediting'] = 'Weider editéieren'; $labels['revertto'] = 'Zréck bei'; - +$labels['responses'] = 'Äntwerten'; +$labels['insertresponse'] = 'Äntwert afügen'; +$labels['manageresponses'] = 'Äntwerte geréieren'; +$labels['savenewresponse'] = 'Nei Äntwert späicheren'; +$labels['editresponses'] = 'Äntwerten Editéieren'; +$labels['editresponse'] = 'Äntwert editéieren'; +$labels['responsename'] = 'Numm'; +$labels['responsetext'] = 'Äntwert-Text'; $labels['attach'] = 'Drunhänken'; $labels['attachments'] = 'Unhäng'; $labels['upload'] = 'Eroplueden'; $labels['uploadprogress'] = '$percent ($current vun $total)'; $labels['close'] = 'Zoumaachen'; $labels['messageoptions'] = 'Message-Optiounen...'; - $labels['low'] = 'Niddreg'; $labels['lowest'] = 'Am niddregsten'; $labels['normal'] = 'Normal'; $labels['high'] = 'Héich'; $labels['highest'] = 'Am héchsten'; - $labels['nosubject'] = '(kee Sujet)'; $labels['showimages'] = 'Biller uweisen'; $labels['alwaysshow'] = 'Biller vun $sender ëmmer uweisen'; @@ -252,25 +223,19 @@ $labels['isdraft'] = 'Dëst ass e Brouillon.'; $labels['andnmore'] = '$nr more...'; $labels['togglemoreheaders'] = 'Méi Message-Headeren uweisen'; $labels['togglefullheaders'] = 'Réi Message-Headeren an-/ausblenden'; - $labels['htmltoggle'] = 'Text mat Formatéierungen'; $labels['plaintoggle'] = 'Text ouni Formatéierungen'; $labels['savesentmessagein'] = 'Dee verschéckte Message späicheren an'; $labels['dontsave'] = 'net späicheren'; $labels['maxuploadsize'] = 'Déi maximal erlaabte Fichiers-Gréisst ass $size'; - $labels['addcc'] = 'CC dobäisetzen'; $labels['addbcc'] = 'BCC dobäisetzen'; $labels['addreplyto'] = '"Äntwert un" dobäisetzen'; $labels['addfollowupto'] = '"Noverfollgung un" dobäisetzen'; - -// mdn $labels['mdnrequest'] = 'De Sender vun dësem Message huet gefrot fir informéiert ze gi wann de Message gelies gëtt. Wëlls du de Sender informéieren?'; $labels['receiptread'] = 'Empfanksbestätegung (gelies)'; $labels['yourmessage'] = 'Dëst ass eng Empfanksbestätegung fir Äre Message.'; $labels['receiptnote'] = 'Bemierkung: Dës Bestätegung bezeit just datt de Message beim Empfänger ugewise ginn ass. Et gëtt keng Garantie dass den Empfänger den Inhalt vum Message gelies oder verstanen huet.'; - -// address boook $labels['name'] = 'Ganzen Numm'; $labels['firstname'] = 'Virnumm'; $labels['surname'] = 'Nonumm'; @@ -305,7 +270,6 @@ $labels['search'] = 'Sichen'; $labels['advsearch'] = 'Avancéiert Sich'; $labels['advanced'] = 'Avancéiert'; $labels['other'] = 'Aneres'; - $labels['typehome'] = 'Doheem'; $labels['typework'] = 'Aarbecht'; $labels['typeother'] = 'Aneres'; @@ -320,14 +284,12 @@ $labels['typeassistant'] = 'Assistent'; $labels['typehomepage'] = 'Websäit'; $labels['typeblog'] = 'Blog'; $labels['typeprofile'] = 'Profil'; - $labels['addfield'] = 'Feld dobäisetzen...'; $labels['addcontact'] = 'Neie Kontakt dobäisetzen'; $labels['editcontact'] = 'Kontakt editéieren'; $labels['contacts'] = 'Kontakter'; $labels['contactproperties'] = 'Kontakt-Eegeschaften'; $labels['personalinfo'] = 'Perséinlech Informatioun'; - $labels['edit'] = 'Änneren'; $labels['cancel'] = 'Ofbriechen'; $labels['save'] = 'Späicheren'; @@ -336,7 +298,6 @@ $labels['rename'] = 'Ëmbenennen'; $labels['addphoto'] = 'Dobäisetzen'; $labels['replacephoto'] = 'Ersetzen'; $labels['uploadphoto'] = 'Foto eroplueden'; - $labels['newcontact'] = 'Nei Kontakt-Kaart erstellen'; $labels['deletecontact'] = 'Déi ausgewielte Kontakter läschen'; $labels['composeto'] = 'Mail schreiwen un'; @@ -350,42 +311,36 @@ $labels['newcontactgroup'] = 'Nei Kontakt-Grupp erstellen'; $labels['grouprename'] = 'Grupp ëmbenennen'; $labels['groupdelete'] = 'Grupp läschen'; $labels['groupremoveselected'] = 'Ausgewielte Kontakter aus Grupp eraushuele'; - $labels['previouspage'] = 'Säit virdru weisen'; $labels['firstpage'] = 'Éischt Säit weisen'; $labels['nextpage'] = 'Nächst Säit weisen'; $labels['lastpage'] = 'Lescht Säit weisen'; - $labels['group'] = 'Grup'; $labels['groups'] = 'Gruppen'; $labels['listgroup'] = 'Gruppe-Memberen oplëschten'; $labels['personaladrbook'] = 'Perséinlech Adressen'; - $labels['searchsave'] = 'Sich späicheren'; $labels['searchdelete'] = 'Sich läschen'; - $labels['import'] = 'Importéieren'; $labels['importcontacts'] = 'Kontakter importéieren'; $labels['importfromfile'] = 'Aus Fichier importéieren:'; -$labels['importtarget'] = 'Nei Kontakter an d\'Adressbuch setzen:'; +$labels['importtarget'] = 'Kontakter dobäisetze bei'; $labels['importreplace'] = 'Dat ganzt Adressbuch ersetzen'; +$labels['importgroups'] = 'Gruppen-Zouweisung importéieren'; +$labels['importgroupsall'] = 'All (nei Gruppen uleeën falls néideg)'; +$labels['importgroupsexisting'] = 'Just fir Gruppen déi schon existéieren'; $labels['importdesc'] = 'Du kanns Kontakter aus engem existéierenden Adressbuch eroplueden.<br/>Mir ënnerstëtze momentan en Adress-Import vum <a href="http://en.wikipedia.org/wiki/VCard">vCard</a>- oder CSV (mat Komma getrennt)-Date-Format.'; $labels['done'] = 'Erleedegt'; - -// settings $labels['settingsfor'] = 'Astellunge fir'; $labels['about'] = 'Iwwert'; $labels['preferences'] = 'Astellungen'; $labels['userpreferences'] = 'Benotzer-Astellungen'; $labels['editpreferences'] = 'Benotzer-Astellungen änneren'; - $labels['identities'] = 'Identitéiten'; $labels['manageidentities'] = 'Identitéite fir dësen Account geréieren'; $labels['newidentity'] = 'Nei Identitéit'; - $labels['newitem'] = 'Neit Element'; $labels['edititem'] = 'Element änneren'; - $labels['preferhtml'] = 'HTML uweisen'; $labels['defaultcharset'] = 'Standard Zeechesaz'; $labels['htmlmessage'] = 'HTML-Message'; @@ -481,7 +436,6 @@ $labels['standardwindows'] = 'Popup-Fënstere wéi normal Fënstere behandelen'; $labels['forwardmode'] = 'Messagë-Weiderleedung'; $labels['inline'] = 'am Message'; $labels['asattachment'] = 'als Unhank'; - $labels['folder'] = 'Dossier'; $labels['folders'] = 'Dossieren'; $labels['foldername'] = 'Dossiersnumm'; @@ -502,26 +456,20 @@ $labels['foldertype'] = 'Dossiers-Typ'; $labels['personalfolder'] = 'Privaten Dossier'; $labels['otherfolder'] = 'Dossier vun anerem Benotzer'; $labels['sharedfolder'] = 'Ëffentlechen Dossier'; - $labels['sortby'] = 'Sortéieren no'; $labels['sortasc'] = 'Opsteigend sortéieren'; $labels['sortdesc'] = 'Ofsteigend sortéieren'; $labels['undo'] = 'Réckgängeg maachen'; - $labels['installedplugins'] = 'Installéiert Plugins'; $labels['plugin'] = 'Plugin'; $labels['version'] = 'Versioun'; $labels['source'] = 'Source'; $labels['license'] = 'Lizenz'; $labels['support'] = 'Support ufroen'; - -// units $labels['B'] = 'B'; $labels['KB'] = 'kB'; $labels['MB'] = 'MB'; $labels['GB'] = 'GB'; - -// character sets $labels['unicode'] = 'Unicode'; $labels['english'] = 'Englesch'; $labels['westerneuropean'] = 'West-Europäesch'; @@ -540,5 +488,4 @@ $labels['vietnamese'] = 'Vietnamesesch'; $labels['japanese'] = 'Japanesch'; $labels['korean'] = 'Koreanesch'; $labels['chinese'] = 'Chinesesch'; - ?> diff --git a/program/localization/lb_LU/messages.inc b/program/localization/lb_LU/messages.inc index 5599f227b..fc053b59e 100644 --- a/program/localization/lb_LU/messages.inc +++ b/program/localization/lb_LU/messages.inc @@ -15,8 +15,6 @@ For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/messages/ */ - -$messages = array(); $messages['errortitle'] = 'Ee Feeler ass opgetrueden!'; $messages['loginfailed'] = 'Login feelgeschloen.'; $messages['cookiesdisabled'] = 'Däi Browser acceptéiert keng Cookien.'; @@ -46,6 +44,8 @@ $messages['messagesent'] = 'Message erfollegräich verschéckt.'; $messages['savingmessage'] = 'Message gëtt gespäichert...'; $messages['messagesaved'] = 'Message als Brouillon gespäichert.'; $messages['successfullysaved'] = 'Erfollegräich gespäichert.'; +$messages['savingresponse'] = 'Äntwert-Text gëtt gespäichert...'; +$messages['deleteresponseconfirm'] = 'Wëlls du dësen Äntwert-Text wierklech läschen?'; $messages['addedsuccessfully'] = 'Kontakt erfollegräich an d\'Adressbuch gesat.'; $messages['contactexists'] = 'Et existéiert schon e Kontakt mat der selweschter E-Mail-Adress.'; $messages['contactnameexists'] = 'Et existéiert schon e Kontakt mam selweschten Numm.'; @@ -56,7 +56,7 @@ $messages['contactnotfound'] = 'Den ugefrotene Kontakt gouf net fonnt.'; $messages['contactsearchonly'] = 'Gëff e puer Sichbegrëffer a fir Kontakter ze fannen'; $messages['sendingfailed'] = 'De Message konnt net verschéckt ginn.'; $messages['senttooquickly'] = 'Waart wann ech gelift $sec Sekonn(en) bevir s du de Message verschécks. '; -$messages['errorsavingsent'] = 'Beim Späichere vum verschéckte Message ass e Feeler opgetrueden'; +$messages['errorsavingsent'] = 'Beim Späichere vum geschéckte Message ass e Feeler opgetruden.'; $messages['errorsaving'] = 'Beim Späicheren ass e Feeler opgetrueden.'; $messages['errormoving'] = 'D\'Messagë konnten net verréckelt ginn.'; $messages['errorcopying'] = 'D\'Messagë konnten net kopéiert ginn.'; @@ -172,5 +172,4 @@ $messages['parentnotwritable'] = 'Den Dossier konnt net am ausgewielten Dossier $messages['messagetoobig'] = 'Den Messagen-Deel ass ze grouss fir verschafft ze ginn.'; $messages['attachmentvalidationerror'] = 'WARNUNG! Dësen Unhank ass verdächteg well den tatsächlechen Typ vum Fichier net mam Typ deen am Message deklaréiert ass iwwertenee stëmmt. Falls du dem Ofsender net traus sollts du den Unhank net am Browser opmaache well e béisaartegen Inhalt enthaale kéint.<br/><br/><em>Erwaart: $expected; fonnt: $detected</em>'; $messages['noscriptwarning'] = 'Warnung: Dëse Webmail brauch JavaScript! Fir de Service benotzen ze kënnen, aktivéier w.e.gl JavaScript an denge Browser-Astellungen.'; - ?> diff --git a/program/localization/lt_LT/labels.inc b/program/localization/lt_LT/labels.inc index 31cb44d27..6398a3683 100644 --- a/program/localization/lt_LT/labels.inc +++ b/program/localization/lt_LT/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'JuodraÅ¡Äiai'; $labels['sent'] = 'IÅ¡siųsti laiÅ¡kai'; $labels['trash'] = 'Å iukÅ¡linÄ—'; $labels['junk'] = 'Brukalas'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Tema'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'SÄ…raÅ¡o rodymo veiksena'; $labels['folderactions'] = 'Veiksmai su aplankais…'; $labels['compact'] = 'Suglaudinti'; $labels['empty'] = 'IÅ¡tuÅ¡tinti'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disko naudojimas'; $labels['unknown'] = 'nežinomas'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'AtÅ¡aukti paieÅ¡kÄ…'; $labels['searchmod'] = 'PaieÅ¡kos modifikatoriai'; $labels['msgtext'] = 'Visas laiÅ¡kas'; $labels['body'] = 'LaiÅ¡ko tekstas'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Atverti naujame lange'; $labels['emlsave'] = 'Parsisiųsti (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Rodyti paskutinį puslapį'; $labels['group'] = 'GrupÄ—'; $labels['groups'] = 'GrupÄ—s'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Asmeniniai adresai'; $labels['searchsave'] = 'Ä®raÅ¡yti kaip radinių aplankÄ…'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Nepaisyti žodžių su skaitmenimis'; $labels['spellcheckignorecaps'] = 'Nepaisyti žodžių vien iÅ¡ didžiųjų raidžių'; $labels['addtodict'] = 'Ä®traukti į žodynÄ…'; $labels['mailtoprotohandler'] = 'Užregistruoti svetainÄ™ kaip dirbanÄiÄ… su „mailto:“ saitais'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'LaiÅ¡kų persiuntimo bÅ«das'; $labels['inline'] = 'kaip citatÄ…'; $labels['asattachment'] = 'kaip priedas'; diff --git a/program/localization/lt_LT/messages.inc b/program/localization/lt_LT/messages.inc index 7eb31ec3f..df19c291b 100644 --- a/program/localization/lt_LT/messages.inc +++ b/program/localization/lt_LT/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Å alinamas laiÅ¡ko formatavimas…'; $messages['messageopenerror'] = 'Nepavyko įkelti laiÅ¡ko iÅ¡ serverio.'; $messages['fileuploaderror'] = 'Nepavyko įkelti failo.'; $messages['filesizeerror'] = 'Ä®keltas failas virÅ¡ija maksimalų leistinÄ… dydį – $size.'; -$messages['copysuccess'] = 'Nukopijuota adresatų: $nr.'; -$messages['movesuccess'] = 'Perkelta adresatų: $nr.'; -$messages['copyerror'] = 'Adresatų nukopijuoti nepavyko.'; -$messages['moveerror'] = 'Adresatų perkelti nepavyko.'; +$messages['copysuccess'] = 'Nukopijuota adresų: $nr.'; +$messages['copyerror'] = 'Adresų nukopijuoti nepavyko.'; $messages['sourceisreadonly'] = 'Å is adresų Å¡altinis prieinamas tik skaitymui.'; $messages['errorsavingcontact'] = 'Asmens adreso įraÅ¡yti nepavyko.'; $messages['movingmessage'] = 'LaiÅ¡kas(-ai) perkeliamas(-i)…'; $messages['copyingmessage'] = 'LaiÅ¡kas(-ai) kopijuojamas(-i)…'; $messages['copyingcontact'] = 'Adresatas(-ai) kopijuojamas(-i)…'; -$messages['movingcontact'] = 'Adresatas(-ai) perkeliamas(-i)…'; $messages['deletingmessage'] = 'LaiÅ¡kas(-ai) Å¡alinamas(-i)…'; $messages['markingmessage'] = 'LaiÅ¡kas(-ai) žymimas(-i)…'; $messages['addingmember'] = 'Adresatas(-ai) įtraukiamas(-i) į grupę…'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importuojama, praÅ¡ome palaukti…'; $messages['importformaterror'] = 'Importas nepavyko! Ä®keltasis failas nÄ—ra tinkamas importavimui duomenų failas.'; $messages['importconfirm'] = '<b>SÄ—kmingai importuoti $inserted adresatai(-ų)</b>'; $messages['importconfirmskipped'] = '<b>Praleisti $skipped jau egzistuojantys adresatai(-ų)</b>'; -$messages['importmessagesuccess'] = 'Importuota laiÅ¡kų: $nr'; -$messages['importmessageerror'] = 'Importas nepavyko! Ä®keltasis failas nÄ—ra tinkamas importavimui laiÅ¡ko arba paÅ¡to dėžutÄ—s failas'; $messages['opnotpermitted'] = 'Veiksmas neleistinas!'; $messages['nofromaddress'] = 'Nenurodytas pasirinktosios tapatybÄ—s el. paÅ¡to adresas.'; $messages['editorwarning'] = 'Pereinant į grynojo teksto redagavimÄ…, visas laiÅ¡ko formatavimas bus prarastas. Ar tÄ™sti?'; diff --git a/program/localization/lv_LV/labels.inc b/program/localization/lv_LV/labels.inc index 0fe5b0faf..7d4de2564 100644 --- a/program/localization/lv_LV/labels.inc +++ b/program/localization/lv_LV/labels.inc @@ -23,51 +23,50 @@ $labels['welcome'] = 'Esiet laipni lÅ«gti $product'; $labels['username'] = 'LietotÄjvÄrds'; $labels['password'] = 'Parole'; $labels['server'] = 'Serveris'; -$labels['login'] = 'AutorizÄ“ties'; +$labels['login'] = 'PieslÄ“gties'; // taskbar -$labels['logout'] = 'Iziet'; +$labels['logout'] = 'AtslÄ“gties'; $labels['mail'] = 'E-pasts'; -$labels['settings'] = 'IestatÄ«jumi'; +$labels['settings'] = 'PersonÄ«gie iestatÄ«jumi'; $labels['addressbook'] = 'AdreÅ¡u grÄmata'; // mailbox names $labels['inbox'] = 'IenÄkoÅ¡Äs'; $labels['drafts'] = 'Uzmetumi'; $labels['sent'] = 'NosÅ«tÄ«tÄs'; -$labels['trash'] = 'PapÄ«rgrozs'; +$labels['trash'] = 'Miskaste'; $labels['junk'] = 'MÄ“stules'; -$labels['show_real_foldernames'] = 'SistÄ“mas mapÄ“m rÄdÄ«t Ä«stos nosaukumus'; // message listing $labels['subject'] = 'Temats'; $labels['from'] = 'No'; -$labels['sender'] = 'SÅ«tÄ«tÄjs'; +$labels['sender'] = 'Sender'; $labels['to'] = 'Kam'; $labels['cc'] = 'Cc'; $labels['bcc'] = 'Bcc'; -$labels['replyto'] = 'AtbildÄ“t-Uz'; -$labels['followupto'] = 'Sekot-Uz'; +$labels['replyto'] = 'Reply-To'; +$labels['followupto'] = 'Followup-To'; $labels['date'] = 'Datums'; $labels['size'] = 'IzmÄ“rs'; $labels['priority'] = 'PrioritÄte'; $labels['organization'] = 'Uzņēmums'; $labels['readstatus'] = 'IzlasÄ«Å¡anas statuss'; -$labels['listoptions'] = 'VÄ“stuļu saraksta attÄ“loÅ¡anas iestatÄ«jumi...'; +$labels['listoptions'] = 'List options...'; $labels['mailboxlist'] = 'Mapes'; $labels['messagesfromto'] = 'VÄ“stules $from lÄ«dz $to no $count'; $labels['threadsfromto'] = 'Vijumi $from lÄ«dz $to no $count'; -$labels['messagenrof'] = '$nr. vÄ“stule no $count'; -$labels['fromtoshort'] = '$from – $to no $count'; +$labels['messagenrof'] = '$nr. vÄ“stule no $count'; +$labels['fromtoshort'] = '$from – $to of $count'; $labels['copy'] = 'KopÄ“t'; $labels['move'] = 'PÄrvietot'; -$labels['moveto'] = 'PÄrvietot uz...'; +$labels['moveto'] = 'pÄrvietot uz...'; $labels['download'] = 'lejupielÄdÄ“t'; -$labels['open'] = 'AtvÄ“rt'; -$labels['showattachment'] = 'RÄdÄ«t'; -$labels['showanyway'] = 'Vienalga rÄdÄ«t'; +$labels['open'] = 'Open'; +$labels['showattachment'] = 'Show'; +$labels['showanyway'] = 'Show it anyway'; $labels['filename'] = 'Faila nosaukums'; $labels['filesize'] = 'Faila izmÄ“rs'; @@ -123,78 +122,77 @@ $labels['longdec'] = 'Decembris'; $labels['today'] = 'Å odien'; // toolbar buttons -$labels['refresh'] = 'Atjaunot'; -$labels['checkmail'] = 'PÄrbaudÄ«t e-pastu'; +$labels['refresh'] = 'Refresh'; +$labels['checkmail'] = 'PÄrbaudÄ«t pastu'; $labels['compose'] = 'RakstÄ«t vÄ“stuli'; $labels['writenewmessage'] = 'RakstÄ«t jaunu vÄ“stuli'; -$labels['reply'] = 'AtbildÄ“t'; -$labels['replytomessage'] = 'AtbildÄ“t sÅ«tÄ«tÄjam'; -$labels['replytoallmessage'] = 'AtbildÄ“t sÅ«tÄ«tÄjam vai listei un visiem adresÄtiem'; +$labels['reply'] = 'Reply'; +$labels['replytomessage'] = 'AtbildÄ“t'; +$labels['replytoallmessage'] = 'AtbildÄ“t sÅ«tÄ«tÄjam un visiem saņēmÄ“jiem'; $labels['replyall'] = 'AtbildÄ“t visiem'; $labels['replylist'] = 'AtbildÄ“t listei'; -$labels['forward'] = 'PÄrsÅ«tÄ«t'; +$labels['forward'] = 'Forward'; $labels['forwardinline'] = 'PÄrsÅ«tÄ«t iekļaujot vÄ“stulÄ“'; $labels['forwardattachment'] = 'PÄrsÅ«tÄ«t kÄ pielikumu'; $labels['forwardmessage'] = 'PÄrsÅ«tÄ«t vÄ“stuli'; $labels['deletemessage'] = 'DzÄ“st vÄ“stuli'; -$labels['movemessagetotrash'] = 'PÄrvietot vÄ“stuli uz papÄ«rgrozu'; -$labels['printmessage'] = 'IzdrukÄt Å¡o vÄ“stuli'; +$labels['movemessagetotrash'] = 'PÄrvietot vÄ“stuli uz miskasti'; +$labels['printmessage'] = 'izdrukÄt'; $labels['previousmessage'] = 'ParÄdÄ«t iepriekÅ¡Ä“jo vÄ“stuli'; $labels['firstmessage'] = 'ParÄdÄ«t pirmo vÄ“stuli'; $labels['nextmessage'] = 'ParÄdÄ«t nÄkamo vÄ“stuli'; $labels['lastmessage'] = 'ParÄdÄ«t pÄ“dÄ“jo vÄ“stuli'; $labels['backtolist'] = 'Atpakaļ uz vÄ“stuļu sarakstu'; -$labels['viewsource'] = 'ParÄdÄ«t pirmtekstu'; -$labels['mark'] = 'AtzÄ«mÄ“t'; -$labels['markmessages'] = 'AtzÄ«mÄ“t vÄ“stules kÄ:'; -$labels['markread'] = 'KÄ lasÄ«tas'; -$labels['markunread'] = 'KÄ nelasÄ«tas'; -$labels['markflagged'] = 'KÄ atÄ«mÄ“tas'; -$labels['markunflagged'] = 'KÄ neatzÄ«mÄ“tas'; -$labels['moreactions'] = 'Papildus darbÄ«bas...'; -$labels['more'] = 'VairÄk'; -$labels['back'] = 'Atpakaļ'; -$labels['options'] = 'Opcijas'; - -$labels['select'] = 'AtzÄ«mÄ“t'; -$labels['all'] = 'Visas'; -$labels['none'] = 'Nevienu'; +$labels['viewsource'] = 'parÄdÄ«t pirmtekstu'; +$labels['mark'] = 'Mark'; +$labels['markmessages'] = 'MarÄ·Ä“t vÄ“stules kÄ:'; +$labels['markread'] = 'lasÄ«tas'; +$labels['markunread'] = 'nelasÄ«tas'; +$labels['markflagged'] = 'iezÄ«mÄ“tas'; +$labels['markunflagged'] = 'neiezÄ«mÄ“tas'; +$labels['moreactions'] = 'Citas darbÄ«bas...'; +$labels['more'] = 'More'; +$labels['back'] = 'Back'; +$labels['options'] = 'Options'; + +$labels['select'] = 'IezÄ«mÄ“t'; +$labels['all'] = 'visas'; +$labels['none'] = 'Neviens'; $labels['currpage'] = 'PaÅ¡reizÄ“jÄ lapa'; -$labels['unread'] = 'NelasÄ«tÄs'; -$labels['flagged'] = 'AtzÄ«mÄ“tÄs'; -$labels['unanswered'] = 'NeatbildÄ“tÄs'; -$labels['withattachment'] = 'Ar pielikumu'; -$labels['deleted'] = 'DzÄ“stÄs'; -$labels['undeleted'] = 'Nav izdzÄ“stas'; -$labels['invert'] = 'PretÄ“ji'; +$labels['unread'] = 'nelasÄ«tÄs'; +$labels['flagged'] = 'iezÄ«mÄ“tÄs'; +$labels['unanswered'] = 'neatbildÄ“tÄs'; +$labels['withattachment'] = 'With attachment'; +$labels['deleted'] = 'dzÄ“stÄs'; +$labels['undeleted'] = 'Not deleted'; +$labels['invert'] = 'invertÄ“t'; $labels['filter'] = 'FiltrÄ“t'; -$labels['list'] = 'RÄdÄ«t kÄ sarakstu'; -$labels['threads'] = 'RÄdÄ«t kÄ vijumus'; +$labels['list'] = 'Saraksts'; +$labels['threads'] = 'Vijumi'; $labels['expand-all'] = 'IzvÄ“rst visus'; -$labels['expand-unread'] = 'IzvÄ“rst neizlasÄ«tÄs'; -$labels['collapse-all'] = 'Sakļaut visas'; -$labels['threaded'] = 'RÄdÄ«t vijumus'; +$labels['expand-unread'] = 'IzvÄ“rst neizlasÄ«tos'; +$labels['collapse-all'] = 'SavÄ“rst visu'; +$labels['threaded'] = 'SavÄ«ts'; $labels['autoexpand_threads'] = 'IzvÄ“rst vÄ“stuļu vijumus'; -$labels['do_expand'] = 'visus vijumus'; -$labels['expand_only_unread'] = 'tikai ar neizlasÄ«tÄm vÄ“stulÄ“m'; -$labels['fromto'] = 'No/Kam'; -$labels['flag'] = 'AtzÄ«mÄ“t'; +$labels['do_expand'] = 'visiem vijumiem'; +$labels['expand_only_unread'] = 'tikai tad, ja ir neizlasÄ«tas vÄ“stules'; +$labels['fromto'] = 'SÅ«tÄ«tÄjs/SaņēmÄ“js'; +$labels['flag'] = 'IezÄ«mÄ“ts'; $labels['attachment'] = 'Pielikums'; -$labels['nonesort'] = 'Neviena'; +$labels['nonesort'] = 'Neviens'; $labels['sentdate'] = 'NosÅ«tÄ«Å¡anas datums'; $labels['arrival'] = 'PienÄkÅ¡anas datums'; $labels['asc'] = 'augoÅ¡a'; $labels['desc'] = 'dilstoÅ¡a'; $labels['listcolumns'] = 'Saraksta kolonnas'; -$labels['listsorting'] = 'KÄrtoÅ¡anas kolonnas'; +$labels['listsorting'] = 'KÄrtot pÄ“c kolonnas'; $labels['listorder'] = 'KÄrtoÅ¡anas secÄ«ba'; -$labels['listmode'] = 'AttÄ“loÅ¡anas veids'; +$labels['listmode'] = 'Saraksta režīms'; $labels['folderactions'] = 'DarbÄ«bas ar mapÄ“m...'; -$labels['compact'] = 'Saspiest'; -$labels['empty'] = 'IztukÅ¡ot'; -$labels['importmessages'] = 'ImportÄ“t vÄ“stules'; +$labels['compact'] = 'saspiest'; +$labels['empty'] = 'iztukÅ¡ot'; $labels['quota'] = 'Kvota'; $labels['unknown'] = 'nezinÄms'; @@ -202,36 +200,35 @@ $labels['unlimited'] = 'neierobežots'; $labels['quicksearch'] = 'Ä€rtÄ meklÄ“Å¡ana'; $labels['resetsearch'] = 'AtstatÄ«t meklÄ“Å¡anu'; -$labels['searchmod'] = 'MeklÄ“Å¡anas modifikatori:'; -$labels['msgtext'] = 'VisÄ vÄ“stulÄ“'; -$labels['body'] = 'Pamatteksts'; -$labels['type'] = 'Tips'; +$labels['searchmod'] = 'MeklÄ“t laukos:'; +$labels['msgtext'] = 'VÄ“stules tekstÄ'; +$labels['body'] = 'Body'; -$labels['openinextwin'] = 'AtvÄ“rt jaunÄ logÄ'; +$labels['openinextwin'] = 'atvÄ“rt jaunÄ logÄ'; $labels['emlsave'] = 'lejupielÄdÄ“t (.eml)'; -$labels['changeformattext'] = 'RÄdÄ«t kÄ neformatÄ“tu tekstu'; -$labels['changeformathtml'] = 'RÄdÄ«t kÄ HTML formatÄ“tu'; +$labels['changeformattext'] = 'Display in plain text format'; +$labels['changeformathtml'] = 'Display in HTML format'; // message compose -$labels['editasnew'] = 'Rediģēt kÄ jaunu'; -$labels['send'] = 'SÅ«tÄ«t'; +$labels['editasnew'] = 'rediģēt kÄ jaunu'; +$labels['send'] = 'Send'; $labels['sendmessage'] = 'SÅ«tÄ«t vÄ“stuli'; -$labels['savemessage'] = 'SaglabÄt kÄ uzmetumu'; +$labels['savemessage'] = 'SaglabÄt uzmetumu'; $labels['addattachment'] = 'Pievienot failu'; $labels['charset'] = 'RakstzÄ«mju kopa'; $labels['editortype'] = 'Redaktora tips'; $labels['returnreceipt'] = 'SaņemÅ¡anas apstiprinÄjums'; -$labels['dsn'] = 'PiegÄdes atskaite'; +$labels['dsn'] = 'Atskaite par piegÄdi'; $labels['mailreplyintro'] = '$sender @ $date rakstÄ«ja:'; $labels['originalmessage'] = 'SÄkotnÄ“jÄ vÄ“stule'; $labels['editidents'] = 'Rediģēt identitÄtes'; -$labels['spellcheck'] = 'IzrunÄt'; +$labels['spellcheck'] = 'Spell'; $labels['checkspelling'] = 'PÄrbaudÄ«t pareizrakstÄ«bu'; $labels['resumeediting'] = 'TurpinÄt rediģēšanu'; $labels['revertto'] = 'Atgriezt uz'; -$labels['attach'] = 'Pievienot'; +$labels['attach'] = 'Attach'; $labels['attachments'] = 'Pielikumi'; $labels['upload'] = 'AugÅ¡upielÄdÄ“t'; $labels['uploadprogress'] = '$percent ($current no $total)'; @@ -244,13 +241,13 @@ $labels['normal'] = 'NormÄla'; $labels['high'] = 'Augsta'; $labels['highest'] = 'AugstÄkÄ'; -$labels['nosubject'] = '(bez tÄ“mas)'; +$labels['nosubject'] = '(no subject)'; $labels['showimages'] = 'RÄdÄ«t attÄ“lus'; -$labels['alwaysshow'] = 'VienmÄ“r rÄdÄ«t attÄ“lus vÄ“stulÄ“s, kuras sÅ«tÄ«jis $sender'; +$labels['alwaysshow'] = 'VienmÄ“r rÄdÄ«t attÄ“lus no $sender'; $labels['isdraft'] = 'Å is ir melnraksts.'; -$labels['andnmore'] = '$nr vairÄk...'; -$labels['togglemoreheaders'] = 'RÄdÄ«t galvenes papildus informÄciju'; -$labels['togglefullheaders'] = 'SlÄ“pt galvenes papildus informÄciju'; +$labels['andnmore'] = '$nr more...'; +$labels['togglemoreheaders'] = 'Show more message headers'; +$labels['togglefullheaders'] = 'Toggle raw message headers'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'VienkÄrÅ¡s teksts'; @@ -260,14 +257,14 @@ $labels['maxuploadsize'] = 'MaksimÄlais atļautais faila izmÄ“rs ir $size'; $labels['addcc'] = 'Pievienot Cc'; $labels['addbcc'] = 'Pievienot Bcc'; -$labels['addreplyto'] = 'Pievienot AtbildÄ“t-Uz'; +$labels['addreplyto'] = 'Pievienot Reply-To'; $labels['addfollowupto'] = 'Pievienot Followup-To'; // mdn -$labels['mdnrequest'] = 'Å Ä«s vÄ“stules sÅ«tÄ«tÄjs vÄ“las redzÄ“t vÄ“stules saņemÅ¡anas apstiprinÄjumu. Vai JÅ«s vÄ“laties nosÅ«tÄ«t Å¡o apstiprinÄjumu?'; +$labels['mdnrequest'] = 'Å Ä«s vÄ“stules sÅ«tÄ«tÄjs vÄ“las redzÄ“t vÄ“stules saņemÅ¡anas apstiprinÄjumu. Vai jÅ«s vÄ“laties nosÅ«tÄ«t apstiprinÄjumu?'; $labels['receiptread'] = 'SaņemÅ¡anas apstiprinÄjums'; -$labels['yourmessage'] = 'Å is ir JÅ«su nosÅ«tÄ«tÄs vÄ“stules saņemÅ¡anas apstiprinÄjums'; -$labels['receiptnote'] = 'PiezÄ«me: Å is apsiprinÄjums nozÄ«mÄ“ tikai to, ka vÄ“stule tika parÄdÄ«ta uz saņēmÄja datora. Tas nenozÄ«mÄ“, ka saņēmÄ“js ir izlasÄ«jis vai sapratis vÄ“stules saturu.'; +$labels['yourmessage'] = 'Å Ä«s ir jÅ«su vÄ“stules saņemÅ¡anas apstiprinÄjums'; +$labels['receiptnote'] = 'PiezÄ«me: Å Ä«s apsiprinÄjums nozÄ«mÄ“ tikai to, ka vÄ“stule tika parÄdÄ«ta uz saņēmÄja datora. Tas nenozÄ«mÄ“, ka saņēmÄ“js ir izlasÄ«jis vai izpratis vÄ“stules saturu.'; // address boook $labels['name'] = 'UzrÄdÄ«tais vÄrds'; @@ -276,33 +273,33 @@ $labels['surname'] = 'UzvÄrds'; $labels['middlename'] = 'Otrais vÄrds'; $labels['nameprefix'] = 'Prefikss'; $labels['namesuffix'] = 'Sufikss'; -$labels['nickname'] = 'SegvÄrds'; +$labels['nickname'] = 'Iesauka (nick)'; $labels['jobtitle'] = 'Amats'; $labels['department'] = 'Nodaļa'; $labels['gender'] = 'Dzimums'; -$labels['maidenname'] = 'PirmslaulÄ«bas uzvÄrds'; +$labels['maidenname'] = 'PirmslaulÄ«bu uzvÄrds'; $labels['email'] = 'E-pasts'; $labels['phone'] = 'TÄlrunis'; $labels['address'] = 'Adrese'; $labels['street'] = 'Iela'; $labels['locality'] = 'PilsÄ“ta'; -$labels['zipcode'] = 'Pasta indekss'; +$labels['zipcode'] = 'Pasta kods'; $labels['region'] = 'Novads'; $labels['country'] = 'PilsÄ“ta'; $labels['birthday'] = 'DzimÅ¡anas diena'; $labels['anniversary'] = 'Gadadiena'; -$labels['website'] = 'MÄjaslapa'; +$labels['website'] = 'Web lapa'; $labels['instantmessenger'] = 'IM'; $labels['notes'] = 'PiezÄ«mes'; $labels['male'] = 'vÄ«rietis'; $labels['female'] = 'sieviete'; $labels['manager'] = 'Menedžeris'; $labels['assistant'] = 'Asistents'; -$labels['spouse'] = 'LaulÄtais'; +$labels['spouse'] = 'LaulÄtais draugs'; $labels['allfields'] = 'Visi lauki'; $labels['search'] = 'MeklÄ“t'; $labels['advsearch'] = 'PaplaÅ¡inÄtÄ meklÄ“Å¡ana'; -$labels['advanced'] = 'PaplaÅ¡inÄtie iestatÄ«jumi'; +$labels['advanced'] = 'Advanced'; $labels['other'] = 'Cits'; $labels['typehome'] = 'MÄjas'; @@ -310,22 +307,22 @@ $labels['typework'] = 'Darbs'; $labels['typeother'] = 'Cits'; $labels['typemobile'] = 'Mobilais tÄlrunis'; $labels['typemain'] = 'Galvenais'; -$labels['typehomefax'] = 'Fakss mÄjÄs'; -$labels['typeworkfax'] = 'Fakss darbÄ'; +$labels['typehomefax'] = 'MÄjas Fax'; +$labels['typeworkfax'] = 'Darba Fax'; $labels['typecar'] = 'Auto'; $labels['typepager'] = 'Peidžeris'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Asistents'; -$labels['typehomepage'] = 'MÄjaslapa'; +$labels['typehomepage'] = 'Web lapa'; $labels['typeblog'] = 'Blogs'; $labels['typeprofile'] = 'Profils'; $labels['addfield'] = 'Pievienot lauku...'; -$labels['addcontact'] = 'Pievienot jaunu kontaktu'; -$labels['editcontact'] = 'Rediģēt kontaktu'; +$labels['addcontact'] = 'Pievienot iezÄ«mÄ“to ierakstu adreÅ¡u grÄmatai'; +$labels['editcontact'] = 'Rediģēt adreÅ¡u grÄmatas ierakstu'; $labels['contacts'] = 'Kontakti'; $labels['contactproperties'] = 'Kontakta Ä«paÅ¡Ä«bas'; -$labels['personalinfo'] = 'PersonÄ«gÄ informÄcija'; +$labels['personalinfo'] = 'PersoniskÄ informÄcija'; $labels['edit'] = 'Rediģēt'; $labels['cancel'] = 'Atcelt'; @@ -334,30 +331,29 @@ $labels['delete'] = 'DzÄ“st'; $labels['rename'] = 'PÄrdÄ“vÄ“t'; $labels['addphoto'] = 'Pievienot'; $labels['replacephoto'] = 'Aizvietot'; -$labels['uploadphoto'] = 'AugÅ¡upielÄdÄ“t fotogrÄfiju'; +$labels['uploadphoto'] = 'Upload photo'; -$labels['newcontact'] = 'Izveidot jaunu kontaktu'; -$labels['deletecontact'] = 'DzÄ“st atzÄ«mÄ“tos kontaktus'; +$labels['newcontact'] = 'Izveidot jaunu ierakstu'; +$labels['deletecontact'] = 'DzÄ“st iezÄ«mÄ“tos ierakstus'; $labels['composeto'] = 'RakstÄ«t vÄ“stuli'; -$labels['contactsfromto'] = 'Ieraksti no $from lÄ«dz $to - kopÄ $count'; +$labels['contactsfromto'] = 'Ieraksti $from lÄ«dz $to no $count'; $labels['print'] = 'DrukÄt'; $labels['export'] = 'EksportÄ“t'; -$labels['exportall'] = 'EksportÄ“t visu'; -$labels['exportsel'] = 'EksportÄ“t atzÄ«mÄ“to'; +$labels['exportall'] = 'Export all'; +$labels['exportsel'] = 'Export selected'; $labels['exportvcards'] = 'EksportÄ“t kontaktus vCard formÄtÄ'; $labels['newcontactgroup'] = 'Izveidot jaunu kontaktu grupu'; $labels['grouprename'] = 'PÄrdÄ“vÄ“t grupu'; $labels['groupdelete'] = 'IzdzÄ“st grupu'; -$labels['groupremoveselected'] = 'DzÄ“st atzÄ«mÄ“tos kontaktus no grupas'; +$labels['groupremoveselected'] = 'Remove selected contacts from group'; -$labels['previouspage'] = 'ParÄdÄ«t iepriekÅ¡Ä“jo lapu'; -$labels['firstpage'] = 'ParÄdÄ«t pirmo lapu'; -$labels['nextpage'] = 'ParÄdÄ«t nÄkamo lapu'; -$labels['lastpage'] = 'ParÄdÄ«t pÄ“dÄ“jo lapu'; +$labels['previouspage'] = 'ParÄdÄ«t iepriekÅ¡Ä“jo kopu'; +$labels['firstpage'] = 'ParÄdÄ«t pirmo kopu'; +$labels['nextpage'] = 'ParÄdÄ«t nÄkamo kopu'; +$labels['lastpage'] = 'ParÄdÄ«t pÄ“dÄ“jo kopu'; $labels['group'] = 'Grupa'; $labels['groups'] = 'Grupas'; -$labels['listgroup'] = 'RÄdÄ«t grupas kontaktus'; $labels['personaladrbook'] = 'PersonÄ«gÄs adreses'; $labels['searchsave'] = 'SaglabÄt meklÄ“Å¡anas pieprasÄ«jumu'; @@ -366,72 +362,72 @@ $labels['searchdelete'] = 'DzÄ“st saglabÄto meklÄ“Å¡anas pieprasÄ«jumu'; $labels['import'] = 'ImportÄ“t'; $labels['importcontacts'] = 'ImportÄ“t kontaktus'; $labels['importfromfile'] = 'ImportÄ“t no faila:'; -$labels['importtarget'] = 'Pievienot jaunus kontaktus adreÅ¡u grÄmatai:'; +$labels['importtarget'] = 'Pievienot jaunus kontaktus adreÅ¡u grÄmatai'; $labels['importreplace'] = 'Aizvietot visu adreÅ¡u grÄmatu'; -$labels['importdesc'] = 'JÅ«s varat ieimportÄ“t kontaktus no jau esoÅ¡as adreÅ¡u grÄmatas.<br/>Uz doto brÄ«di tiek atbalstÄ«ti <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> vai CSV (ar komatu atdalÄ«tie) datu formÄti.'; +$labels['importdesc'] = 'You can upload contacts from an existing address book.<br/>We currently support importing addresses from the <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> or CSV (comma-separated) data format.'; $labels['done'] = 'Pabeigts'; // settings $labels['settingsfor'] = 'IestatÄ«jumi'; $labels['about'] = 'Par'; $labels['preferences'] = 'IestatÄ«jumi'; -$labels['userpreferences'] = 'LietotÄja iestatÄ«jumi'; -$labels['editpreferences'] = 'Rediģēt iestatÄ«jumus'; +$labels['userpreferences'] = 'LietotÄja preferences'; +$labels['editpreferences'] = 'Rediģēt lietotÄja preferences'; $labels['identities'] = 'IdentitÄtes'; -$labels['manageidentities'] = 'Rediģēt identitÄtes'; +$labels['manageidentities'] = 'Rediģēt Å¡Ä« konta identitÄtes'; $labels['newidentity'] = 'Jauna identitÄte'; $labels['newitem'] = 'Jauns'; $labels['edititem'] = 'Rediģēt'; -$labels['preferhtml'] = 'RÄdÄ«t HTML formatÄ“tÄs vÄ“stules'; +$labels['preferhtml'] = 'Dot priekÅ¡roku HTML formatÄ“tÄm vÄ“stulÄ“m'; $labels['defaultcharset'] = 'NoklusÄ“tÄ rakstzÄ«mju kopa'; -$labels['htmlmessage'] = 'HTML formatÄ“ta vÄ“stule'; -$labels['messagepart'] = 'Daļa'; -$labels['digitalsig'] = 'DigitÄlais paraksts'; +$labels['htmlmessage'] = 'HTML vÄ“stule'; +$labels['messagepart'] = 'Part'; +$labels['digitalsig'] = 'Digital Signature'; $labels['dateformat'] = 'Datuma formÄts'; $labels['timeformat'] = 'Laika formÄts'; -$labels['prettydate'] = 'RÄdÄ«t Ä«sos datumus'; +$labels['prettydate'] = 'FormatÄ“t datumus'; $labels['setdefault'] = 'Uzlikt kÄ noklusÄ“to'; -$labels['autodetect'] = 'AutomÄtiska'; +$labels['autodetect'] = 'AutomÄtiski'; $labels['language'] = 'Valoda'; $labels['timezone'] = 'Laika zona'; $labels['pagesize'] = 'Rindas lapÄ'; $labels['signature'] = 'Paraksts'; $labels['dstactive'] = 'Vasaras/ziemas laiks'; -$labels['showinextwin'] = 'VÄ“stules atvÄ“rt jaunÄ logÄ'; -$labels['composeextwin'] = 'VÄ“stuli rakstÄ«t jaunÄ logÄ'; -$labels['htmleditor'] = 'RakstÄ«t HTML formatÄ“tas vÄ“stules'; +$labels['showinextwin'] = 'Open message in a new window'; +$labels['composeextwin'] = 'Compose in a new window'; +$labels['htmleditor'] = 'RakstÄ«t HTML vÄ“stules'; $labels['htmlonreply'] = 'tikai atbildot uz HTML formatÄ“tÄm vÄ“stulÄ“m'; -$labels['htmlonreplyandforward'] = 'tikai pÄrsÅ«tot vai atbildot uz HTML formatÄ“tu vÄ“stuli'; -$labels['htmlsignature'] = 'HTML formatÄ“ts paraksts'; -$labels['showemail'] = 'Pie vÄrda rÄdÄ«t arÄ« e-pasta adresi'; +$labels['htmlonreplyandforward'] = 'on forward or reply to HTML message'; +$labels['htmlsignature'] = 'HTML paraksts'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'RÄdÄ«t priekÅ¡skatÄ«juma paneli'; -$labels['skin'] = 'Saskarnes izskats'; -$labels['logoutclear'] = 'Izejot no e-pasta, iztÄ«rÄ«t papÄ«rgrozu'; -$labels['logoutcompact'] = 'Izejot no e-pasta, saspiest iesÅ«tni'; +$labels['skin'] = 'Interfeisa izskats'; +$labels['logoutclear'] = 'Izejot no sistÄ“mas, iztÄ«rÄ«t miskasti'; +$labels['logoutcompact'] = 'Izejot no sistÄ“mas, saspiest iesÅ«tni'; $labels['uisettings'] = 'LietotÄja saskarne'; $labels['serversettings'] = 'Servera iestatÄ«jumi'; $labels['mailboxview'] = 'Pastkastes skats'; $labels['mdnrequests'] = 'VÄ“stules izlasÄ«Å¡anas atskaites sÅ«tÄ«Å¡ana'; -$labels['askuser'] = 'jautÄt man vai sÅ«tÄ«t'; +$labels['askuser'] = 'jautÄt lietotÄjam'; $labels['autosend'] = 'sÅ«tÄ«t automÄtiski'; -$labels['autosendknown'] = 'automÄtiski sÅ«tÄ«t ja pieprasÄ«tÄjs ir manos kontaktos, par citiem jautÄt'; -$labels['autosendknownignore'] = 'automÄtiski sÅ«tÄ«t ja pieprasÄ«tÄjs ir manos kontaktos, citiem ignorÄ“t un nesÅ«tÄ«t'; -$labels['ignore'] = 'ignorÄ“t un nesÅ«tÄ«t'; -$labels['readwhendeleted'] = 'DzÄ“Å¡ot vÄ“stules tÄs atzÄ«mÄ“t kÄ izlasÄ«tas'; -$labels['flagfordeletion'] = 'DzÄ“Å¡ot vÄ“stules tÄs nedzÄ“st, bet marÄ·Ä“t kÄ dzÄ“Å¡amas'; +$labels['autosendknown'] = 'automÄtiski sÅ«tÄ«t maniem kontaktiem, par citiem jautÄt'; +$labels['autosendknownignore'] = 'automÄtiski sÅ«tÄ«t maniem kontaktiem, citiem nesÅ«tÄ«t'; +$labels['ignore'] = 'ignorÄ“t'; +$labels['readwhendeleted'] = 'AtzÄ«mÄ“t dzÄ“stÄs vÄ“stules kÄ izlasÄ«tas'; +$labels['flagfordeletion'] = 'DzÄ“Å¡ot marÄ·Ä“t vÄ“stules kÄ dzÄ“stas, bet nedzÄ“st'; $labels['skipdeleted'] = 'NerÄdÄ«t dzÄ“stÄs vÄ“stules'; -$labels['deletealways'] = 'IzdzÄ“st vÄ“stules, ja tÄs neizdodas pÄrvietot uz papÄ«rgrozu'; -$labels['deletejunk'] = 'AutomÄtiski dzÄ“st vÄ“stules no mÄ“stuļu mapÄ«tes'; -$labels['showremoteimages'] = 'RÄdÄ«t vÄ“stulÄ“s attÄ“lus, kuri atrodas uz cita servera'; -$labels['fromknownsenders'] = 'tikai no zinÄmiem sÅ«tÄ«tÄjiem'; +$labels['deletealways'] = 'IzdzÄ“st vÄ“stules, ja tÄs neizdodas pÄrvietot uz miskasti'; +$labels['deletejunk'] = 'Directly delete messages in Junk'; +$labels['showremoteimages'] = 'RÄdÄ«t attÄ“lus, kas atrodas uz cita servera'; +$labels['fromknownsenders'] = 'no zinÄmiem sÅ«tÄ«tÄjiem'; $labels['always'] = 'vienmÄ“r'; $labels['showinlineimages'] = 'RÄdÄ«t pielikuma attÄ“lus zem vÄ“stules'; -$labels['autosavedraft'] = 'AutomÄtiski saglabÄt vÄ“stules uzmetumu'; -$labels['everynminutes'] = 'ik pÄ“c $n minÅ«tes(Ä“m)'; -$labels['refreshinterval'] = 'PÄrbaudÄ«t jaunÄs vÄ“stules'; +$labels['autosavedraft'] = 'AutomÄtiski saglabÄt uzmetumu'; +$labels['everynminutes'] = 'ik pa $n minÅ«ti(Ä“m)'; +$labels['refreshinterval'] = 'Refresh (check for new messages, etc.)'; $labels['never'] = 'nekad'; $labels['immediately'] = 'nekavÄ“joties'; $labels['messagesdisplaying'] = 'VÄ“stuļu attÄ“loÅ¡ana'; @@ -441,45 +437,44 @@ $labels['2231folding'] = 'Pilns RFC 2231 (Thunderbird)'; $labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; $labels['2047folding'] = 'Pilns RFC 2047 (citi)'; $labels['force7bit'] = 'Izmantot MIME kodÄ“jumu 8-bitu simboliem'; -$labels['advancedoptions'] = 'PaplaÅ¡inÄtie iestatÄ«jumi'; -$labels['focusonnewmessage'] = 'UzstÄdÄ«t pÄrlÅ«ka fokusu uz jaunu vÄ“stuli'; -$labels['checkallfolders'] = 'MeklÄ“t visÄs mapÄ“s jaunÄs vÄ“stules'; -$labels['displaynext'] = 'PÄ“c vÄ“stules dzÄ“Å¡anas/pÄrvietoÅ¡anas rÄdÄ«t nÄkamo vÄ“stuli'; -$labels['defaultfont'] = 'NoklusÄ“tais fonts vÄ“stulÄ“m HTML formÄtÄ'; +$labels['advancedoptions'] = 'PaplaÅ¡inÄti iestatÄ«jumi'; +$labels['focusonnewmessage'] = 'UztÄdÄ«t pÄrlÅ«ka fokusu uz jaunu vÄ“stuli'; +$labels['checkallfolders'] = 'PÄrbaudÄ«t visas mapes pÄ“c jaunÄm vÄ“stulÄ“m'; +$labels['displaynext'] = 'RÄdÄ«t nÄkamo vÄ“stuli pÄ“c dzÄ“Å¡anas/pÄrvietoÅ¡anas'; +$labels['defaultfont'] = 'NoklusÄ“tais fonts vÄ“stulei HTML formÄtÄ'; $labels['mainoptions'] = 'Galvenie iestatÄ«jumi'; -$labels['browseroptions'] = 'PÄrlÅ«ka iestatÄ«jumi'; -$labels['section'] = 'Sadaļa'; +$labels['browseroptions'] = 'Browser Options'; +$labels['section'] = 'Kategorija'; $labels['maintenance'] = 'UzturÄ“Å¡ana'; $labels['newmessage'] = 'VÄ“stuļu pienÄkÅ¡ana'; $labels['signatureoptions'] = 'Paraksta iestatÄ«jumi'; $labels['whenreplying'] = 'Atbildot'; -$labels['replyempty'] = 'neiekļaut vÄ“stules sÄkotnÄ“jo tekstu'; +$labels['replyempty'] = 'do not quote the original message'; $labels['replytopposting'] = 'sÄkt jaunu vÄ“stuli virs oriÄ£inÄla'; $labels['replybottomposting'] = 'sÄkt jaunu vÄ“stuli zem oriÄ£inÄla'; $labels['replyremovesignature'] = 'Atbildot izņemt oriÄ£inÄlo parakstu no vÄ“stules'; $labels['autoaddsignature'] = 'AutomÄtiski pievienot parakstu'; -$labels['newmessageonly'] = 'tikai jaunÄm vÄ“stulÄ“m'; -$labels['replyandforwardonly'] = 'tikai atbildÄ“m un pÄrsÅ«tÄ«jumiem'; +$labels['newmessageonly'] = 'tikai jaunas vÄ“stules'; +$labels['replyandforwardonly'] = 'tikai atbildes un pÄrsÅ«tÄ«jumi'; $labels['insertsignature'] = 'Ievietot parakstu'; $labels['previewpanemarkread'] = 'AtzÄ«mÄ“t priekÅ¡skatÄ«tÄs vÄ“stules kÄ lasÄ«tas'; $labels['afternseconds'] = 'pÄ“c $n sekundÄ“m'; -$labels['reqmdn'] = 'VienmÄ“r pieprasÄ«t saņemÅ¡anas apstiprinÄjumu'; -$labels['reqdsn'] = 'VienmÄ“r pieprasÄ«t atskati par piegÄdi'; +$labels['reqmdn'] = 'VienmÄ“r pieprasÄ«t atskati par vÄ“stules izlasÄ«Å¡anu'; +$labels['reqdsn'] = 'VienmÄ“r pieprasÄ«t atskati par vÄ“stules piegÄdÄÅ¡anu saņēmÄ“ja serverim'; $labels['replysamefolder'] = 'GlabÄt atbildes tajÄ paÅ¡Ä mapÄ“, kurÄ ir vÄ“stule, uz kuru tika atbildÄ“ts'; -$labels['defaultabook'] = 'NoklusÄ“tÄ adreÅ¡u grÄmata'; -$labels['autocompletesingle'] = 'AutomÄtiski aizpildot, nerÄdÄ«t alternatÄ«vÄs e-pasta adreses'; -$labels['listnamedisplay'] = 'RÄdÄ«t kontaktus kÄ'; -$labels['spellcheckbeforesend'] = 'Pirms vÄ“stules nosÅ«tÄ«Å¡anas pÄrbaudÄ«t pareizrakstÄ«bu'; +$labels['defaultabook'] = 'Default address book'; +$labels['autocompletesingle'] = 'AutomÄtiski aizpildot, izlaist alternatÄ«vÄs e-pasta adreses'; +$labels['listnamedisplay'] = 'List contacts as'; +$labels['spellcheckbeforesend'] = 'PÄrbaudÄ«t pareizrakstÄ«bu pirms vÄ“stules nosÅ«tÄ«Å¡anas'; $labels['spellcheckoptions'] = 'PareizrakstÄ«bas iestatÄ«jumi'; $labels['spellcheckignoresyms'] = 'IgnorÄ“t vÄrdus, kuri satur simbolus'; $labels['spellcheckignorenums'] = 'IgnorÄ“t vÄrdus, kuri satur skaitļus'; $labels['spellcheckignorecaps'] = 'IgnorÄ“t vÄrdus, kuri rakstÄ«ti ar lielajiem burtiem'; $labels['addtodict'] = 'Pievienot vÄrdnÄ«cai'; -$labels['mailtoprotohandler'] = 'Atverot mailto: saites, lietot Å¡o e-pasta programmu'; -$labels['standardwindows'] = 'IzlÄ“coÅ¡ie logi kÄ parasti logi'; -$labels['forwardmode'] = 'VÄ“stuļu pÄrsÅ«tÄ«Å¡ana'; -$labels['inline'] = 'iekļaujot'; -$labels['asattachment'] = 'kÄ pielikumu'; +$labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; +$labels['forwardmode'] = 'Messages forwarding'; +$labels['inline'] = 'inline'; +$labels['asattachment'] = 'as attachment'; $labels['folder'] = 'Mapi'; $labels['folders'] = 'Mapes'; @@ -496,8 +491,8 @@ $labels['parentfolder'] = 'Virsmape'; $labels['location'] = 'AtraÅ¡anÄs vieta'; $labels['info'] = 'InformÄcija'; $labels['getfoldersize'] = 'UzklikÅ¡Ä·iniet, lai uzzinÄtu mapes izmÄ“ru'; -$labels['changesubscription'] = 'UzklikÅ¡Ä·iniet, lai mainÄ«tu abonÄ“Å¡anas iestatÄ«jumus'; -$labels['foldertype'] = 'Mapes tips'; +$labels['changesubscription'] = 'UzklikÅ¡Ä·iniet, lai mainÄ«tu abonÄ“Å¡anu'; +$labels['foldertype'] = 'Mapes veids'; $labels['personalfolder'] = 'PrivÄta mape'; $labels['otherfolder'] = 'Cita lietotÄja mape'; $labels['sharedfolder'] = 'Publiska mape'; @@ -507,7 +502,7 @@ $labels['sortasc'] = 'KÄrtot augoÅ¡Ä secÄ«bÄ'; $labels['sortdesc'] = 'KÄrtot dilstoÅ¡Ä secÄ«bÄ'; $labels['undo'] = 'Atsaukt'; -$labels['installedplugins'] = 'UzstÄdÄ«tie spraudņi'; +$labels['installedplugins'] = 'Installed plugins'; $labels['plugin'] = 'Spraudnis'; $labels['version'] = 'Versija'; $labels['source'] = 'OriÄ£inÄls'; @@ -521,7 +516,7 @@ $labels['MB'] = 'MB'; $labels['GB'] = 'GB'; // character sets -$labels['unicode'] = 'Unikods'; +$labels['unicode'] = 'Unikoda'; $labels['english'] = 'Angļu'; $labels['westerneuropean'] = 'Rietumeiropas'; $labels['easterneuropean'] = 'Austrumeiropas'; diff --git a/program/localization/lv_LV/messages.inc b/program/localization/lv_LV/messages.inc index 37ceb0463..b69a73e2b 100644 --- a/program/localization/lv_LV/messages.inc +++ b/program/localization/lv_LV/messages.inc @@ -28,7 +28,7 @@ $messages['dberror'] = 'DatubÄzes kļūda!'; $messages['requesttimedout'] = 'PieprasÄ«jumam iestÄjÄs noilgums'; $messages['errorreadonly'] = 'NeizdevÄs veikt darbÄ«bu: mape ir tikai lasÄma (read only)'; $messages['errornoperm'] = 'NeizdevÄs veikt darbÄ«bu: piekļuve liegta'; -$messages['erroroverquota'] = 'OperÄciju veikt nav iespÄ“jams. Uz diska nav brÄ«vas veitas.'; +$messages['erroroverquota'] = 'OperÄciju nav iespÄ“jams veikt. Uz diska nav brÄ«vas veitas.'; $messages['erroroverquotadelete'] = 'Uz diska nav brÄ«vas vietas. Lai dzÄ“stu vÄ“stuli, lietojiet SHIFT+DEL.'; $messages['invalidrequest'] = 'NederÄ«gs pieprasÄ«jums! Dati netika saglabÄti ...'; $messages['invalidhost'] = 'NederÄ«gs servera nosaukums'; @@ -45,7 +45,7 @@ $messages['sendingmessage'] = 'Tiek sÅ«tÄ«ta vÄ“stule ...'; $messages['messagesent'] = 'VÄ“stule nosÅ«tÄ«ta veiksmÄ«gi'; $messages['savingmessage'] = 'VÄ“stule tiek saglabÄta ...'; $messages['messagesaved'] = 'VÄ“stule saglabÄta Uzmetumos'; -$messages['successfullysaved'] = 'VeiksmÄ«gi saglabÄts.'; +$messages['successfullysaved'] = 'VÄ“stule veiksmÄ«gi saglabÄta'; $messages['addedsuccessfully'] = 'Kontakts veiksmÄ«gi pievienots adreÅ¡u grÄmatai'; $messages['contactexists'] = 'Kontakts ar Å¡Ädu e-pasta adresi jau eksistÄ“'; $messages['contactnameexists'] = 'Kontakts ar Å¡Ädu vÄrdu jau eksistÄ“.'; @@ -100,74 +100,72 @@ $messages['deletedsuccessfully'] = 'VeiksmÄ«gi izdzÄ“sts'; $messages['converting'] = 'Tiek noņemts vÄ“stules formatÄ“jums...'; $messages['messageopenerror'] = 'NevarÄ“ja ielÄdÄ“t vÄ“stuli no servera'; $messages['fileuploaderror'] = 'Faila augÅ¡upielÄde neveiksmÄ«ga'; -$messages['filesizeerror'] = 'AugÅ¡upielÄdÄ“tais fails pÄrsniedz pieļaujamo $size izmÄ“ru.'; -$messages['copysuccess'] = 'VeiksmÄ«gi nokopÄ“tas $nr adreses.'; -$messages['copyerror'] = 'NevarÄ“ja nokopÄ“t nevienu adresi.'; +$messages['filesizeerror'] = 'IelÄdÄ“tais fails pÄrsniedz pieļaujamo $size apjomu'; +$messages['copysuccess'] = 'VeiksmÄ«gi nokopÄ“tas $nr vÄ“stules'; +$messages['copyerror'] = 'NevarÄ“ja nokopÄ“t nevienu adresi'; $messages['sourceisreadonly'] = 'Adreses avots ir lasÄ«Å¡anas režīmÄ tikai'; -$messages['errorsavingcontact'] = 'Kontakta adresi nevarÄ“ja saglabÄt.'; -$messages['movingmessage'] = 'PÄrvieto vÄ“stules...'; +$messages['errorsavingcontact'] = 'NevarÄ“ja saglabÄt kontakta adreses'; +$messages['movingmessage'] = 'PÄrvietoju vÄ“stules...'; $messages['copyingmessage'] = 'KopÄ“ vÄ“stules...'; $messages['copyingcontact'] = 'KopÄ“ kontaktus...'; $messages['deletingmessage'] = 'DzÄ“Å¡ vÄ“stules...'; $messages['markingmessage'] = 'AtzÄ«mÄ“ vÄ“stules...'; -$messages['addingmember'] = 'Kontaktus pievieno grupai...'; -$messages['removingmember'] = 'Kontaktus atvieno no grupas...'; -$messages['receiptsent'] = 'SaņemÅ¡anas apstiprinÄjums nosÅ«tÄ«ts veiksmÄ«gi.'; -$messages['errorsendingreceipt'] = 'NeizdevÄs nosÅ«tÄ«t saņemÅ¡anas apstiprinÄjumu.'; -$messages['deleteidentityconfirm'] = 'Vai JÅ«s tieÅ¡Äm vÄ“laties dzÄ“st Å¡o identitÄti?'; -$messages['nodeletelastidentity'] = 'Å o identitÄti nav iespÄ“jams izdzÄ“st, jo tÄ ir pati pÄ“dÄ“jÄ.'; -$messages['forbiddencharacter'] = 'Mapes nosaukums satur aizliegtus simbolus.'; -$messages['selectimportfile'] = 'LÅ«dzu norÄdiet failu, kuru vÄ“laties augÅ¡upielÄdÄ“t.'; -$messages['addresswriterror'] = 'IzvÄ“lÄ“tÄs adreÅ¡u grÄmatas datus nav iespÄ“jams rediģēt.'; +$messages['addingmember'] = 'Pievieno kontaktu(s) grupai...'; +$messages['removingmember'] = 'Atvieno kontaktu(s) no grupas...'; +$messages['receiptsent'] = 'SaņemÅ¡anas apstiprinÄjums nosÅ«tÄ«ts'; +$messages['errorsendingreceipt'] = 'NeizdevÄs nosÅ«tÄ«t apstiprinÄjumu'; +$messages['deleteidentityconfirm'] = 'Vai tieÅ¡Äm vÄ“laties dzÄ“st Å¡o identitÄti?'; +$messages['nodeletelastidentity'] = 'Å o identitÄti nevar izdzÄ“st, tÄ ir pati pÄ“dÄ“jÄ.'; +$messages['forbiddencharacter'] = 'Mapes nosaukums satur aizliegtus simbolus'; +$messages['selectimportfile'] = 'LÅ«dzu izvÄ“lieties failu, ko vÄ“laties augÅ¡upielÄdÄ“t'; +$messages['addresswriterror'] = 'IzvÄ“lÄ“tÄs adreÅ¡u grÄmatas datus nevar labot'; $messages['contactaddedtogroup'] = 'Kontakti tika veiksmÄ«gi pievienoti Å¡ai grupai.'; $messages['contactremovedfromgroup'] = 'Kontakti tika veiksmÄ«gi atvienoti no Å¡Ä«s grupas.'; $messages['nogroupassignmentschanged'] = 'GrupÄ nekas netika mainÄ«ts.'; $messages['importwait'] = 'ImportÄ“ju, lÅ«dzu uzgaidiet...'; $messages['importformaterror'] = 'Imports neizdevÄs! AugÅ¡upielÄdÄ“tais fails nav derÄ«gs importam.'; -$messages['importconfirm'] = '<b>VeiksmÄ«gi ieimportÄ“ti $inserted kontakti</b>'; +$messages['importconfirm'] = '<b>VeiksmÄ«gi ieimportÄ“ti $inserted kontakti, netika importÄ“ti $skipped esoÅ¡i ieraksti</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Izlaida $skipped jau eksistÄ“joÅ¡us ierakstus</b>'; -$messages['importmessagesuccess'] = 'VeiksmÄ«gi ieimportÄ“tas $nr vÄ“stules'; -$messages['importmessageerror'] = 'ImportÄ“Å¡anas kļūda! AugÅ¡upielÄdÄ“tÄ datne satur nekorektus datus'; $messages['opnotpermitted'] = 'DarbÄ«ba nav atļauta!'; -$messages['nofromaddress'] = 'IzvÄ“lÄ“tajai identitÄtei nav norÄdÄ«ta e-pasta adrese.'; -$messages['editorwarning'] = 'PÄrslÄ“dzoties uz vienkÄrÅ¡otu teksta redaktoru, tiks pazaudÄ“ts esoÅ¡ais teksta formatÄ“jums. Vai tieÅ¡Äm vÄ“laties turpinÄt?'; -$messages['httpreceivedencrypterror'] = 'Notika kritiska kļūme. LÅ«dzu nekavÄ“joties sazinieties ar JÅ«su administratoru. <b>JÅ«su vÄ“stuli nosÅ«tÄ«t nav iespÄ“jams.</b>'; +$messages['nofromaddress'] = 'IzvÄ“lÄ“tajai identitÄtei nav norÄdÄ«ta e-pasta adrese'; +$messages['editorwarning'] = 'PÄrslÄ“dzoties uz vienkÄrÅ¡otu teksta redaktoru, tiks pazaudÄ“ts esoÅ¡ais teksta formatÄ“jums. Vai vÄ“laties turpinÄt?'; +$messages['httpreceivedencrypterror'] = 'Kļūme. LÅ«dzu sazinieties ar administratoru. <b>Nav iespÄ“jams nosÅ«tÄ«t vÄ“stuli.</b>'; $messages['smtpconnerror'] = 'SMTP kļūme ($code): NeizdevÄs pieslÄ“gties serverim'; -$messages['smtpautherror'] = 'SMTP kļūda ($code): NeizdevÄs autorizÄ“ties.'; -$messages['smtpfromerror'] = 'SMTP kļūda ($code): NeizdevÄs iestatÄ«t sÅ«tÄ«tÄju "$from" ($msg).'; -$messages['smtptoerror'] = 'SMTP kļūda ($code): NeizdevÄs pievienot saņēmÄ“ju "$to" ($msg).'; -$messages['smtprecipientserror'] = 'SMTP kļūda: Nav iespÄ“jams aptrÄdÄt saņēmÄ“ju sarakstu.'; -$messages['smtperror'] = 'SMTP kļūda: $msg'; +$messages['smtpautherror'] = 'SMTP kļūme ($code): NeizdevÄs autentificÄ“ties'; +$messages['smtpfromerror'] = 'SMTP kļūme ($code): NeizdevÄs iestatÄ«t sÅ«tÄ«tÄju "$from" ($msg)'; +$messages['smtptoerror'] = 'SMTP kļūme ($code): NeizdevÄs pievienot saņēmÄ“ju "$to" ($msg)'; +$messages['smtprecipientserror'] = 'SMTP kļūme: Nav iespÄ“jams parsÄ“t saņēmÄ“ju sarakstu'; +$messages['smtperror'] = 'SMTP kļūme: $msg'; $messages['emailformaterror'] = 'Nepareiza e-pasta adrese: $email'; $messages['toomanyrecipients'] = 'PÄrÄk daudz saņēmÄ“ju. Samaziniet skaitu lÄ«dz $max.'; $messages['maxgroupmembersreached'] = 'Grupas dalÄ«bnieku skaits pÄrsniedz limitu $max.'; -$messages['internalerror'] = 'Notika servera iekÅ¡Ä“jÄ kļūda. LÅ«dzu mÄ“Ä£iniet vÄ“lreiz.'; -$messages['contactdelerror'] = 'Kontaktus izdzÄ“st neizdevÄs.'; -$messages['contactdeleted'] = 'Kontakti izdzÄ“sti veiksmÄ«gi.'; -$messages['contactrestoreerror'] = 'IzdzÄ“stos kontaktus atjaunot neizdevÄs.'; -$messages['contactrestored'] = 'Kontakti atjaunoti veiksmÄ«gi.'; -$messages['groupdeleted'] = 'Grupa izdzÄ“sta veiksmÄ«gi.'; -$messages['grouprenamed'] = 'Grupa pÄrdÄ“vÄ“ta veiksmÄ«gi.'; -$messages['groupcreated'] = 'Grupa izveidota veiksmÄ«gi.'; -$messages['savedsearchdeleted'] = 'SaglabÄtais meklÄ“Å¡anas pieprasÄ«jums izdzÄ“sts veiksmÄ«gi.'; -$messages['savedsearchdeleteerror'] = 'SaglabÄto meklÄ“Å¡anas pieprasÄ«jumu izdzÄ“st neizdevÄs.'; -$messages['savedsearchcreated'] = 'SaglabÄtais meklÄ“Å¡anas pieprasÄ«jums saglabÄts veiksmÄ«gi.'; -$messages['savedsearchcreateerror'] = 'MeklÄ“Å¡anas pieprasÄ«jumu izveidot neizdevÄs.'; +$messages['internalerror'] = 'Servera iekÅ¡Ä“jÄ kļūda. LÅ«dzu mÄ“Ä£iniet vÄ“lreiz.'; +$messages['contactdelerror'] = 'NeizdevÄs izdzÄ“st kontaktu(s).'; +$messages['contactdeleted'] = 'Kontakti veiksmÄ«gi izdzÄ“sti.'; +$messages['contactrestoreerror'] = 'NeizdevÄs atjaunot izdzÄ“stos kontaktus.'; +$messages['contactrestored'] = 'Kontakti veiksmÄ«gi atjaunoti.'; +$messages['groupdeleted'] = 'Grupa veiksmÄ«gi izdzÄ“sta.'; +$messages['grouprenamed'] = 'Grupa veiksmÄ«gi pÄrdÄ“vÄ“ta.'; +$messages['groupcreated'] = 'Grupa veiksmÄ«gi izveidota.'; +$messages['savedsearchdeleted'] = 'SaglabÄtais meklÄ“Å¡anas pieprasÄ«jums veiksmÄ«gi dzÄ“sts.'; +$messages['savedsearchdeleteerror'] = 'NeizdevÄs nodzÄ“st saglabÄto meklÄ“Å¡anas pieprasÄ«jumu.'; +$messages['savedsearchcreated'] = 'SaglabÄtais meklÄ“Å¡anas pieprasÄ«jums veiksmÄ«gi saglabÄts.'; +$messages['savedsearchcreateerror'] = 'NeizdevÄs saglabÄt meklÄ“Å¡anas pieprasÄ«jumu.'; $messages['messagedeleted'] = 'VÄ“stule(s) veiksmÄ«gi izdzÄ“sta(s).'; $messages['messagemoved'] = 'VÄ“stule(s) veiksmÄ«gi pÄrvietota(s).'; $messages['messagecopied'] = 'VÄ“stule(s) veiksmÄ«gi pÄrkopÄ“ta(s).'; -$messages['messagemarked'] = 'VÄ“stule(s) veiksmÄ«gi atzÄ«mÄ“ta(s).'; -$messages['autocompletechars'] = 'Lai automÄtiski meklÄ“tu, ievadiet vismaz $min burtus.'; -$messages['autocompletemore'] = 'Atrasti vairÄki ieraksti. Papildiniet meklÄ“Å¡anas kritÄ“riju ar vairÄk burtiem.'; +$messages['messagemarked'] = 'VÄ“stule(s) veiksmÄ«gi iezÄ«mÄ“ta(s).'; +$messages['autocompletechars'] = 'Ievadiet vismaz $min burtus, lai meklÄ“tu automÄtiski.'; +$messages['autocompletemore'] = 'Atrasti vairÄki ieraksti. Papildiniet meklÄ“Å¡anas kritÄ“riju.'; $messages['namecannotbeempty'] = 'LÅ«dzu ievadiet vÄrdu.'; -$messages['nametoolong'] = 'VÄrds ir pÄrÄk garÅ¡.'; +$messages['nametoolong'] = 'VÄrds ir par garu.'; $messages['folderupdated'] = 'Mape vieksmÄ«gi atjaunota.'; $messages['foldercreated'] = 'Mape veiksmÄ«gi izveidota.'; $messages['invalidimageformat'] = 'NederÄ«gs attÄ“la formÄts.'; $messages['mispellingsfound'] = 'VÄ“stulÄ“ atrastas pareizrakstÄ«bas kļūdas.'; -$messages['parentnotwritable'] = 'NeizdevÄs izveidot/pÄrvietot mapi atzÄ«mÄ“tajÄ virsmapÄ“. Nav piekļuves tiesÄ«bu.'; -$messages['messagetoobig'] = 'VÄ“stule daļa ir pÄrÄk liela, lai to varÄ“tu apstrÄdÄt.'; +$messages['parentnotwritable'] = 'NeizdevÄs izveidot/pÄrvietot mapi uz atzÄ«mÄ“to virsmapi. Nav piekļuves tiesÄ«bu.'; +$messages['messagetoobig'] = 'VÄ“stule ir pÄrÄk liela, lai to varÄ“tu apstrÄdÄt.'; $messages['attachmentvalidationerror'] = 'BRĪDINÄ€JUMS! Å is pielikums ir aizdomÄ«gs, jo tÄ tips neatbilst tipam, kurÅ¡ ir uzrÄdÄ«ts e-pasta ziņojumÄ. Ja jÅ«s neuzticaties sÅ«tÄ«tÄjam, Å¡o failu Jums vaÄ¼Ä vÄ“rt nevajadzÄ“tu, jo tas var saturÄ“t ļaunprÄtÄ«gu saturu. <br/><br/><em>BÅ«tu jÄbÅ«t: $expected; Bet ir: $detected</em>'; -$messages['noscriptwarning'] = 'UzmanÄ«bu: lai lasÄ«tu e-pastus, JÅ«su pÄrlÅ«kprogrammÄ jÄbÅ«t ieslÄ“gtiem JavaScript.'; +$messages['noscriptwarning'] = 'UzmanÄ«bu: lai lasÄ«tu e-pastus, JÅ«su tÄ«mekļa pÄrlÅ«kÄ jÄbÅ«t iespÄ“jotiem JavaScript.'; ?> diff --git a/program/localization/mk_MK/labels.inc b/program/localization/mk_MK/labels.inc index 519df5823..bb9606e6a 100755..100644 --- a/program/localization/mk_MK/labels.inc +++ b/program/localization/mk_MK/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Ðепратени'; $labels['sent'] = 'Пратени'; $labels['trash'] = 'Корпа'; $labels['junk'] = 'Ѓубре'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ÐаÑлов'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Компактно'; $labels['empty'] = 'ИÑпразни'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ИÑкориÑтен проÑтор'; $labels['unknown'] = 'непознато'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Ðово пребарување'; $labels['searchmod'] = 'Модификатори на пребарувањето'; $labels['msgtext'] = 'Цело пиÑмо'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Отвори во нов прозорец'; $labels['emlsave'] = 'Преземи (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Прикажи ја поÑледната Ñтран $labels['group'] = 'Group'; $labels['groups'] = 'Групи'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Лични адреÑи'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/mk_MK/messages.inc b/program/localization/mk_MK/messages.inc index 7a7548ce0..f7a8d9a12 100755..100644 --- a/program/localization/mk_MK/messages.inc +++ b/program/localization/mk_MK/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Форматирањето на пиÑмото е Ð¾Ñ $messages['messageopenerror'] = 'Ðе можев да го вчитам пиÑното од Ñерверот'; $messages['fileuploaderror'] = 'Прикачувањето е неуÑпешно'; $messages['filesizeerror'] = 'Подигнатата податотека го надминува ограничувањето од $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'УÑпешно Ñе копирани $nr имиња'; +$messages['copyerror'] = 'Ðе можам да ги копирам адреÑите'; $messages['sourceisreadonly'] = 'Изворот на оваа адреÑа неможе да Ñе промени'; $messages['errorsavingcontact'] = 'Името неможе да Ñе Ñними'; $messages['movingmessage'] = 'Пораката Ñе премеÑтува...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Убезувам,, почекајте...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>УÑпешно Ñе увезени $inserted имиња, $skipped веќе поÑтојат и Ñе преÑкокнати</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Операцијата не е дозволена'; $messages['nofromaddress'] = 'Ðе е внеÑена е-пошта во одберениот идентитет'; $messages['editorwarning'] = 'Префрлањето на уредникот на обичен текÑÑ‚ ќе резултира Ñо губење на целото форматирање на текÑтот. Дали Ñакате да продолжите?'; diff --git a/program/localization/ml_IN/labels.inc b/program/localization/ml_IN/labels.inc index 7d3fdc501..ed0e7402a 100644 --- a/program/localization/ml_IN/labels.inc +++ b/program/localization/ml_IN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'പൂരàµâ€à´¤àµà´¤à´¿à´¯à´¾à´•à´¾à´¤àµà´¤à´µ'; $labels['sent'] = 'അയചàµà´šà´µ'; $labels['trash'] = 'ചവറàµà´±àµà´•àµà´Ÿàµà´Ÿ'; $labels['junk'] = 'ആവശàµà´¯à´®à´¿à´²àµà´²à´¾à´¤àµà´¤à´µ'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'വിഷയം'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'à´šàµà´°àµà´•àµà´•àµ'; $labels['empty'] = 'ശൂനàµà´¯à´‚'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'à´¡à´¿à´¸àµà´•àµà´•àµ ഉപയോഗം'; $labels['unknown'] = 'അറിയാതàµà´¤'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Reset search'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'à´®àµà´´àµà´µà´¨àµâ€ സനàµà´¦àµ‡à´¶à´µàµà´‚'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'à´ªàµà´¤à´¿à´¯ വിനàµâ€à´¡àµ‹à´¯à´¿à´²àµâ€ à´¤àµà´±à´•àµà´•àµà´•'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'കൂടàµà´Ÿà´‚'; $labels['groups'] = 'കൂടàµà´Ÿà´™àµà´™à´³àµâ€'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'à´¸àµà´µà´•à´¾à´°àµà´¯ വിലാസങàµà´™à´³àµâ€'; $labels['searchsave'] = 'തിരയലàµâ€ സൂകàµà´·à´¿à´•àµà´•àµà´•'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'à´…à´•àµà´•à´™àµà´™à´³àµâ€ ഉളàµà´³ à $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'നിഘണàµà´Ÿàµà´µà´¿à´²àµâ€ ചേരàµâ€à´•àµà´•àµà´•'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ml_IN/messages.inc b/program/localization/ml_IN/messages.inc index cc189a17d..28eb22be2 100644 --- a/program/localization/ml_IN/messages.inc +++ b/program/localization/ml_IN/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removing formatting...'; $messages['messageopenerror'] = 'Could not load message from server.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Successfully copied $nr addresses.'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'This address source is read only.'; $messages['errorsavingcontact'] = 'Could not save the contact address.'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/mr_IN/labels.inc b/program/localization/mr_IN/labels.inc index d26583d4d..02b129e0b 100755..100644 --- a/program/localization/mr_IN/labels.inc +++ b/program/localization/mr_IN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'मसà¥à¤¦à¤¾'; $labels['sent'] = 'पाठवलेले'; $labels['trash'] = 'कचरा पेटी'; $labels['junk'] = 'नको असलेले कचरा संदेश'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'विषय'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'यादी दरà¥à¤¶à¤• पधà¥â€à¤¦à¤¤'; $labels['folderactions'] = 'फोलà¥à¤¡à¤° कृती..'; $labels['compact'] = 'छोटा'; $labels['empty'] = 'रिकामा'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'डिसà¥à¤•à¤šà¤¾ वापर'; $labels['unknown'] = 'माहित नसलेला'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'परत शोध'; $labels['searchmod'] = 'बदलकरà¥à¤¤à¥â€à¤¯à¤¾à¤‚ना शोधा'; $labels['msgtext'] = 'संपूरà¥à¤£ संदेश'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'नवीन खिडकी उघडा'; $labels['emlsave'] = 'इà¤à¤®à¤à¤² सà¥â€à¤µà¤°à¥‚पात उतरवून घà¥à¤¯à¤¾'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'शेवटचा संच दाखवा'; $labels['group'] = 'गट'; $labels['groups'] = 'अनेक गट'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'वैयकà¥à¤¤à¤¿à¤• पतà¥à¤¤à¥‡'; $labels['searchsave'] = 'शोध जतन करा'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/mr_IN/messages.inc b/program/localization/mr_IN/messages.inc index 2b1bd3f33..bc4097fb5 100755..100644 --- a/program/localization/mr_IN/messages.inc +++ b/program/localization/mr_IN/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'दृषà¥à¤¯ सà¥à¤µà¤°à¥à¤ª काढून ठ$messages['messageopenerror'] = 'सरà¥à¤µà¥à¤¹à¤°à¤µà¤°à¥à¤¨ संदेश आणता आला नाही.'; $messages['fileuploaderror'] = 'फाईल चढवता आली नाही'; $messages['filesizeerror'] = 'तà¥à¤®à¥à¤¹à¥€ चढवलेली फाईल कà¥à¤·à¤®à¤¤à¥‡à¤ªà¥‡à¤•à¥à¤·à¤¾ जासà¥à¤¤ मोठी आहे.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr पतà¥à¤¤à¥à¤¯à¤¾à¤‚ची यशसà¥à¤µà¥€à¤°à¤¿à¤¤à¥à¤¯à¤¾ पà¥à¤°à¤¤ केली.'; +$messages['copyerror'] = 'कोणतà¥à¤¯à¤¾à¤¹à¥€ पतà¥à¤¤à¥à¤¯à¤¾à¤šà¥€ पà¥à¤°à¤¤ बनवता आली नाही.'; $messages['sourceisreadonly'] = 'पतà¥à¤¤à¤¾ फकà¥à¤¤ वाचणà¥à¤¯à¤¾à¤¸à¤¾à¤ ी आहे.'; $messages['errorsavingcontact'] = 'पतà¥à¤¤à¤¾ नोंदवहीत ठेवता आला नाही.'; $messages['movingmessage'] = 'संदेश हलवत आहे..'; $messages['copyingmessage'] = 'संदेशाची नकà¥â€à¤•à¤² करत आहे...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'आयात करत आहे, कृपया व $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>$inserted पतà¥à¤¤à¥‡ यशसà¥à¤µà¥€à¤°à¤¿à¤¤à¥à¤¯à¤¾ आयात केल, $skipped आधिच असलेलà¥à¤¯à¤¾ नोंदी केलà¥à¤¯à¤¾ नाहीत</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'ही कà¥à¤°à¤¿à¤¯à¤¾ करणà¥à¤¯à¤¾à¤¸ परवानगी नाही.'; $messages['nofromaddress'] = 'निवडलेलà¥à¤¯à¤¾ खातà¥à¤¯à¤¾à¤¤ इमेल पतà¥à¤¤à¤¾ दिलेला नाही.'; $messages['editorwarning'] = 'टेकà¥à¤¸à¥à¤Ÿ संपादन निवडलà¥à¤¯à¤¾à¤¸ संदेशाचे दृषà¥à¤¯ सà¥à¤µà¤°à¥à¤ª बदलून जाईल. तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ असेच करायचे आहे ना?'; diff --git a/program/localization/ms_MY/labels.inc b/program/localization/ms_MY/labels.inc index a6bdfbfa0..318af05ad 100644 --- a/program/localization/ms_MY/labels.inc +++ b/program/localization/ms_MY/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Draf'; $labels['sent'] = 'Hantar'; $labels['trash'] = 'Tong Sampah'; $labels['junk'] = 'Junk'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Subjek'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Mod senarai paparan'; $labels['folderactions'] = 'Aksi folder'; $labels['compact'] = 'Kompak'; $labels['empty'] = 'Kosong'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Penggunaan cakera'; $labels['unknown'] = 'tidak diketahui'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Set semula carian'; $labels['searchmod'] = 'Pengubah carian'; $labels['msgtext'] = 'Keseluruhan mesej'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Buka dalam tetingkap baru'; $labels['emlsave'] = 'Muat-turun (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Papar set akhir'; $labels['group'] = 'Group'; $labels['groups'] = 'Kumpulan'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Alamat-alamat Peribadi'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ms_MY/messages.inc b/program/localization/ms_MY/messages.inc index 50f10af13..72d2e3075 100644 --- a/program/localization/ms_MY/messages.inc +++ b/program/localization/ms_MY/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Singkir format dari mesej...'; $messages['messageopenerror'] = 'Tidak boleh muat mesej dari server'; $messages['fileuploaderror'] = 'Muatnaik fail gagal'; $messages['filesizeerror'] = 'Fail yang dimuatnaik melampaui saiz maksima $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Berjaya salin alamat-alamat $nr'; +$messages['copyerror'] = 'Tidak boleh salin apa-apa alamat'; $messages['sourceisreadonly'] = 'Sumber alamat ini adalah untuk bacaan sahaja'; $messages['errorsavingcontact'] = 'Tidak boleh simmpan alamat kontek'; $messages['movingmessage'] = 'Memindah mesej...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/nb_NO/labels.inc b/program/localization/nb_NO/labels.inc index b5c8ce4c6..cba58dc9c 100644 --- a/program/localization/nb_NO/labels.inc +++ b/program/localization/nb_NO/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Kladd'; $labels['sent'] = 'Sendt'; $labels['trash'] = 'Slettet'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Emne'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Listevisningsmodus'; $labels['folderactions'] = 'Mappehandlinger...'; $labels['compact'] = 'Rydd opp'; $labels['empty'] = 'Tøm'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Plassforbruk'; $labels['unknown'] = 'ukjent'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Nullstill søk'; $labels['searchmod'] = 'Søke felt'; $labels['msgtext'] = 'Hele meldingen'; $labels['body'] = 'Meldingstekst'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Ã…pne i nytt vindu'; $labels['emlsave'] = 'Last ned (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Vis siste sett'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Grupper'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Egne adresser'; $labels['searchsave'] = 'Lagre søk'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorer ord med tall'; $labels['spellcheckignorecaps'] = 'Ignorer ord med kun store bokstaver'; $labels['addtodict'] = 'Legg til i ordbok'; $labels['mailtoprotohandler'] = 'Registrer protokollhÃ¥ndtering for mailto-lenker'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Meldinger videresendes'; $labels['inline'] = 'i teksten'; $labels['asattachment'] = 'som vedlegg'; diff --git a/program/localization/nb_NO/messages.inc b/program/localization/nb_NO/messages.inc index 6138b9379..7785f474a 100644 --- a/program/localization/nb_NO/messages.inc +++ b/program/localization/nb_NO/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Fjerner formatering fra meldingen ...'; $messages['messageopenerror'] = 'Kunne ikke hente meldingen fra server'; $messages['fileuploaderror'] = 'Feil under opplastning.'; $messages['filesizeerror'] = 'Filen overstiger maksimum tillatt filstørrelse ($size)'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Kopierte $nr adresser.'; +$messages['copyerror'] = 'Kunne ikke kopiere adresser.'; $messages['sourceisreadonly'] = 'Denne adressekilden er skrivebeskyttet'; $messages['errorsavingcontact'] = 'Kunne ikke lagre kontaktadressen.'; $messages['movingmessage'] = 'Flytter e-post ...'; $messages['copyingmessage'] = 'Kopierer e-post...'; $messages['copyingcontact'] = 'Kopierer kontakt(er) …'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Sletter melding(er) …'; $messages['markingmessage'] = 'Markerer melding(er) ...'; $messages['addingmember'] = 'Legger til kontakt(er) i gruppa ...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importerer, vennligst vent...'; $messages['importformaterror'] = 'Import feilet! Den opplastede filen er i feil format.'; $messages['importconfirm'] = '<b>Importerte $inserted kontakter</b>'; $messages['importconfirmskipped'] = '<b>Hoppet over $skipped eksisterende oppføringer</b>'; -$messages['importmessagesuccess'] = 'Kopierte $nr meldinger'; -$messages['importmessageerror'] = 'Importeringen var mislykket! Den opplastede filen er ikke en gyldig melding, eller er ikke kompatibel med meldingssystemet.'; $messages['opnotpermitted'] = 'Handling ikke tillatt!'; $messages['nofromaddress'] = 'E-postadresse mangler i valgt identitet'; $messages['editorwarning'] = 'Ved Ã¥ bytte format til ren tekst vil all tekstformatering gÃ¥ tapt. Ønsker du Ã¥ fortsette?'; diff --git a/program/localization/ne_NP/labels.inc b/program/localization/ne_NP/labels.inc index 5f69e1916..29d43ef9c 100644 --- a/program/localization/ne_NP/labels.inc +++ b/program/localization/ne_NP/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'डà¥à¤°à¤¾à¤«à¥à¤Ÿà¤¹à¤°à¥‚'; $labels['sent'] = 'पठईà¤à¤•à¤¾ मेलहरà¥'; $labels['trash'] = 'रदà¥à¤¦à¥€ टोकरी'; $labels['junk'] = 'सà¥à¤ªà¤¾à¤®'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'विषय'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'छोटो गरà¥à¤¨à¥à¤¹à¥‹à¤¸'; $labels['empty'] = 'खाली गरà¥à¤¨à¥‡'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'डिसà¥à¤•à¤•à¥‹ उपà¤à¥‹à¤—'; $labels['unknown'] = 'अजà¥à¤žà¤¾à¤¤'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'पन: खोज'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'अनà¥à¤¤à¤¿à¤® सेट देखाउनà¥à $labels['group'] = 'Group'; $labels['groups'] = 'समूहहरà¥'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'वà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त ठेगानाहरà¥'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ne_NP/messages.inc b/program/localization/ne_NP/messages.inc index bedf41d8d..c5214bb0f 100644 --- a/program/localization/ne_NP/messages.inc +++ b/program/localization/ne_NP/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'मेलबाट फोरà¥à¤®à¤¾à¤Ÿà¤¿à¤™ हट $messages['messageopenerror'] = 'सरà¥à¤µà¤°à¤¬à¤¾à¤Ÿ मेल लोड हà¥à¤¨ सकेन'; $messages['fileuploaderror'] = 'फाईल अपलोड हà¥à¤¨ असफल'; $messages['filesizeerror'] = 'अपलोड गरिà¤à¤•à¥‹ फाईल हद $size à¤à¤¨à¥à¤¦à¤¾ ठूलो छ'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'सफलà¥à¤¤à¤¾à¤ªà¥‚रà¥à¤µà¤• $nr ठेगानाहरॠउतारियो'; +$messages['copyerror'] = 'कà¥à¤¨à¥ˆ पनि ठेगानाहरॠउतारà¥à¤¨ सकिà¤à¤¨'; $messages['sourceisreadonly'] = 'यो ठेगाना को शà¥à¤°à¥‹à¤¤ पढà¥à¤¨à¤•à¥‹ लागि मातà¥à¤° उपलबà¥à¤§ छ'; $messages['errorsavingcontact'] = 'सà¥à¤®à¤ªà¤°à¥à¤•à¤•à¥‹ ठेगाना जोगाउन सकिà¤à¤¨'; $messages['movingmessage'] = 'Moving message(s)...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/nl_BE/labels.inc b/program/localization/nl_BE/labels.inc index 1e6bb2d2f..eb44eefc0 100644 --- a/program/localization/nl_BE/labels.inc +++ b/program/localization/nl_BE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Concepten'; $labels['sent'] = 'Verzonden berichten'; $labels['trash'] = 'Prullenbak'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Onderwerp'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Lijstweergave mode'; $labels['folderactions'] = 'Acties voor map...'; $labels['compact'] = 'Comprimeren'; $labels['empty'] = 'Legen'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Gebruikte schijfruimte'; $labels['unknown'] = 'onbekend'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Zoek opnieuw'; $labels['searchmod'] = 'Zoekopties'; $labels['msgtext'] = 'Volledig bericht'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Openen in een nieuw venster'; $labels['emlsave'] = 'Opslaan (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Toon laatste'; $labels['group'] = 'Groep'; $labels['groups'] = 'Groepen'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personlijke adressen'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/nl_BE/messages.inc b/program/localization/nl_BE/messages.inc index f7ed8e8d4..d87329dc3 100644 --- a/program/localization/nl_BE/messages.inc +++ b/program/localization/nl_BE/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Opmaak van het bericht wordt gewist...'; $messages['messageopenerror'] = 'Kon het bericht niet ophalen van de server.'; $messages['fileuploaderror'] = 'Bestandsupload mislukt.'; $messages['filesizeerror'] = 'Het bestand overschrijdt de maximum grootte van $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr adressen met succes gekopieerd.'; +$messages['copyerror'] = 'Kon de adressen niet kopiëren.'; $messages['sourceisreadonly'] = 'Het adres kan niet worden opgeslagen.'; $messages['errorsavingcontact'] = 'Kon de contactpersoon niet bewaren.'; $messages['movingmessage'] = 'Bericht wordt verplaatst...'; $messages['copyingmessage'] = 'Bericht wordt gekopieerd...'; $messages['copyingcontact'] = 'Kopiëren contactpersonen...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Bericht wordt verwijderd...'; $messages['markingmessage'] = 'Bericht wordt gemarkeerd...'; $messages['addingmember'] = 'Contactpersonen worden toegevoegd aan de groep...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Bezig met importeren, even geduld...'; $messages['importformaterror'] = 'Importeren mislukt! Het geüploade bestand is geen importeerbaar bestand.'; $messages['importconfirm'] = '<b>Er zijn $inserted contactpersonen succesvol geïmporteerd</b>'; $messages['importconfirmskipped'] = '<b>$skipped bestaande contactpersonen overgeslagen</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Deze actie is niet toegestaan!'; $messages['nofromaddress'] = 'De geselecteerde identiteit bevat geen emailadres.'; $messages['editorwarning'] = 'Door het overschakelen naar de platte tekst editor gaat alle opmaak verloren. Weet u zeker dat u verder wilt gaan?'; diff --git a/program/localization/nl_NL/labels.inc b/program/localization/nl_NL/labels.inc index 8a6f994fa..7bd48bd4a 100644 --- a/program/localization/nl_NL/labels.inc +++ b/program/localization/nl_NL/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Concepten'; $labels['sent'] = 'Verzonden'; $labels['trash'] = 'Prullenbak'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Toon echte namen voor speciale mappen'; // message listing $labels['subject'] = 'Onderwerp'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Lijstweergave'; $labels['folderactions'] = 'Mapacties...'; $labels['compact'] = 'Opschonen'; $labels['empty'] = 'Legen'; -$labels['importmessages'] = 'Berichten importeren'; $labels['quota'] = 'Opslagverbruik'; $labels['unknown'] = 'onbekend'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Wis zoekopdracht'; $labels['searchmod'] = 'Zoekopties'; $labels['msgtext'] = 'Gehele bericht'; $labels['body'] = 'Inhoud'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Openen in een nieuw venster'; $labels['emlsave'] = 'Opslaan (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Laatste pagina'; $labels['group'] = 'Groep'; $labels['groups'] = 'Groepen'; -$labels['listgroup'] = 'Toon groepsleden'; $labels['personaladrbook'] = 'Persoonlijk adresboek'; $labels['searchsave'] = 'Zoekopdracht opslaan'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Negeer woorden met cijfers'; $labels['spellcheckignorecaps'] = 'Negeer woorden welke volledig uit hoofdletters bestaan'; $labels['addtodict'] = 'Voeg toe aan woordenboek'; $labels['mailtoprotohandler'] = 'Registreer protocolhandler voor mailto: links'; -$labels['standardwindows'] = 'Behandel pop-ups als normale vensters'; $labels['forwardmode'] = 'Berichten doorsturen'; $labels['inline'] = 'invoegen'; $labels['asattachment'] = 'als bijlage'; diff --git a/program/localization/nl_NL/messages.inc b/program/localization/nl_NL/messages.inc index 01c43b243..4a67e1590 100644 --- a/program/localization/nl_NL/messages.inc +++ b/program/localization/nl_NL/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Opmaak van bericht verwijderen...'; $messages['messageopenerror'] = 'Kan het bericht niet van de server laden.'; $messages['fileuploaderror'] = 'Bestand uploaden mislukt.'; $messages['filesizeerror'] = 'Het bestand overschrijdt de maximale grootte van $size.'; -$messages['copysuccess'] = '$nr contactpersonen succesvol gekopieerd.'; -$messages['movesuccess'] = '$nr contactpersonen succesvol verplaatst.'; -$messages['copyerror'] = 'Kon geen contactpersoon kopieren.'; -$messages['moveerror'] = 'Kon geen contactpersoon verplaatsen.'; +$messages['copysuccess'] = '$nr adressen succesvol gekopieerd.'; +$messages['copyerror'] = 'Kan geen adressen kopiëren.'; $messages['sourceisreadonly'] = 'Deze adresbron is alleen-lezen.'; $messages['errorsavingcontact'] = 'Kan contactpersoon niet opslaan.'; $messages['movingmessage'] = 'Bericht(en) verplaatsen...'; $messages['copyingmessage'] = 'Bericht(en) kopiëren...'; $messages['copyingcontact'] = 'Contact(en) kopiëren...'; -$messages['movingcontact'] = 'Contact(en) verplaatsen...'; $messages['deletingmessage'] = 'Bericht(en) verwijderen...'; $messages['markingmessage'] = 'Bericht(en) markeren...'; $messages['addingmember'] = 'Contactpersonen worden toegevoegd aan groep...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importeren, even geduld...'; $messages['importformaterror'] = 'Importeren mislukt! Het geüploade bestand is geen geldig importbestand.'; $messages['importconfirm'] = '<b>$inserted contactpersonen succesvol geïmporteerd</b>'; $messages['importconfirmskipped'] = '<b>$skipped bestaande contactpersonen overgeslagen</b>'; -$messages['importmessagesuccess'] = '$nr berichten succesvol geïmporteerd'; -$messages['importmessageerror'] = 'Importeren mislukt! Het verstuurde bestand is geen geldig bericht of mailboxbestand'; $messages['opnotpermitted'] = 'Deze bewerking is niet toegestaan!'; $messages['nofromaddress'] = 'Het e-mailadres ontbreekt in de geselecteerde identiteit.'; $messages['editorwarning'] = 'Door het overschakelen naar de platte-tekstverwerker gaat alle opmaak verloren. Weet u zeker dat u verder wilt gaan?'; diff --git a/program/localization/nn_NO/labels.inc b/program/localization/nn_NO/labels.inc index 5934a01d9..d1a1c5700 100644 --- a/program/localization/nn_NO/labels.inc +++ b/program/localization/nn_NO/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Kladd'; $labels['sent'] = 'Sendt'; $labels['trash'] = 'Sletta'; $labels['junk'] = 'Søppel'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Emne'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Listevisningmodus'; $labels['folderactions'] = 'Mappehandlingar'; $labels['compact'] = 'Kompakt'; $labels['empty'] = 'Tom'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Plassbruk'; $labels['unknown'] = 'ukjend'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Tilbakestill søk'; $labels['searchmod'] = 'Søkeutsagn'; $labels['msgtext'] = 'Heile eposten'; $labels['body'] = 'Meldingstekst'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Opna i nytt vindauga'; $labels['emlsave'] = 'Last ned (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Siste side'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Gruppar'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personlege adresser'; $labels['searchsave'] = 'Lagre søk'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorer ord med tal'; $labels['spellcheckignorecaps'] = 'Ignorer ord med berre store bokstavar'; $labels['addtodict'] = 'Legg til i ordliste'; $labels['mailtoprotohandler'] = 'Registrer protokollhandsaming for mailto-lenkjer'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Meldingar vidaresendast'; $labels['inline'] = 'i teksten'; $labels['asattachment'] = 'som vedlegg'; diff --git a/program/localization/nn_NO/messages.inc b/program/localization/nn_NO/messages.inc index 741b4cb20..3dce30b98 100644 --- a/program/localization/nn_NO/messages.inc +++ b/program/localization/nn_NO/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Fjernar formatering frÃ¥ meldinga …'; $messages['messageopenerror'] = 'Klarte ikkje lasta meldinga frÃ¥ tenaren.'; $messages['fileuploaderror'] = 'Filopplasting feila.'; $messages['filesizeerror'] = 'Fila du lasta opp, er større enn største tillatne filstorleik, $size.'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Kopierte $nr adresser.'; +$messages['copyerror'] = 'Klarte ikkje kopiera nokon adresser.'; $messages['sourceisreadonly'] = 'Denne adressekjelda er berre lesbar.'; $messages['errorsavingcontact'] = 'Klarte ikkje lagra kontaktadressa.'; $messages['movingmessage'] = 'Flyttar melding(ar) …'; $messages['copyingmessage'] = 'Kopierer melding(ar) …'; $messages['copyingcontact'] = 'Kopierer kontakt(ar) …'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Slettar melding(ar) …'; $messages['markingmessage'] = 'Merkar melding(ar) …'; $messages['addingmember'] = 'Legg til kontakt(ar) i gruppa …'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importerer, vent …'; $messages['importformaterror'] = 'Importering feila. Den opplasta fila er i feil format.'; $messages['importconfirm'] = '<b>Importerte $inserted kontaktar</b>'; $messages['importconfirmskipped'] = '<b>Hoppa over $skipped oppføringar som fanst frÃ¥ før</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Ulovleg operasjon.'; $messages['nofromaddress'] = 'Manglar e-postadresse i denne identiteten.'; $messages['editorwarning'] = 'Ã… byta til rein tekst vil fjerna all tekstformateringa. Vil du halda fram?'; diff --git a/program/localization/pl_PL/labels.inc b/program/localization/pl_PL/labels.inc index d7b9cd2d4..426ac381e 100644 --- a/program/localization/pl_PL/labels.inc +++ b/program/localization/pl_PL/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Kopie robocze'; $labels['sent'] = 'WysÅ‚ane'; $labels['trash'] = 'Kosz'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Pokaż prawdziwe nazwy dla folderów specjalnych'; // message listing $labels['subject'] = 'Temat'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Typ listy'; $labels['folderactions'] = 'DziaÅ‚ania na folderach...'; $labels['compact'] = 'PorzÄ…dkuj'; $labels['empty'] = 'Opróżnij'; -$labels['importmessages'] = 'Import wiadomoÅ›ci'; $labels['quota'] = 'Użyte miejsce'; $labels['unknown'] = 'nieznane'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Wyczyść filtr'; $labels['searchmod'] = 'Parametry wyszukiwania'; $labels['msgtext'] = 'CaÅ‚a wiadomość'; $labels['body'] = 'Treść'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Otwórz w nowym oknie'; $labels['emlsave'] = 'Pobierz (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Ostatnia strona'; $labels['group'] = 'Grupa'; $labels['groups'] = 'Grupy'; -$labels['listgroup'] = 'CzÅ‚onkowie grupy'; $labels['personaladrbook'] = 'Kontakty osobiste'; $labels['searchsave'] = 'Zapisz wyszukiwanie'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignoruj sÅ‚owa zawierajÄ…ce cyfry'; $labels['spellcheckignorecaps'] = 'Ignoruj sÅ‚owa pisane wielkimi literami'; $labels['addtodict'] = 'Dodaj do sÅ‚ownika'; $labels['mailtoprotohandler'] = 'Zainstaluj obsÅ‚ugÄ™ linków mailto:'; -$labels['standardwindows'] = 'Traktuj okna wyskakujÄ…ce jako standardowe okna'; $labels['forwardmode'] = 'Przekazywanie wiadomoÅ›ci'; $labels['inline'] = 'w treÅ›ci'; $labels['asattachment'] = 'jako zaÅ‚Ä…cznik'; diff --git a/program/localization/pl_PL/messages.inc b/program/localization/pl_PL/messages.inc index 3cac0c426..fb7ad6c97 100644 --- a/program/localization/pl_PL/messages.inc +++ b/program/localization/pl_PL/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Importowanie, proszÄ™ czekać...'; $messages['importformaterror'] = 'Import nieudany! Użyty plik nie jest poprawnym plikiem importu danych.'; $messages['importconfirm'] = '<b>PomyÅ›lnie dodano $inserted kontaktów, pominiÄ™to $skipped istniejÄ…cych wpisów</b>:<p><em>$names</em></p>.'; $messages['importconfirmskipped'] = '<b>PominiÄ™to $skipped istniejÄ…cych wpisów.</b>'; -$messages['importmessagesuccess'] = 'PomyÅ›lnie zaimportowano nastÄ™pujÄ…cÄ… liczbÄ™ wiadomoÅ›ci: $nr'; -$messages['importmessageerror'] = 'Import nieudany! Wgrywany plik nie jest poprawnÄ… wiadomoÅ›ciÄ… lub plikiem skrzynki pocztowej'; $messages['opnotpermitted'] = 'Niedozwolona operacja!'; $messages['nofromaddress'] = 'Brak adresu e-mail w wybranej tożsamoÅ›ci.'; $messages['editorwarning'] = 'Zmiana edytora spowoduje utratÄ™ formatowania tekstu. Czy jesteÅ› pewien, że chcesz to zrobić?'; diff --git a/program/localization/ps/labels.inc b/program/localization/ps/labels.inc index d5e513419..262e3d490 100755..100644 --- a/program/localization/ps/labels.inc +++ b/program/localization/ps/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'بارليک'; $labels['sent'] = 'Ù„ÛÚ–Ù„ شوي ليکونه'; $labels['trash'] = 'کثاÙت دانÛ'; $labels['junk'] = 'جنک'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'مضمون'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Ú©ÛÚšÚ©Ù„ÛŒ'; $labels['empty'] = 'تش'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ټيکلي لارښود'; $labels['unknown'] = 'نامعلوم'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'د Ù¾Ù„Ù¼Ù†Û Ø¨ÙŠØ§Ø³Ù…ÙˆÙ†'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'په نوي Ú©Ú“Ú©Û Ú©Û Ù¾Ø±Ø§Ù†ÙŠØ²Ù‡'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'پای غونډ وښيه'; $labels['group'] = 'Group'; $labels['groups'] = 'Ú‰Ù„Û'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Úاني پتÛ'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ps/messages.inc b/program/localization/ps/messages.inc index 50c1849bd..d3a8483ee 100755..100644 --- a/program/localization/ps/messages.inc +++ b/program/localization/ps/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'له استوزي څخه Ø¨Ú¼Û Ú“Ù†Ú«ÛÚ–ÙŠ'; $messages['messageopenerror'] = 'له سرور څخه استوزي پرمخ نه شي تلی'; $messages['fileuploaderror'] = 'دÙايل پورته کول په بري سره سرته ونه رسيده'; $messages['filesizeerror'] = 'د پورته شوي Ùايل Ú©Ú†Ù‡ بايد لږترلږه له $څخه تيری ونه Ú©Ú“ÙŠ'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'په بشپړه توګه $Ù¾ØªÛ Ú©Ø§Ù¾ÙŠ شوÛ'; +$messages['copyerror'] = 'Ù‡ÛÚ… يوه پته ÙŠÛ Ú©Ø§Ù¾ÙŠâ€ŒÙ†Ù‡ شوای کړای'; $messages['sourceisreadonly'] = 'Ø¯Ø¯Û Ù¾ØªÛ ÙŠÙˆØ§Ø²Û Ø³Ø±Ú†ÙŠÙ†Ù‡ لوستل Ú©ÛÚ–ÙŠ'; $messages['errorsavingcontact'] = 'د Ù¾ØªÛ Ø§Ú“ÙŠÚ©Ù„ÙˆØ±ÛŒ ÙŠÛ Ø®ÙˆÙ†Ø¯ÙŠâ€ŒÙ†Ù‡ شو کړای'; $messages['movingmessage'] = 'استوزه خوÚوي'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'نقلوي...صبر وکړئ'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>په بشپړه توګه نقل شو $اړيکلوري داخل شول, $شته تيرشوي انټاير څخه تيرشول</b>:<p><em>$نومونه</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'چار اجازه نه لري'; $messages['nofromaddress'] = 'په ټاکل شوي پيژندنه Ú©Û Ø¨Ø±Ûښناليک Ù¾ØªÛ Ù„Ù‡ لاسه ورکړي'; $messages['editorwarning'] = 'Ú©Ù‡ د متن بڼو له منÚÙ‡ تللو ګواښ وي نو د متن سمون پرانيزئ. غواړئ Ú†Û Ø¯ÙˆØ§Ù… ورکړئ'; diff --git a/program/localization/pt_BR/labels.inc b/program/localization/pt_BR/labels.inc index e70ae35b9..9a1946eee 100644 --- a/program/localization/pt_BR/labels.inc +++ b/program/localization/pt_BR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Rascunhos'; $labels['sent'] = 'Enviados'; $labels['trash'] = 'Lixeira'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Exibir o nome real das pastas de sistema'; // message listing $labels['subject'] = 'Assunto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Visualização em lista'; $labels['folderactions'] = 'Ações para as pastas...'; $labels['compact'] = 'Compactar'; $labels['empty'] = 'Esvaziar'; -$labels['importmessages'] = 'Importar mensagens'; $labels['quota'] = 'Uso de disco'; $labels['unknown'] = 'desconhecido'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Limpar pesquisa'; $labels['searchmod'] = 'Opções da pesquisa'; $labels['msgtext'] = 'Mensagem inteira'; $labels['body'] = 'Conteúdo'; -$labels['type'] = 'Tipo'; $labels['openinextwin'] = 'Abrir em nova janela'; $labels['emlsave'] = 'Baixar (formato .eml)'; @@ -270,7 +267,7 @@ $labels['yourmessage'] = 'Esta é uma confirmação de leitura da sua mensagem'; $labels['receiptnote'] = 'Nota: Esta confirmação de leitura somente informa que a mensagem foi aberta no computador do destinatário. Não há garantia que o destinatário tenha lido ou compreendido o conteúdo da mensagem.'; // address boook -$labels['name'] = 'Nome'; +$labels['name'] = 'Nome de exibição'; $labels['firstname'] = 'Primeiro Nome'; $labels['surname'] = 'Sobrenome'; $labels['middlename'] = 'Segundo Nome'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Última Página'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'Listar membros do grupo'; $labels['personaladrbook'] = 'Endereços pessoais'; $labels['searchsave'] = 'Salvar pesquisa'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorar palavras com números'; $labels['spellcheckignorecaps'] = 'Ignorar palavras com todas letras maiúsculas'; $labels['addtodict'] = 'Adicionar ao dicionário'; $labels['mailtoprotohandler'] = 'Associar links de e-mail (mailto:) para envio de mensagem através do webmail'; -$labels['standardwindows'] = 'Usar popups como janelas do navegador'; $labels['forwardmode'] = 'Encaminhamento de mensagens'; $labels['inline'] = 'Em linha (no corpo da mensagem)'; $labels['asattachment'] = 'como anexo'; @@ -489,7 +484,7 @@ $labels['messagecount'] = 'Mensagens'; $labels['create'] = 'Criar'; $labels['createfolder'] = 'Criar nova pasta'; $labels['managefolders'] = 'Gerenciar pastas'; -$labels['specialfolders'] = 'Pastas de sistema'; +$labels['specialfolders'] = 'Pastas especiais'; $labels['properties'] = 'Propriedades'; $labels['folderproperties'] = 'Propriedades da pasta'; $labels['parentfolder'] = 'Pasta pai'; diff --git a/program/localization/pt_BR/messages.inc b/program/localization/pt_BR/messages.inc index 45b835d44..6ec481b8f 100644 --- a/program/localization/pt_BR/messages.inc +++ b/program/localization/pt_BR/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Removendo formatação...'; $messages['messageopenerror'] = 'Não foi possÃvel carregar a mensagem do servidor'; $messages['fileuploaderror'] = 'Falha ao enviar o arquivo'; $messages['filesizeerror'] = 'O arquivo enviado excede o tamanho máximo de $size'; -$messages['copysuccess'] = '$nr contato(s) copiado(s) com sucesso.'; -$messages['movesuccess'] = '$nr contato(s) movido(s) com sucesso.'; -$messages['copyerror'] = 'Não foi possÃvel copiar os contatos.'; -$messages['moveerror'] = 'Não foi possÃvel mover os contatos.'; +$messages['copysuccess'] = '$nr endereço(s) copiado(s) com sucesso'; +$messages['copyerror'] = 'Não foi possÃvel copiar os endereços'; $messages['sourceisreadonly'] = 'Esta fonte de endereço é somente leitura'; $messages['errorsavingcontact'] = 'Não foi possÃvel salvar o endereço de contato'; $messages['movingmessage'] = 'Movendo mensagem(ns)...'; $messages['copyingmessage'] = 'Copiando mensagem(ns)...'; $messages['copyingcontact'] = 'Copiando contato(s)...'; -$messages['movingcontact'] = 'Movendo contato(s)...'; $messages['deletingmessage'] = 'Excluindo mensagem(ns)...'; $messages['markingmessage'] = 'Marcando mensagem(ns)...'; $messages['addingmember'] = 'Adicionando contato(s) para o grupo...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importando, aguarde por favor...'; $messages['importformaterror'] = 'Falha na importação! O arquivo enviado não está em um formato válido.'; $messages['importconfirm'] = '<b>Foram importados com sucesso $inserted contatos</b>'; $messages['importconfirmskipped'] = '<b>Ignorado(s) $skipped registro(s) já existente(s)</b>'; -$messages['importmessagesuccess'] = 'Importação de $nr mensagens com sucesso'; -$messages['importmessageerror'] = 'Falha na importação! O arquivo enviado não é uma mensagem ou caixa postal válida'; $messages['opnotpermitted'] = 'Operação não permitida!'; $messages['nofromaddress'] = 'Falta o e-mail na identidade selecionada.'; $messages['editorwarning'] = 'Mudar para o editor de texto simples elimina toda a formatação de texto. Deseja continuar?'; diff --git a/program/localization/pt_PT/labels.inc b/program/localization/pt_PT/labels.inc index cc4c534e0..316255e5e 100644 --- a/program/localization/pt_PT/labels.inc +++ b/program/localization/pt_PT/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Rascunhos'; $labels['sent'] = 'Itens Enviados'; $labels['trash'] = 'Reciclagem'; $labels['junk'] = 'Spam'; -$labels['show_real_foldernames'] = 'Mostrar nomes reais para as pastas especiais'; // message listing $labels['subject'] = 'Assunto'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Modo de visualização'; $labels['folderactions'] = 'Acções para pastas...'; $labels['compact'] = 'Compactar'; $labels['empty'] = 'Esvaziar'; -$labels['importmessages'] = 'Importar mensagens'; $labels['quota'] = 'Espaço utilizado'; $labels['unknown'] = 'desconhecido'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Limpar pesquisa'; $labels['searchmod'] = 'Pesquisar em'; $labels['msgtext'] = 'Mensagem completa'; $labels['body'] = 'Corpo'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Abrir numa nova janela'; $labels['emlsave'] = 'Guardar como (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Última página'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; -$labels['listgroup'] = 'Lista de membros do grupo'; $labels['personaladrbook'] = 'Endereços pessoais'; $labels['searchsave'] = 'Guardar pesquisa'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorar palavras com números'; $labels['spellcheckignorecaps'] = 'Ignorar palavras em maiúsculas'; $labels['addtodict'] = 'Adicionar ao dicionário'; $labels['mailtoprotohandler'] = 'Registar manipulador de protocolo para mailto: links'; -$labels['standardwindows'] = 'Lidar com popups como janelas padrão'; $labels['forwardmode'] = 'Reencaminhamento de mensagens'; $labels['inline'] = 'em linha'; $labels['asattachment'] = 'como anexo'; diff --git a/program/localization/pt_PT/messages.inc b/program/localization/pt_PT/messages.inc index f0855096e..88b96e60e 100644 --- a/program/localization/pt_PT/messages.inc +++ b/program/localization/pt_PT/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'A remover a formatação...'; $messages['messageopenerror'] = 'Não foi possÃvel carregar a mensagem.'; $messages['fileuploaderror'] = 'Falha ao carregar o ficheiro'; $messages['filesizeerror'] = 'O ficheiro excede o tamanho máximo permitido de $size'; -$messages['copysuccess'] = '$nr contacto(s) copiado(s) com sucesso.'; -$messages['movesuccess'] = '$nr contacto(s) movido(s) com sucesso.'; -$messages['copyerror'] = 'Não foi possÃvel copiar o(s) contacto(s).'; -$messages['moveerror'] = 'Não foi possÃvel mover o(s) contacto(s).'; +$messages['copysuccess'] = 'Foram copiados $nr endereços com sucesso'; +$messages['copyerror'] = 'Não foi possÃvel copiar os endereços'; $messages['sourceisreadonly'] = 'Esta origem de endereços é só de leitura'; $messages['errorsavingcontact'] = 'Não foi possÃvel guardar o endereço deste contacto'; $messages['movingmessage'] = 'A mover mensagem(ns)...'; $messages['copyingmessage'] = 'A copiar mensagem(ns)...'; $messages['copyingcontact'] = 'A copiar contacto(s)...'; -$messages['movingcontact'] = 'A mover contacto(s)...'; $messages['deletingmessage'] = 'A eliminar mensagem(ns)...'; $messages['markingmessage'] = 'A marcar mensagem(ns)...'; $messages['addingmember'] = 'A adicionar contacto(s) ao grupo...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'A importar, por favor aguarde...'; $messages['importformaterror'] = 'A importação falhou! O ficheiro enviado não é um ficheiro de dados válido.'; $messages['importconfirm'] = '<b>$inserted contactos importados com sucesso, $skipped contactos já existentes foram ignorados</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = 'Ignoradas $skipped entradas já existentes.'; -$messages['importmessagesuccess'] = '$nr mensagens importadas com sucesso'; -$messages['importmessageerror'] = 'A importação falhou! O ficheiro carregado não é um arquivo de caixa de correio ou ficheiro de mensagem válido.'; $messages['opnotpermitted'] = 'Operação não permitida'; $messages['nofromaddress'] = 'Falta o endereço de e-mail na identidade seleccionada'; $messages['editorwarning'] = 'Ao mudar para o editor Plain Text vai perder toda a formação de texto. Deseja continuar?'; diff --git a/program/localization/ro_RO/labels.inc b/program/localization/ro_RO/labels.inc index 4f6ddb1fa..9b76d7175 100644 --- a/program/localization/ro_RO/labels.inc +++ b/program/localization/ro_RO/labels.inc @@ -194,7 +194,6 @@ $labels['listmode'] = 'Mod de vizualizare'; $labels['folderactions'] = 'AcÈ›iuni dosar...'; $labels['compact'] = 'Compactează'; $labels['empty'] = 'GoleÅŸte'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'SpaÅ£iu folosit'; $labels['unknown'] = 'necunoscut'; @@ -205,7 +204,6 @@ $labels['resetsearch'] = 'Anulează căutarea'; $labels['searchmod'] = 'Parametrii de căutare'; $labels['msgtext'] = 'Tot mesajul'; $labels['body'] = 'Corp'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Deschide în fereastră nouă'; $labels['emlsave'] = 'Salvează în format .eml'; @@ -357,7 +355,6 @@ $labels['lastpage'] = 'Ultima pagină'; $labels['group'] = 'Grup'; $labels['groups'] = 'Grupuri'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Adrese personale'; $labels['searchsave'] = 'Salvează căutarea'; diff --git a/program/localization/ro_RO/messages.inc b/program/localization/ro_RO/messages.inc index 96b9de593..78e0fcb65 100644 --- a/program/localization/ro_RO/messages.inc +++ b/program/localization/ro_RO/messages.inc @@ -25,13 +25,13 @@ $messages['storageerror'] = 'Conectarea la serverul IMAP a eÅŸuat'; $messages['servererror'] = 'Eroare de server!'; $messages['servererrormsg'] = 'Eroare Server: $msg'; $messages['dberror'] = 'Eroare bază de date!'; -$messages['requesttimedout'] = 'Timpul alocat cereri a expirat'; -$messages['errorreadonly'] = 'Nu se poate efectua operaÅ£ia. Dosarul este doar-citire.'; -$messages['errornoperm'] = 'Nu se poate efectua operaÅ£ia. Acces interzis.'; -$messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; -$messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; +$messages['requesttimedout'] = 'Timpul alocat cererii a expirat'; +$messages['errorreadonly'] = 'Nu se poate efectua operaÅ£iunea. Dosarul este disponibil doar pentru citire.'; +$messages['errornoperm'] = 'Nu se poate efectua operaÅ£iunea. Acces interzis.'; +$messages['erroroverquota'] = 'Nu se poate efectua operaÈ›ia. Nu există spaÈ›iu liber.'; +$messages['erroroverquotadelete'] = 'Nu există spaÈ›iu liber. FolosiÈ›i SHIFT+DEL pentru a È™terge un mesaj.'; $messages['invalidrequest'] = 'Solicitare invalidă! Datele nu au fost salvate.'; -$messages['invalidhost'] = 'Hosname invalid'; +$messages['invalidhost'] = 'Nume server invalid.'; $messages['nomessagesfound'] = 'Nu a fost găsit nici un mesaj în această căsuţă poÅŸtală'; $messages['loggedout'] = 'Sesiune încheiată cu succes. La revedere!'; $messages['mailboxempty'] = 'CăsuÅ£a poÅŸtală este goală'; @@ -40,34 +40,34 @@ $messages['loading'] = 'Se încarcă...'; $messages['uploading'] = 'FiÅŸierul se încarcă...'; $messages['uploadingmany'] = 'ÃŽncarc fiÅŸierele...'; $messages['loadingdata'] = 'Se încarcă informaÅ£iile...'; -$messages['checkingmail'] = 'Se caută mesaje noi...'; +$messages['checkingmail'] = 'Se verifică pentru mesaje noi...'; $messages['sendingmessage'] = 'Trimitere mesaj...'; $messages['messagesent'] = 'Mesajul a fost trimis cu succes!'; $messages['savingmessage'] = 'Salvare mesaj...'; $messages['messagesaved'] = 'Mesajul a fost salvat în Ciorne'; -$messages['successfullysaved'] = 'Salvarea s-a efectuat cu succes'; +$messages['successfullysaved'] = 'Salvat cu succes.'; $messages['addedsuccessfully'] = 'Contactul a fost adăugat cu succes în agendă'; -$messages['contactexists'] = 'Mai există un contact cu această adresă de e-mail'; +$messages['contactexists'] = 'Un contact cu această adresă de e-mail există deja.'; $messages['contactnameexists'] = 'Există deja un contact cu acelaÅŸi nume.'; $messages['blockedimages'] = 'Pentru a vă proteja intimitatea, imaginile externe au fost blocate.'; $messages['encryptedmessage'] = 'Acesta este un mesaj criptat ÅŸi nu poate fi afiÅŸat. Ne pare rău.'; $messages['nocontactsfound'] = 'Nu s-a găsit nici un contact'; $messages['contactnotfound'] = 'Contactul solicitat nu a fost găsit.'; -$messages['contactsearchonly'] = 'Introdu niÅŸte termeni decăutare pentru a găsi contactele'; +$messages['contactsearchonly'] = 'Introdu niÅŸte termeni de căutare pentru a găsi contactele'; $messages['sendingfailed'] = 'Nu s-a reuÅŸit trimiterea mesajului'; $messages['senttooquickly'] = 'Vă rugăm aÅŸteptaÅ£i $sec sec. înainte de a trimite acest mesaj'; $messages['errorsavingsent'] = 'A intervenit o eroare în timp ce se efectua salvarea mesajului trimis'; $messages['errorsaving'] = 'A intervenit o eroare în timp ce se efectua salvarea'; -$messages['errormoving'] = 'Mesajul(e) nu a(u) putut fi mutat(e)'; -$messages['errorcopying'] = 'Mesajul(e) nu a(u) putut fi copiat(e)'; -$messages['errordeleting'] = 'Mesajul(e) nu a(u) putut fi ÅŸters(e)'; -$messages['errormarking'] = 'Mesajul(e) nu a(u) putut fi marcat(e)'; -$messages['deletecontactconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i contactul(ele) selectate?'; -$messages['deletegroupconfirm'] = 'Chiar vrei să ÅŸtergi grupul selectat?'; -$messages['deletemessagesconfirm'] = 'Chiar doriÅ£i să ÅŸtergeÅ£i mesajele selectate ?'; +$messages['errormoving'] = 'Nu am putut muta mesajul (mesajele).'; +$messages['errorcopying'] = 'Nu am putut copia mesajul (mesajele).'; +$messages['errordeleting'] = 'Nu am putut ÅŸterge mesajul (mesajele).'; +$messages['errormarking'] = 'Nu am putut marca mesajul (mesajele)'; +$messages['deletecontactconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i contactul/ele selectat(e)?'; +$messages['deletegroupconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i grupul selectat?'; +$messages['deletemessagesconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i mesajul (mesajele) selectate ?'; $messages['deletefolderconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i acest dosar?'; $messages['purgefolderconfirm'] = 'SunteÅ£i sigur că doriÅ£i să ÅŸtergeÅ£i toate mesajele din acest dosar?'; -$messages['contactdeleting'] = 'Åžterg contactul(ele)...'; +$messages['contactdeleting'] = 'Åžterg contactul (ele)...'; $messages['groupdeleting'] = 'Åžterg grupul...'; $messages['folderdeleting'] = 'Se ÅŸterge dosarul...'; $messages['foldermoving'] = 'Se mută dosarul...'; @@ -100,10 +100,10 @@ $messages['deletedsuccessfully'] = 'Mesaj ÅŸters cu succes !'; $messages['converting'] = 'Resetez mesajul la parametrii iniÅ£iali...'; $messages['messageopenerror'] = 'Nu s-a putut încărca mesajul din server'; $messages['fileuploaderror'] = 'ÃŽncărcarea pe server a eÅŸuat'; -$messages['filesizeerror'] = 'FiÅŸierul încărcat depăşeÅŸte mărimea de $size'; -$messages['copysuccess'] = '$nr adrese s-au copiat cu succes'; +$messages['filesizeerror'] = 'FiÅŸierul încărcat depăşeÅŸte dimensiunea de $size'; +$messages['copysuccess'] = '$nr adrese copiat(e) cu succes'; $messages['copyerror'] = 'Nu s-a putut copia nicio adresă'; -$messages['sourceisreadonly'] = 'Sursa acestei adrese este "read-only"(se poate doar citi)'; +$messages['sourceisreadonly'] = 'Sursa acestei adrese este "read-only" (se poate doar citi)'; $messages['errorsavingcontact'] = 'Nu s-a putut salva adresa de contact'; $messages['movingmessage'] = 'Mutare mesaj....'; $messages['copyingmessage'] = 'Copiere mesaj...'; @@ -118,18 +118,18 @@ $messages['deleteidentityconfirm'] = 'Chiar vrei să ÅŸtergi aceasă identitate? $messages['nodeletelastidentity'] = 'Nu puteÅ£i ÅŸterge această identitate, este ultima.'; $messages['forbiddencharacter'] = 'Numele dosarului conÅ£ine un caracter nepermis.'; $messages['selectimportfile'] = 'Va rugăm să selectaÅ£i fiÅŸierul pentru încărcare'; -$messages['addresswriterror'] = 'Agenda selectată nu poate fi actualizată'; +$messages['addresswriterror'] = 'Agenda selectată nu poate fi actualizată, aceasta fiind disponibila doar pentru citire.'; $messages['contactaddedtogroup'] = 'Contactele au fost adăugate cu succes la acest grup'; $messages['contactremovedfromgroup'] = 'Contactele au fost ÅŸterse cu succes din acest grup'; $messages['nogroupassignmentschanged'] = 'Atribuirile la grupuri nu au fost modificate.'; $messages['importwait'] = 'Datele sunt importate, vă rugăm să aÅŸteptaÅ£i...'; $messages['importformaterror'] = 'Importul a eÈ™uat! FiÈ™ierul încărcat nu este un fiÈ™ier valid pentru import de date.'; -$messages['importconfirm'] = 'Contactele $inserted au fost importate cu succes, $skipped intrări au fost ignorate deoarece ele există deja:$names'; +$messages['importconfirm'] = '<b>$inserted contacte au fost importate cu succes, $skipped intrări au fost ignorate deoarece ele există deja: $names</b>'; $messages['importconfirmskipped'] = '<b>Am sărit peste $skipped înregistrări</b>'; -$messages['opnotpermitted'] = 'OperaÅ£ia nu este permisă!'; +$messages['opnotpermitted'] = 'OperaÅ£iunea nu este permisă!'; $messages['nofromaddress'] = 'Nu există o adresă de e-mail în identitatea selectată'; $messages['editorwarning'] = 'Trecerea în mod text a editorului va cauza pierderea formatării textului. DoriÅ£i să continuaÅ£i?'; -$messages['httpreceivedencrypterror'] = 'Vă rugăm să luaÅ£i legătura cu administratorul serverului de mail, deoarece există o eroare în configuraÅ£ia acestuia. Mesajul d-voastră nu a fost trimis.'; +$messages['httpreceivedencrypterror'] = 'Vă rugăm să luaÅ£i legătura cu administratorul serverului de mail, deoarece există o eroare în configuraÅ£ia acestuia. <b>Mesajul d-voastră nu a fost trimis.</b>'; $messages['smtpconnerror'] = 'Eroare SMTP ($code): Conexiunea cu serverul a eÅŸuat'; $messages['smtpautherror'] = 'Eroare SMTP ($code): Autentificare eÅŸuată'; $messages['smtpfromerror'] = 'Eroare SMTP ($code): Nu s-a putut seta expeditorul "$from" ($msg)'; @@ -148,13 +148,13 @@ $messages['groupdeleted'] = 'Grupul a fost ÅŸters cu succes.'; $messages['grouprenamed'] = 'Grupul a fost redenumit cu succes.'; $messages['groupcreated'] = 'Grupul a fost creat cu succes.'; $messages['savedsearchdeleted'] = 'Căutarea salvată a fost ÅŸtearsă cu succes.'; -$messages['savedsearchdeleteerror'] = 'Nu a putut ÅŸterge căutarea salvată.'; +$messages['savedsearchdeleteerror'] = 'Nu am putut ÅŸterge căutarea salvată.'; $messages['savedsearchcreated'] = 'Căutarea a fost salvată cu succes.'; $messages['savedsearchcreateerror'] = 'Nu am putut salva căutarea.'; -$messages['messagedeleted'] = 'Mesaj(ele) a(u) fost ÅŸters(e) cu succes.'; -$messages['messagemoved'] = 'Mesaj(ele) a(u) fost mutat(e) cu succes.'; -$messages['messagecopied'] = 'Mesaj(ele) a(u) fost copiat(e) cu succes.'; -$messages['messagemarked'] = 'Mesaj(ele) a(u) fost marcat(e) cu succes.'; +$messages['messagedeleted'] = 'Mesajul (ele) a (u) fost ÅŸters (e) cu succes.'; +$messages['messagemoved'] = 'Mesajul (ele) a (u) fost mutat (e) cu succes.'; +$messages['messagecopied'] = 'Mesajul (ele) a (u) fost copiat (e) cu succes.'; +$messages['messagemarked'] = 'Mesajul (ele) a (u) fost marcat (e) cu succes.'; $messages['autocompletechars'] = 'Introdu măcar $min caractere pentru autocompletare.'; $messages['autocompletemore'] = 'Au fost găsite mai multe înregistrări. Introdu mai multe caractere.'; $messages['namecannotbeempty'] = '"Nume" nu poate fi gol.'; @@ -166,6 +166,6 @@ $messages['mispellingsfound'] = 'Au fost găsite greÅŸeli de ortografie în mesa $messages['parentnotwritable'] = 'Nu pot crea/muta dosarul în dosarul părinte selectat. Fără drepturi de acces.'; $messages['messagetoobig'] = 'Partea de mesaj este prea mare pentru a o procesa.'; $messages['attachmentvalidationerror'] = 'ATENÈšIE! Acest ataÈ™ament este suspect, fiindcă tipul lui nu coincide cu tipul declarat în mesaj. Dacă nu aveÈ›i încredere în expeditor, nu vă recomandăm să deschideÈ›i fiÈ™ierul, fiindcă poate avea conÈ›inut maliÈ›ios. <br/><br/><em>AÈ™teptat: $expected; găsit: $detected</em>'; -$messages['noscriptwarning'] = 'AtenÈ›ie: Serviciul de webmail necesită Javascript! Pentru al utiliza vă rugăm activaÈ›i Javascript în navigator.'; +$messages['noscriptwarning'] = 'AtenÈ›ie: Serviciul de webmail necesită Javascript! Pentru a-l utiliza vă rugăm activaÈ›i Javascript în setările browserului.'; ?> diff --git a/program/localization/ru_RU/labels.inc b/program/localization/ru_RU/labels.inc index 6b2b4ebca..8a136aa77 100644 --- a/program/localization/ru_RU/labels.inc +++ b/program/localization/ru_RU/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Черновики'; $labels['sent'] = 'Отправленные'; $labels['trash'] = 'Корзина'; $labels['junk'] = 'СПÐÐœ'; -$labels['show_real_foldernames'] = 'Показывать наÑтоÑщие Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñпециальных папок'; // message listing $labels['subject'] = 'Тема'; @@ -146,7 +145,7 @@ $labels['lastmessage'] = 'Показать поÑледнее ÑообщеР$labels['backtolist'] = 'К ÑпиÑку Ñообщений'; $labels['viewsource'] = 'ИÑходный текÑÑ‚'; $labels['mark'] = 'Пометить'; -$labels['markmessages'] = 'Пометить ÑообщениÑ'; +$labels['markmessages'] = 'Пометить Ñообщение'; $labels['markread'] = 'Как прочитанное'; $labels['markunread'] = 'Как непрочитанное'; $labels['markflagged'] = 'УÑтановить флаг'; @@ -164,9 +163,9 @@ $labels['unread'] = 'Ðепрочитанные'; $labels['flagged'] = 'Помеченные'; $labels['unanswered'] = 'Ðеотвеченные'; $labels['withattachment'] = 'С вложением'; -$labels['deleted'] = 'Удаленные'; -$labels['undeleted'] = 'Ðе удаленные'; -$labels['invert'] = 'Инвертировать'; +$labels['deleted'] = 'Удаленное'; +$labels['undeleted'] = 'Ðе удалено'; +$labels['invert'] = 'Инвертное'; $labels['filter'] = 'Фильтр'; $labels['list'] = 'СпиÑок'; $labels['threads'] = 'ОбÑуждениÑ'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Режим проÑмотра'; $labels['folderactions'] = 'Операции над папкой...'; $labels['compact'] = 'Сжать'; $labels['empty'] = 'ОпуÑтошить'; -$labels['importmessages'] = 'Импорт Ñообщений'; $labels['quota'] = 'Квота'; $labels['unknown'] = 'неизвеÑтно'; @@ -205,8 +203,6 @@ $labels['resetsearch'] = 'СброÑ'; $labels['searchmod'] = 'Варианты поиÑка'; $labels['msgtext'] = 'Ð’ÑÑ‘ Ñообщение'; $labels['body'] = 'Тело пиÑьма'; -$labels['type'] = 'Тип'; -$labels['namex'] = 'ИмÑ'; $labels['openinextwin'] = 'Открыть в новом окне'; $labels['emlsave'] = 'Сохранить (.eml)'; @@ -240,7 +236,7 @@ $labels['close'] = 'Закрыть'; $labels['messageoptions'] = 'ÐаÑтройки Ñообщений...'; $labels['low'] = 'Ðизкий'; -$labels['lowest'] = 'Ðизший'; +$labels['lowest'] = 'Ðижайш.'; $labels['normal'] = 'Ðорм.'; $labels['high'] = 'Ð’Ñ‹Ñокий'; $labels['highest'] = 'Ð’Ñ‹Ñоч.'; @@ -322,7 +318,7 @@ $labels['typeblog'] = 'Блог'; $labels['typeprofile'] = 'Профиль'; $labels['addfield'] = 'Добавить поле...'; -$labels['addcontact'] = 'Добавить новый контакт'; +$labels['addcontact'] = 'Добавить выбранные контакты в ÑпиÑок контактов'; $labels['editcontact'] = 'Редактировать контакт'; $labels['contacts'] = 'Контакты'; $labels['contactproperties'] = 'СвойÑтва контакта'; @@ -351,14 +347,13 @@ $labels['grouprename'] = 'Переименовать группу'; $labels['groupdelete'] = 'Удалить группу'; $labels['groupremoveselected'] = 'Удалить выбранные контакты из группы'; -$labels['previouspage'] = 'Показать предыдущую Ñтраницу'; +$labels['previouspage'] = 'Показать предыдущий'; $labels['firstpage'] = 'Показать первую Ñтраницу'; $labels['nextpage'] = 'Показать Ñледующую Ñтраницу'; $labels['lastpage'] = 'Показать поÑледнюю Ñтраницу'; $labels['group'] = 'Группа'; $labels['groups'] = 'Группы'; -$labels['listgroup'] = 'СпиÑок членов группы'; $labels['personaladrbook'] = 'ПерÑональные адреÑа'; $labels['searchsave'] = 'Сохранить запроÑ'; @@ -477,7 +472,6 @@ $labels['spellcheckignorenums'] = 'ПропуÑкать Ñлова Ñ Ñ†Ð¸Ñ„Ñ€Ð° $labels['spellcheckignorecaps'] = 'ПропуÑкать Ñлова из пропиÑных букв'; $labels['addtodict'] = 'Добавить в Ñловарь'; $labels['mailtoprotohandler'] = 'ЗарегиÑтрировать обработчик Ð´Ð»Ñ ÑÑылок mailto:'; -$labels['standardwindows'] = 'Обрабатывать вÑплывающие окна как обычные'; $labels['forwardmode'] = 'ПереÑылка Ñообщений'; $labels['inline'] = 'в текÑте'; $labels['asattachment'] = 'как вложение'; diff --git a/program/localization/ru_RU/messages.inc b/program/localization/ru_RU/messages.inc index e7dd36298..f9c8c433a 100644 --- a/program/localization/ru_RU/messages.inc +++ b/program/localization/ru_RU/messages.inc @@ -18,23 +18,23 @@ $messages = array(); $messages['errortitle'] = 'Произошла ошибка!'; -$messages['loginfailed'] = 'ÐÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° входа.'; -$messages['cookiesdisabled'] = 'Ваш браузер не принимает cookie.'; -$messages['sessionerror'] = 'Ваша ÑеÑÑÐ¸Ñ ÑƒÑтарела.'; +$messages['loginfailed'] = 'ÐÐµÑƒÐ´Ð°Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð¿Ñ‹Ñ‚ÐºÐ° входа'; +$messages['cookiesdisabled'] = 'Ваш броузер не принимает cookie'; +$messages['sessionerror'] = 'Ваша ÑеÑÑÐ¸Ñ ÑƒÑтарела'; $messages['storageerror'] = 'Ðеудачное Ñоединение Ñ IMAP Ñервером'; $messages['servererror'] = 'Ошибка Ñервера!'; $messages['servererrormsg'] = 'Ошибка Ñервера: $msg'; $messages['dberror'] = 'Ошибка базы данных!'; $messages['requesttimedout'] = 'Превышено Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа'; -$messages['errorreadonly'] = 'Ðевозможно выполнить операцию. Папка доÑтупна только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.'; -$messages['errornoperm'] = 'Ðевозможно выполнить операцию. ДоÑтуп запрещён.'; +$messages['errorreadonly'] = 'Ðевозможно выполнить операцию. Папка доÑтупна только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ'; +$messages['errornoperm'] = 'Ðевозможно выполнить операцию. ДоÑтуп запрещён'; $messages['erroroverquota'] = 'Ðевозможно выполнить операцию. Ðет Ñвободного меÑта на диÑке.'; $messages['erroroverquotadelete'] = 'Ðет Ñвободного меÑта на диÑке. ИÑпользуйте SHIFT+DEL Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ ÑообщениÑ.'; $messages['invalidrequest'] = 'Ðеверный запроÑ! Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ðµ Ñохранена.'; $messages['invalidhost'] = 'Ðеверное Ð¸Ð¼Ñ Ñервера.'; $messages['nomessagesfound'] = 'Сообщений не найдено'; $messages['loggedout'] = 'Ваша ÑеÑÑÐ¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð°. Ð’Ñего доброго!'; -$messages['mailboxempty'] = 'Почтовый Ñщик пуÑÑ‚.'; +$messages['mailboxempty'] = 'Почтовый Ñщик пуÑÑ‚'; $messages['refreshing'] = 'Обновление...'; $messages['loading'] = 'Загрузка...'; $messages['uploading'] = 'Файл загружаетÑÑ…'; @@ -42,28 +42,28 @@ $messages['uploadingmany'] = 'Загрузка файлов...'; $messages['loadingdata'] = 'Загрузка данных...'; $messages['checkingmail'] = 'Проверка новых Ñообщений...'; $messages['sendingmessage'] = 'Отправка ÑообщениÑ...'; -$messages['messagesent'] = 'Сообщение отправлено.'; +$messages['messagesent'] = 'Сообщение отправлено'; $messages['savingmessage'] = 'Сохранение ÑообщениÑ...'; -$messages['messagesaved'] = 'Сохранено в Черновиках.'; -$messages['successfullysaved'] = 'Сохранено.'; -$messages['addedsuccessfully'] = 'Контакт добавлен в адреÑную книгу.'; -$messages['contactexists'] = 'Контакт Ñ Ñтим адреÑом e-mail уже ÑущеÑтвует.'; +$messages['messagesaved'] = 'Сохранено в Черновиках'; +$messages['successfullysaved'] = 'Сохранено'; +$messages['addedsuccessfully'] = 'Контакт добавлен в ÑпиÑок контактов'; +$messages['contactexists'] = 'Контакт Ñ Ñтим адреÑом e-mail уже ÑущеÑтвует'; $messages['contactnameexists'] = 'Контакт Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует.'; $messages['blockedimages'] = 'Ð’ целÑÑ… безопаÑноÑти загрузка изображений заблокирована.'; $messages['encryptedmessage'] = 'Сообщение зашифровано и не может быть показано. ОбратитеÑÑŒ к админиÑтратору Ñервера.'; -$messages['nocontactsfound'] = 'Контакты не найдены.'; -$messages['contactnotfound'] = 'Требуемый контакт не найден.'; +$messages['nocontactsfound'] = 'Контакты не найдены'; +$messages['contactnotfound'] = 'Требуемый контакт не найден'; $messages['contactsearchonly'] = 'Введите уÑÐ»Ð¾Ð²Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка контактов'; -$messages['sendingfailed'] = 'Ðе удалоÑÑŒ отправить Ñообщение.'; -$messages['senttooquickly'] = 'Ð’Ñ‹ должны подождать $sec Ñек. Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸ ÑообщениÑ.'; -$messages['errorsavingsent'] = 'Произошла ошибка при Ñохранении отправленного ÑообщениÑ.'; -$messages['errorsaving'] = 'Ð’ процеÑÑе ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð¾ÑˆÐ»Ð° ошибка.'; -$messages['errormoving'] = 'Ðе удалоÑÑŒ перемеÑтить Ñообщение(Ñ).'; -$messages['errorcopying'] = 'Ðе удалоÑÑŒ Ñкопировать Ñообщение(Ñ).'; -$messages['errordeleting'] = 'Ðе удалоÑÑŒ удалить Ñообщение(Ñ).'; -$messages['errormarking'] = 'Ðе удалоÑÑŒ пометить Ñообщение(Ñ).'; +$messages['sendingfailed'] = 'Ðе удалоÑÑŒ отправить Ñообщение'; +$messages['senttooquickly'] = 'Ð’Ñ‹ должны подождать $sec Ñек. Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸ ÑообщениÑ'; +$messages['errorsavingsent'] = 'Произошла ошибка при Ñохранении отправленного ÑообщениÑ'; +$messages['errorsaving'] = 'Ð’ процеÑÑе ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð¾ÑˆÐ»Ð° ошибка'; +$messages['errormoving'] = 'Ðе удалоÑÑŒ перемеÑтить Ñообщение'; +$messages['errorcopying'] = 'Ðе удалоÑÑŒ Ñкопировать Ñообщение'; +$messages['errordeleting'] = 'Ðе удалоÑÑŒ удалить Ñообщение'; +$messages['errormarking'] = 'Ðевозможно пометить Ñообщение'; $messages['deletecontactconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить выделенные контакты?'; -$messages['deletegroupconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить выделенную группу?'; +$messages['deletegroupconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить группу?'; $messages['deletemessagesconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить выбранные ÑообщениÑ?'; $messages['deletefolderconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить Ñту папку?'; $messages['purgefolderconfirm'] = 'Ð’Ñ‹ дейÑтвительно хотите удалить вÑе ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð² Ñтой папке?'; @@ -73,104 +73,99 @@ $messages['folderdeleting'] = 'Удаление папки...'; $messages['foldermoving'] = 'Перемещение папки...'; $messages['foldersubscribing'] = 'ПодпиÑать папку...'; $messages['folderunsubscribing'] = 'ОтпиÑать папку...'; -$messages['formincomplete'] = 'Заполнены не вÑе Ð¿Ð¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ñ‹.'; -$messages['noemailwarning'] = 'ПожалуйÑта, введите корректный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты.'; -$messages['nonamewarning'] = 'ПожалуйÑта, введите имÑ.'; -$messages['nopagesizewarning'] = 'ПожалуйÑта, введите размер Ñтраницы.'; -$messages['nosenderwarning'] = 'ПожалуйÑта, введите Ð°Ð´Ñ€ÐµÑ Ñлектронной почты отправителÑ.'; -$messages['norecipientwarning'] = 'ПожалуйÑта, введите Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одного получателÑ.'; +$messages['formincomplete'] = 'Заполнены не вÑе полÑ'; +$messages['noemailwarning'] = 'ПожалуйÑта, введите корректный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты'; +$messages['nonamewarning'] = 'ПожалуйÑта, введите имÑ'; +$messages['nopagesizewarning'] = 'ПожалуйÑта, введите размер Ñтраницы'; +$messages['nosenderwarning'] = 'ПожалуйÑта, введите Ð°Ð´Ñ€ÐµÑ Ñлектронной почты отправителÑ'; +$messages['norecipientwarning'] = 'ПожалуйÑта, введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ'; $messages['nosubjectwarning'] = 'Поле Тема не заполнено. Хотите заполнить его ÑейчаÑ?'; $messages['nobodywarning'] = 'Отправить Ñообщение без текÑта?'; $messages['notsentwarning'] = 'Сообщение не было отправлено. Ð’Ñ‹ хотите отказатьÑÑ Ð¾Ñ‚ отправки?'; -$messages['noldapserver'] = 'ПожалуйÑта, выберите LDAP Ñервер Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка.'; +$messages['noldapserver'] = 'ПожалуйÑта, выберите LDAP Ñервер Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка'; $messages['nosearchname'] = 'ПожалуйÑта, введите Ð¸Ð¼Ñ Ð¸Ð»Ð¸ Ð°Ð´Ñ€ÐµÑ E-Mail'; $messages['notuploadedwarning'] = 'Ð’Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð°Ð³Ñ€ÑƒÐ¶ÐµÐ½Ñ‹ не полноÑтью. Подождите или отмените загрузку.'; $messages['searchsuccessful'] = 'Ðайденных Ñообщений - $nr'; $messages['contactsearchsuccessful'] = '$nr контактов найдено.'; -$messages['searchnomatch'] = 'Ðичего не найдено.'; +$messages['searchnomatch'] = 'Сообщений не найдено'; $messages['searching'] = 'ПоиÑк...'; $messages['checking'] = 'Проверка...'; -$messages['nospellerrors'] = 'ОрфографичеÑких ошибок не найдено.'; -$messages['folderdeleted'] = 'Папка удалена.'; +$messages['nospellerrors'] = 'ОрфографичеÑких ошибок не найдено'; +$messages['folderdeleted'] = 'Папка удалена'; $messages['foldersubscribed'] = 'Папка подпиÑана'; $messages['folderunsubscribed'] = 'Папка отпиÑана'; -$messages['folderpurged'] = 'Папка очищена.'; -$messages['folderexpunged'] = 'Папка Ñжата.'; -$messages['deletedsuccessfully'] = 'Удалено.'; +$messages['folderpurged'] = 'Папка удалена'; +$messages['folderexpunged'] = 'Папка очищена'; +$messages['deletedsuccessfully'] = 'Удалено'; $messages['converting'] = 'Удаление Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÑообщениÑ...'; -$messages['messageopenerror'] = 'Ðевозможно загрузить Ñообщение Ñ Ñервера.'; -$messages['fileuploaderror'] = 'Ошибка загрузки файла.'; -$messages['filesizeerror'] = 'Загруженный файл больше макÑимального размера в $size.'; -$messages['copysuccess'] = 'УÑпешно Ñкопировано $nr контактов.'; -$messages['movesuccess'] = 'УÑпешно перемещено $nr контактов.'; -$messages['copyerror'] = 'Контакты не Ñкопированы.'; -$messages['moveerror'] = 'Контакты не перемещены.'; -$messages['sourceisreadonly'] = 'Данный иÑточник адреÑов только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.'; -$messages['errorsavingcontact'] = 'Ðевозможно Ñохранить Ð°Ð´Ñ€ÐµÑ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°.'; -$messages['movingmessage'] = 'Перемещение ÑообщениÑ(й)…'; -$messages['copyingmessage'] = 'Копирование ÑообщениÑ(й)...'; +$messages['messageopenerror'] = 'Ðевозможно загрузить Ñообщение Ñ Ñервера'; +$messages['fileuploaderror'] = 'Ðевозможно загрузить файл'; +$messages['filesizeerror'] = 'Загруженный файл больше макÑимального размера в $size'; +$messages['copysuccess'] = 'Скопировано $nr адреÑов'; +$messages['copyerror'] = 'Ðевозможно Ñкопировать адреÑа'; +$messages['sourceisreadonly'] = 'Данный иÑточник адреÑов только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ'; +$messages['errorsavingcontact'] = 'Ðевозможно Ñохранить Ð°Ð´Ñ€ÐµÑ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð°'; +$messages['movingmessage'] = 'Перемещение Ñообщений…'; +$messages['copyingmessage'] = 'Копирование Ñообщений...'; $messages['copyingcontact'] = 'Копирование контакта(ов)...'; -$messages['movingcontact'] = 'Перемещение контакта(ов)...'; -$messages['deletingmessage'] = 'Удаление ÑообщениÑ(й)...'; -$messages['markingmessage'] = 'Выделение ÑообщениÑ(й)...'; +$messages['deletingmessage'] = 'Удаление Ñообщений...'; +$messages['markingmessage'] = 'Выделение Ñообщений...'; $messages['addingmember'] = 'Добавление контакта(ов) в группу...'; $messages['removingmember'] = 'Удаление контакта(ов) из группы...'; -$messages['receiptsent'] = 'Уведомление о прочтении отправлено.'; -$messages['errorsendingreceipt'] = 'Уведомление о прочтении не отправлено.'; +$messages['receiptsent'] = 'Уведомление о прочтении отправлено'; +$messages['errorsendingreceipt'] = 'Уведомление о прочтении не отправлено'; $messages['deleteidentityconfirm'] = 'Ð’Ñ‹ на Ñамом деле хотите удалить Ñту ÑущноÑÑ‚ÑŒ?'; -$messages['nodeletelastidentity'] = 'Ð’Ñ‹ не можете удалить Ñтот профиль, он у Ð²Ð°Ñ Ð¿Ð¾Ñледний.'; -$messages['forbiddencharacter'] = 'Ð˜Ð¼Ñ Ð¿Ð°Ð¿ÐºÐ¸ Ñодержит недопуÑтимые Ñимволы.'; -$messages['selectimportfile'] = 'Выберите файл Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸.'; -$messages['addresswriterror'] = 'Ð’Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð°Ñ Ð°Ð´Ñ€ÐµÑÐ½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° недоÑтупна Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи.'; -$messages['contactaddedtogroup'] = 'Контакты добавлены в Ñту группу.'; -$messages['contactremovedfromgroup'] = 'Контакты удалены из Ñтой группы.'; +$messages['nodeletelastidentity'] = 'Ð’Ñ‹ не можете удалить Ñтот профиль, он у Ð²Ð°Ñ Ð¿Ð¾Ñледний'; +$messages['forbiddencharacter'] = 'Ð˜Ð¼Ñ Ð¿Ð°Ð¿ÐºÐ¸ Ñодержит недопуÑтимые Ñимволы'; +$messages['selectimportfile'] = 'Выберите файл Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸'; +$messages['addresswriterror'] = 'Ð’Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð°Ñ Ð°Ð´Ñ€ÐµÑÐ½Ð°Ñ ÐºÐ½Ð¸Ð³Ð° недоÑтупна Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи'; +$messages['contactaddedtogroup'] = 'Контакты добавлены в группу'; +$messages['contactremovedfromgroup'] = 'Контакты удалены из группы'; $messages['nogroupassignmentschanged'] = 'РаÑпределение по группам не изменено.'; $messages['importwait'] = 'Импортирование, пожалуйÑта, подождите...'; $messages['importformaterror'] = 'Ошибка импорта! Загруженный файл имеет неизвеÑтный формат данных.'; -$messages['importconfirm'] = '<b>УÑпешно импортировано $inserted контактов</b>'; -$messages['importconfirmskipped'] = '<b>Пропущено $skipped ÑущеÑтвующих запиÑей</b>'; -$messages['importmessagesuccess'] = '$nr Ñообщений уÑпешно импортировано.'; -$messages['importmessageerror'] = 'Сбой импорта! Загруженный файл не ÑвлÑетÑÑ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ почтового Ñщика'; +$messages['importconfirm'] = '<b>УÑпешно импортировано $inserted контакт(ов), пропущено $skipped ÑущеÑтвующих</b>:<p><em>$names</em></p>'; +$messages['importconfirmskipped'] = '<b>Пропущенные $skipped ÑущеÑтвующие запиÑи</b>'; $messages['opnotpermitted'] = 'ДейÑтвие запрещено!'; -$messages['nofromaddress'] = 'Ð’ выбранном профиле не хватает адреÑа Ñлектронной почты.'; +$messages['nofromaddress'] = 'Ð’ выбранном профиле не хватает адреÑа Ñлектронной почты'; $messages['editorwarning'] = 'При переключении в редактор проÑтого текÑта вÑе форматирование будет потерÑно. Продолжить?'; -$messages['httpreceivedencrypterror'] = 'Ðа Ñервере возникла Ð½ÐµÐ¸Ð·Ð±ÐµÐ¶Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°. Срочно ÑвÑжитеÑÑŒ Ñ Ð’Ð°ÑˆÐ¸Ð¼ админиÑтратором. <b>Ваше Ñообщение не может быть отправлено.</b>'; -$messages['smtpconnerror'] = 'SMTP ошибка ($code): Сбой ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ñервером.'; -$messages['smtpautherror'] = 'SMTP ошибка ($code): Ошибка авторизации.'; -$messages['smtpfromerror'] = 'SMTP ошибка ($code): Ðевозможно уÑтановить Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÐµÐ»Ñ "$from" ($msg)'; -$messages['smtptoerror'] = 'SMTP ошибка ($code): Ðевозможно добавить Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ "$to" ($msg)'; -$messages['smtprecipientserror'] = 'SMTP ошибка: Ðевозможно обработать ÑпиÑок получателей.'; -$messages['smtperror'] = 'SMTP ошибка: $msg'; +$messages['httpreceivedencrypterror'] = 'Ðа Ñервере возникла Ð½ÐµÐ¸Ð·Ð±ÐµÐ¶Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°. Срочно ÑвÑжитеÑÑŒ Ñ Ð’Ð°ÑˆÐ¸Ð¼ админиÑтратором. <b>Ваше Ñообщение может быть не отправлено.</b>'; +$messages['smtpconnerror'] = 'SMTP Error ($code): Соединение Ñ Ñервером Ñброшено'; +$messages['smtpautherror'] = 'SMTP Error ($code): Ошибка авторизации'; +$messages['smtpfromerror'] = 'SMTP Error ($code): Ðевозможно уÑтановить Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÐµÐ»Ñ "$from" ($msg)'; +$messages['smtptoerror'] = 'SMTP Error ($code): Ðевозможно добавить Ð¿Ð¾Ð»ÑƒÑ‡Ð°Ñ‚ÐµÐ»Ñ "$to" ($msg)'; +$messages['smtprecipientserror'] = 'SMTP Error: Ðевозможно обработать ÑпиÑок получателей'; +$messages['smtperror'] = 'SMTP Error ($code): $msg'; $messages['emailformaterror'] = 'Ðеверный адреÑ: $email'; -$messages['toomanyrecipients'] = 'Слишком много получателей. Уменьшите их количеÑтво до $max.'; -$messages['maxgroupmembersreached'] = 'Размер группы больше макÑимально разрешенного - $max.'; -$messages['internalerror'] = 'Произошла внутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°. Попробуйте ещё раз.'; -$messages['contactdelerror'] = 'Ðе возможно удалить контакт(Ñ‹).'; -$messages['contactdeleted'] = 'Контакт(Ñ‹) уÑпешно удален(Ñ‹).'; +$messages['toomanyrecipients'] = 'Слишком много получателей, уменьшите их количеÑтво до $max.'; +$messages['maxgroupmembersreached'] = 'Размер группы больше макÑимально разрешенного - $max'; +$messages['internalerror'] = 'Произошла внутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°. Попробуйте ещё раз'; +$messages['contactdelerror'] = 'Ðе могу удалить контакт(Ñ‹)'; +$messages['contactdeleted'] = 'Контакт(Ñ‹) уÑпешно удален(Ñ‹)'; $messages['contactrestoreerror'] = 'Ðе удалоÑÑŒ воÑÑтановить удалённый(е) контакт(Ñ‹).'; -$messages['contactrestored'] = 'Контакт(Ñ‹) уÑпешно воÑÑтановлен(Ñ‹).'; -$messages['groupdeleted'] = 'Группа уÑпешно удалена.'; -$messages['grouprenamed'] = 'Группа уÑпешно переименована.'; -$messages['groupcreated'] = 'Группа уÑпешно Ñоздана.'; +$messages['contactrestored'] = 'Контакт(Ñ‹) уÑпешно воÑÑтановлены.'; +$messages['groupdeleted'] = 'Группа уÑпешно удалена'; +$messages['grouprenamed'] = 'Группа уÑпешно переименована'; +$messages['groupcreated'] = 'Группа уÑпешно Ñоздана'; $messages['savedsearchdeleted'] = 'Сохранённый Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно удалён.'; $messages['savedsearchdeleteerror'] = 'Ðе удалоÑÑŒ удалить Ñохранённый запроÑ.'; $messages['savedsearchcreated'] = 'Сохранённый Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно Ñоздан.'; $messages['savedsearchcreateerror'] = 'Ðе удалоÑÑŒ Ñоздать Ñохранённый запроÑ.'; -$messages['messagedeleted'] = 'Сообщение(Ñ) уÑпешно удалено(Ñ‹).'; -$messages['messagemoved'] = 'Сообщение(Ñ) уÑпешно перемещено(Ñ‹).'; -$messages['messagecopied'] = 'Сообщение(Ñ) уÑпешно Ñкопировано(Ñ‹).'; -$messages['messagemarked'] = 'Сообщение(Ñ) уÑпешно выделено(Ñ‹).'; -$messages['autocompletechars'] = 'Введите, как минимум, $min Ñимволов Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ.'; +$messages['messagedeleted'] = 'Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ ÑƒÑпешно удалены'; +$messages['messagemoved'] = 'Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ ÑƒÑпешно перемещены'; +$messages['messagecopied'] = 'Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ ÑƒÑпешно Ñкопированы'; +$messages['messagemarked'] = 'Ð¡Ð¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ ÑƒÑпешно выделены'; +$messages['autocompletechars'] = 'Введите, как минимум, $min Ñимволов Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ'; $messages['autocompletemore'] = 'ПоиÑк возвратил Ñлишком много результатов. ПожалуйÑта, уточните.'; -$messages['namecannotbeempty'] = 'Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым.'; -$messages['nametoolong'] = 'Слишком длинное имÑ.'; -$messages['folderupdated'] = 'Папка обновлена.'; -$messages['foldercreated'] = 'Папка Ñоздана.'; -$messages['invalidimageformat'] = 'Ðеверный формат изображениÑ.'; -$messages['mispellingsfound'] = 'Ð’ Ñообщении обнаружены орфографичеÑкие ошибки.'; +$messages['namecannotbeempty'] = 'Ð˜Ð¼Ñ Ð½Ðµ может быть пуÑтым'; +$messages['nametoolong'] = 'Слишком длинное имÑ'; +$messages['folderupdated'] = 'Папка обновлена'; +$messages['foldercreated'] = 'Папка Ñоздана'; +$messages['invalidimageformat'] = 'Ðеверный формат изображениÑ'; +$messages['mispellingsfound'] = 'Ð’ Ñообщении обнаружены орфографичеÑкие ошибки'; $messages['parentnotwritable'] = 'Ðе удаетÑÑ Ñоздать/перемеÑтить папку в выбранную родительÑкую папку. Ðет прав доÑтупа.'; $messages['messagetoobig'] = 'ЧаÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñлишком велика Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸.'; -$messages['attachmentvalidationerror'] = 'Ð’ÐИМÐÐИЕ! Ðто вложение ÑвлÑетÑÑ Ð¿Ð¾Ð´Ð¾Ð·Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ð¼, потому что его тип не Ñовпадает Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼, объÑвленным в Ñообщении. ЕÑли Ð’Ñ‹ не доверÑете отправителю, не открывайте его в браузере, поÑкольку оно может заключать в Ñебе вредоноÑное Ñодержимое.<br/><br/><em>Expected: $expected; found: $detected</em>'; +$messages['attachmentvalidationerror'] = 'Ð’ÐИМÐÐИЕ! Ðто приложение ÑвлÑетÑÑ Ð¿Ð¾Ð´Ð¾Ð·Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹, потому что его тип не Ñовпадает Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼, объÑвленным в Ñообщении. ЕÑли вы не доверÑете отправителю, вы не должны открывать его в браузере, поÑкольку он может Ñодержать вредоноÑный Ñодержание.<br/><br/><em>Expected: $expected; found: $detected</em>'; $messages['noscriptwarning'] = 'Внимание: Данному ÑервиÑу веб-почты требуетÑÑ Javascript! Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы его иÑпользовать необходимо включить поддержку Javascript в наÑтройках вашего браузера.'; ?> diff --git a/program/localization/si_LK/labels.inc b/program/localization/si_LK/labels.inc index 92d33d3b7..d8cd71662 100644 --- a/program/localization/si_LK/labels.inc +++ b/program/localization/si_LK/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'කටු සටහන්'; $labels['sent'] = 'යà·à·€à·–'; $labels['trash'] = 'ඉවà¶à¶½à¶± බඳුන'; $labels['junk'] = 'සුන්බුන්'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'මà·à¶à·˜à¶šà·à·€'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'බහà·à¶½à·”ම් ක්â€à¶»à·’යà·...'; $labels['compact'] = 'සංයුක්à¶'; $labels['empty'] = 'හිස්'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'නොදනී'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'සෙවුම යලි පිහිටවීම'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'සම්පූර්ණ පණිවිඩය'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'නව කවුළුවක විවෘචකරන්න'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'අවසà·à¶± පිටුව පෙන්වනà $labels['group'] = 'කණ්ඩà·à¶ºà¶¸'; $labels['groups'] = 'කණ්ඩà·à¶ºà¶¸à·Š'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'පුද්ගලික ලිපිනය'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'අංක සහිචවචන නොසල $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'à·à¶¶à·Šà¶¯ කà·à·‚යට එක් කරන්න'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/si_LK/messages.inc b/program/localization/si_LK/messages.inc index dd020b928..c3828bc64 100644 --- a/program/localization/si_LK/messages.inc +++ b/program/localization/si_LK/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'පනිවුඩයෙන් ආකෘà¶à·“කරà $messages['messageopenerror'] = 'පනිවුඩය පූරනය කිරීමට නොහà·à¶š'; $messages['fileuploaderror'] = 'ගොනුව ඇà¶à·”ලà¶à·Š කිරීමට නොහà·à¶š'; $messages['filesizeerror'] = 'ඇà¶à·”ලà¶à·Š කල ගොනුවෙ ප්රමà·à¶«à¶º උපරිම අගය $size ඉක්මව෠ඇà¶'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '$nr ලිපිනය à·ƒà·à¶»à·Šà¶®à¶šà·€ පිටපà¶à·Š කරන ලදී'; +$messages['copyerror'] = 'Could not copy any addresses.'; $messages['sourceisreadonly'] = 'මෙම ලිපින මූලà·à·à·Šà¶»à¶º කියවීම සඳහ෠පමනි'; $messages['errorsavingcontact'] = 'ලිපිනය à¶à·à¶±à·Šà¶´à¶à·Š කීරීමට නොහà·à¶š'; $messages['movingmessage'] = 'පණිවිඩ(ය) ගෙනයමින්...'; $messages['copyingmessage'] = 'පණිවිඩ(ය) පිටපà¶à·Š කරමින්...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'පණිවිඩ(ය) මක෠දමමින්...'; $messages['markingmessage'] = 'පණිවිඩ(ය) සලකුණු කරමින්...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'ආනයනය කරමින්, කරුණà·à¶ $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/sk_SK/labels.inc b/program/localization/sk_SK/labels.inc index 465252409..10673382a 100644 --- a/program/localization/sk_SK/labels.inc +++ b/program/localization/sk_SK/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'RozpÃsané'; $labels['sent'] = 'Odoslané'; $labels['trash'] = 'Kôš'; $labels['junk'] = 'Nevyžiadaná poÅ¡ta'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Predmet'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Režim zobrazenia zoznamu'; $labels['folderactions'] = 'Akcie so zložkou...'; $labels['compact'] = 'ZhustiÅ¥ prieÄinok'; $labels['empty'] = 'VyprázdniÅ¥'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Zaplnenie schránky'; $labels['unknown'] = 'neznáme'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'VyÄistiÅ¥ vyhľadávanie'; $labels['searchmod'] = 'Parametre hľadanie'; $labels['msgtext'] = 'Celá správa'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'OtvoriÅ¥ v novom okne'; $labels['emlsave'] = 'StiahnuÅ¥'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Posledná stránka'; $labels['group'] = 'Skupina'; $labels['groups'] = 'Skupiny'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Osobné adresy'; $labels['searchsave'] = 'UložiÅ¥ vyhľadávanie'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'IgnorovaÅ¥ slová s ÄÃslami'; $labels['spellcheckignorecaps'] = 'IgnorovaÅ¥ slová pÃsané veľkými pÃsmenami'; $labels['addtodict'] = 'PridaÅ¥ do slovnÃka'; $labels['mailtoprotohandler'] = 'ZaregistrovaÅ¥ handler pre odkazy „mailto:“'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Preposielanie správ'; $labels['inline'] = 'v tele spávy'; $labels['asattachment'] = 'ako prÃloha'; diff --git a/program/localization/sk_SK/messages.inc b/program/localization/sk_SK/messages.inc index 17aaa3a53..a6f319db6 100644 --- a/program/localization/sk_SK/messages.inc +++ b/program/localization/sk_SK/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Odstraňuje sa formátovanie správy...'; $messages['messageopenerror'] = 'Nedá sa naÄÃtaÅ¥ správa zo servera'; $messages['fileuploaderror'] = 'NaÄÃtanie súboru nebolo úspeÅ¡né'; $messages['filesizeerror'] = 'NaÄÃtavaný súbor prekroÄil maximálnu veľkosÅ¥ $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'ÚspeÅ¡ne sa skopÃrovalo $nr adries'; +$messages['copyerror'] = 'Nedá sa kopÃrovaÅ¥ žiadna adresa'; $messages['sourceisreadonly'] = 'Tento zdroj adries je len na ÄÃtanie'; $messages['errorsavingcontact'] = 'Nedá sa uložiÅ¥ adresa kontaktu'; $messages['movingmessage'] = 'Správa sa presúva...'; $messages['copyingmessage'] = 'Správa sa kopÃruje...'; $messages['copyingcontact'] = 'KopÃrujem kontakt(y)'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Mažem správu(y)...'; $messages['markingmessage'] = 'OznaÄujem správu(y)...'; $messages['addingmember'] = 'Pridávam kontakt(y) do skupiny...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Prebieha import, poÄkajte ...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>ÚspeÅ¡ne sa naÄÃtalo $inserted kontaktov, preskoÄilo sa $skipped existujúcich záznamov</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>PreskoÄených $skipped existujúcich záznamov</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operácia nie je povolená!'; $messages['nofromaddress'] = 'Zvolená identita neobsahuje e-mailovú adresu'; $messages['editorwarning'] = 'Prepnutie na editor obyÄajného textu spôsobà stratu formátovania. Chcete napriek tomu pokraÄovaÅ¥?'; diff --git a/program/localization/sl_SI/labels.inc b/program/localization/sl_SI/labels.inc index c33ea479c..6b9ba2d41 100644 --- a/program/localization/sl_SI/labels.inc +++ b/program/localization/sl_SI/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Osnutki'; $labels['sent'] = 'Poslano'; $labels['trash'] = 'Smeti'; $labels['junk'] = 'Nezaželena sporoÄila'; -$labels['show_real_foldernames'] = 'Prikaži prava imena za posebne mape'; // message listing $labels['subject'] = 'Zadeva'; @@ -163,7 +162,7 @@ $labels['currpage'] = 'Trenutna stran'; $labels['unread'] = 'Neprebrano'; $labels['flagged'] = 'OznaÄeno'; $labels['unanswered'] = 'NeoznaÄeno'; -$labels['withattachment'] = 'S priponko'; +$labels['withattachment'] = 'With attachment'; $labels['deleted'] = 'Izbrisano'; $labels['undeleted'] = 'Ni izbrisano'; $labels['invert'] = 'Zamenjaj'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'NaÄin prikaza seznama'; $labels['folderactions'] = 'Upravljanje map...'; $labels['compact'] = 'Stisni'; $labels['empty'] = 'Izprazni'; -$labels['importmessages'] = 'Uvozi sporoÄila'; $labels['quota'] = 'Poraba prostora'; $labels['unknown'] = 'neznana'; @@ -205,12 +203,11 @@ $labels['resetsearch'] = 'PrekliÄi iskanje'; $labels['searchmod'] = 'Spremembe iskanja'; $labels['msgtext'] = 'Celotno sporoÄilo'; $labels['body'] = 'Vsebina sporoÄila'; -$labels['type'] = 'Tip'; $labels['openinextwin'] = 'Odpri v novem oknu'; $labels['emlsave'] = 'Prenos datoteke (.eml)'; -$labels['changeformattext'] = 'Prikaži kot golo besedilo'; -$labels['changeformathtml'] = 'Prikaži v formatu HTML'; +$labels['changeformattext'] = 'Display in plain text format'; +$labels['changeformathtml'] = 'Display in HTML format'; // message compose $labels['editasnew'] = 'Uredi kot novo'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Zadnja stran'; $labels['group'] = 'Skupina'; $labels['groups'] = 'Skupine'; -$labels['listgroup'] = 'IzpiÅ¡i seznam Älanov skupine'; $labels['personaladrbook'] = 'Stiki'; $labels['searchsave'] = 'Shrani iskanje'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'Sestavi sporoÄila z obogatenim besedilom'; $labels['htmlonreply'] = 'le pri odgovoru na sporoÄila z obogatenim besedilom'; $labels['htmlonreplyandforward'] = 'le pri posredovanju ali odgovoru na sporoÄila z obogatenim besedilom'; $labels['htmlsignature'] = 'Podpis z obogatenim besedilom'; -$labels['showemail'] = 'Prikaži e-naslove poleg imen'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Prikaži predogled'; $labels['skin'] = 'Tema uporabniÅ¡kega vmesnika'; $labels['logoutclear'] = 'Izprazni mapo Smeti ob odjavi'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ne upoÅ¡tevaj besed, ki vsebujejo Å¡tevilke'; $labels['spellcheckignorecaps'] = 'Ne upoÅ¡tevaj besed, ki vsebujejo samo velike Ärke'; $labels['addtodict'] = 'Dodaj v slovar'; $labels['mailtoprotohandler'] = 'Registriraj upravljavca protokola za e-naslov: povezave'; -$labels['standardwindows'] = 'Prikaži pojavna okna kot obiÄajna'; $labels['forwardmode'] = 'Posredovanje sporoÄil'; $labels['inline'] = 'medvrstiÄno'; $labels['asattachment'] = 'Kot priponka'; diff --git a/program/localization/sl_SI/messages.inc b/program/localization/sl_SI/messages.inc index dc731d01b..081d912c1 100644 --- a/program/localization/sl_SI/messages.inc +++ b/program/localization/sl_SI/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Uvažanje poteka...'; $messages['importformaterror'] = 'Uvoz ni uspel! Uvožena datoteka ni pravega formata.'; $messages['importconfirm'] = '<b>UspeÅ¡no uvoženi $inserted stiki, $skipped stikov že obstaja v imeniku</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>PreskoÄeni že obstojeÄi vnosi $skipped </b>'; -$messages['importmessagesuccess'] = 'UpeÅ¡no ste uvozili $nr sporoÄil.'; -$messages['importmessageerror'] = 'Uvoz je spodletel. Naložena datoteka ni veljavno sporoÄilo ali poÅ¡tna datoteka'; $messages['opnotpermitted'] = 'Operacija ni dovoljena.'; $messages['nofromaddress'] = 'V izbrani identiteti manjka elektronski naslov.'; $messages['editorwarning'] = 'Preklop v sploÅ¡en urejevalnik onemogoÄa uporabo izbranih nastavitev oblikovanja. Želite nadaljevati?'; diff --git a/program/localization/sq_AL/labels.inc b/program/localization/sq_AL/labels.inc index e2cb6791b..ba9b559d8 100644 --- a/program/localization/sq_AL/labels.inc +++ b/program/localization/sq_AL/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Drafte'; $labels['sent'] = 'Dërguar'; $labels['trash'] = 'Fshirë'; $labels['junk'] = 'Reklama'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Tema'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Zvogëlo'; $labels['empty'] = 'Boshatis'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Përdorimi i diskut'; $labels['unknown'] = 'i panjohur'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Pastro kërkimin'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Shfaq grupin e fundit'; $labels['group'] = 'Group'; $labels['groups'] = 'Grupet'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Adresat Personale'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/sq_AL/messages.inc b/program/localization/sq_AL/messages.inc index 5a18aafca..56bb9feb2 100644 --- a/program/localization/sq_AL/messages.inc +++ b/program/localization/sq_AL/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Po i heq formatimin mesazhit...'; $messages['messageopenerror'] = 'Nuk marr dot mesazhe nga serveri'; $messages['fileuploaderror'] = 'Ngarkimi i skedarit dështoi'; $messages['filesizeerror'] = 'Skedari i ngarkuar e kalon madhësinë kufi prej $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'U kopjuan me sukses $nr adresa'; +$messages['copyerror'] = 'Nuk munda të kopjoj adresat'; $messages['sourceisreadonly'] = 'Ky burim adrese është vetëm i lexueshëm'; $messages['errorsavingcontact'] = 'Nuk e ruajta dot adresën e kontaktit'; $messages['movingmessage'] = 'Po lëviz mesazhin...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/sr_CS/labels.inc b/program/localization/sr_CS/labels.inc index 4bdf25020..130d3a7a6 100644 --- a/program/localization/sr_CS/labels.inc +++ b/program/localization/sr_CS/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'U pripremi'; $labels['sent'] = 'ПоÑлате'; $labels['trash'] = 'Канта'; $labels['junk'] = 'Смеће'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'ÐаÑлов'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'ЛиÑÑ‚ режим приказивања'; $labels['folderactions'] = 'ПоÑтавке фаÑцикле'; $labels['compact'] = 'Компакција'; $labels['empty'] = 'ИÑпразни'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Квота'; $labels['unknown'] = 'непозната'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Прикажи Ñве поруке'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Цела порука'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Отвори у новом прозору'; $labels['emlsave'] = 'Довнлоад (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Прикажи поÑледњи Ñкуп'; $labels['group'] = 'Група'; $labels['groups'] = 'Групе'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Личне адреÑе'; $labels['searchsave'] = 'Сачувај претрагу'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'игнориши речи Ñа бројевР$labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Додај у речник'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/sr_CS/messages.inc b/program/localization/sr_CS/messages.inc index 016cef163..32007e6f2 100644 --- a/program/localization/sr_CS/messages.inc +++ b/program/localization/sr_CS/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Уклањање форматирања из пору $messages['messageopenerror'] = 'Порука Ñе не може учитати Ñа Ñервера'; $messages['fileuploaderror'] = 'Слање датотеке неуÑпешно'; $messages['filesizeerror'] = 'ПоÑлата датотека не може да прекорачи величину од $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'УÑпешно копирано $nr адреÑа'; +$messages['copyerror'] = 'Ðемогуће је иÑкопирати иједну адреÑу'; $messages['sourceisreadonly'] = 'Овај извор адреÑе је Ñамо за читање'; $messages['errorsavingcontact'] = 'ÐеуÑпело Ñнимање адреÑе контакта'; $messages['movingmessage'] = 'Премештам поруку...'; $messages['copyingmessage'] = 'Копирам поруке...'; $messages['copyingcontact'] = 'Умножава контакте...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'бришем поруке...'; $messages['markingmessage'] = 'Означавам поруке...'; $messages['addingmember'] = 'Додаје контакте у групу...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Увоз података, молимо ÑÐ°Ñ‡ÐµÐºÐ°Ñ $messages['importformaterror'] = 'Увоз је неуÑпешан! ПоÑлата датотека није допуштена за увоз.'; $messages['importconfirm'] = '<b>УÑпешно увезжени $inserted контакти </b>'; $messages['importconfirmskipped'] = '<b>ПреÑкочени $skipped поÑтојећи уноÑи </b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Операција није дозвољена!'; $messages['nofromaddress'] = 'ÐедоÑтаје имејл адреÑа у изабраном налогу'; $messages['editorwarning'] = 'Пребацивање на обичан текÑÑ‚ едитор ће изазвати губитак целог форматирања. Да ли желите да наÑтавите?'; diff --git a/program/localization/sv_SE/labels.inc b/program/localization/sv_SE/labels.inc index 7169aeba8..f61433527 100644 --- a/program/localization/sv_SE/labels.inc +++ b/program/localization/sv_SE/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Utkast'; $labels['sent'] = 'Skickat'; $labels['trash'] = 'Papperskorg'; $labels['junk'] = 'Skräp'; -$labels['show_real_foldernames'] = 'Visa verkliga namn pÃ¥ särskilda kataloger'; // message listing $labels['subject'] = 'Ämne'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Visningsläge'; $labels['folderactions'] = 'Hantera kataloger'; $labels['compact'] = 'Packa'; $labels['empty'] = 'Töm'; -$labels['importmessages'] = 'Importera meddelanden'; $labels['quota'] = 'Diskutrymme'; $labels['unknown'] = 'okänt'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Ã…terställ sökning'; $labels['searchmod'] = 'Sökalternativ'; $labels['msgtext'] = 'Hela meddelandet'; $labels['body'] = 'InnehÃ¥ll'; -$labels['type'] = 'Typ'; $labels['openinextwin'] = 'Öppna i nytt fönster'; $labels['emlsave'] = 'Spara (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Visa sista sidan'; $labels['group'] = 'Grupp'; $labels['groups'] = 'Kontaktgrupper'; -$labels['listgroup'] = 'Visa gruppmedlemmar'; $labels['personaladrbook'] = 'Personliga adresser'; $labels['searchsave'] = 'Lägg till sökning'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignorera ord med siffror'; $labels['spellcheckignorecaps'] = 'Ignorera ord med enbart stora bokstäver'; $labels['addtodict'] = 'Lägg till i ordlista'; $labels['mailtoprotohandler'] = 'Ange program för hantering av mailto-länkar'; -$labels['standardwindows'] = 'Hantera popup-rutor som standardfönster'; $labels['forwardmode'] = 'Vidarebefordra meddelande'; $labels['inline'] = 'Infogat'; $labels['asattachment'] = 'Bilaga'; diff --git a/program/localization/sv_SE/messages.inc b/program/localization/sv_SE/messages.inc index d0c58a97d..63dddc548 100644 --- a/program/localization/sv_SE/messages.inc +++ b/program/localization/sv_SE/messages.inc @@ -42,11 +42,11 @@ $messages['uploadingmany'] = 'Överför filer...'; $messages['loadingdata'] = 'Laddar data...'; $messages['checkingmail'] = 'Hämtar nya meddelanden...'; $messages['sendingmessage'] = 'Skickar meddelande...'; -$messages['messagesent'] = 'Meddelandet har skickats.'; +$messages['messagesent'] = 'Meddelandet har skickats'; $messages['savingmessage'] = 'Sparar meddelande...'; $messages['messagesaved'] = 'Meddelandet har sparats i Utkast'; -$messages['successfullysaved'] = 'Informationen har sparats.'; -$messages['addedsuccessfully'] = 'Kontakten har lagts till i adressboken.'; +$messages['successfullysaved'] = 'Informationen har sparats'; +$messages['addedsuccessfully'] = 'Kontakten har lagts till i adressboken'; $messages['contactexists'] = 'En kontakt med den här adressen finns redan'; $messages['contactnameexists'] = 'En kontakt med det här namnet finns redan'; $messages['blockedimages'] = 'Externt länkade bilder i meddelandet har blockerats.'; @@ -85,52 +85,47 @@ $messages['notsentwarning'] = 'Meddelandet har inte skickats. Vill du avbryta me $messages['noldapserver'] = 'Ange en LDAP-server för att söka'; $messages['nosearchname'] = 'Ange ett kontaktnamn eller en adress'; $messages['notuploadedwarning'] = 'Alla bilagor har inte överförts ännu. Vänta eller avbryt överföringen.'; -$messages['searchsuccessful'] = '$nr meddelanden hittades.'; -$messages['contactsearchsuccessful'] = '$nr kontakter hittades.'; +$messages['searchsuccessful'] = '$nr meddelanden hittades'; +$messages['contactsearchsuccessful'] = '$nr kontakter hittades'; $messages['searchnomatch'] = 'Sökningen gav inget resultat'; $messages['searching'] = 'Söker...'; $messages['checking'] = 'Kontrollerar...'; $messages['nospellerrors'] = 'Inget stavfel hittades'; -$messages['folderdeleted'] = 'Katalogen togs bort.'; -$messages['foldersubscribed'] = 'Prenumeration pÃ¥ katalog startad.'; -$messages['folderunsubscribed'] = 'Prenumeration pÃ¥ katalog avslutad.'; -$messages['folderpurged'] = 'Katalog rensad.'; -$messages['folderexpunged'] = 'Katalog tömd.'; -$messages['deletedsuccessfully'] = 'Lyckad borttagning.'; +$messages['folderdeleted'] = 'Katalogen togs bort'; +$messages['foldersubscribed'] = 'Prenumeration pÃ¥ katalog startad'; +$messages['folderunsubscribed'] = 'Prenumeration pÃ¥ katalog avslutad'; +$messages['folderpurged'] = 'Katalog rensad'; +$messages['folderexpunged'] = 'Katalog tömd'; +$messages['deletedsuccessfully'] = 'Lyckad borttagning'; $messages['converting'] = 'Tar bort formatering frÃ¥n meddelande...'; $messages['messageopenerror'] = 'Meddelandet kunde inte hämtas frÃ¥n servern'; $messages['fileuploaderror'] = 'Filuppladdning misslyckades'; $messages['filesizeerror'] = 'Den uppladdade filens storlek överstiger högsta tillÃ¥tna $size'; -$messages['copysuccess'] = '$nr kontakter har kopierats.'; -$messages['movesuccess'] = '$nr kontakter har flyttats.'; -$messages['copyerror'] = 'NÃ¥gra kontakter kunde inte kopieras.'; -$messages['moveerror'] = 'NÃ¥gra kontakter kunde inte flyttas.'; +$messages['copysuccess'] = '$nr adresser har kopierats'; +$messages['copyerror'] = 'NÃ¥gra adresser kunde inte kopieras'; $messages['sourceisreadonly'] = 'Denna adresskälla är skrivskyddad'; $messages['errorsavingcontact'] = 'Kontaktadressen kunde inte sparas'; $messages['movingmessage'] = 'Flyttar meddelande...'; $messages['copyingmessage'] = 'Kopierar meddelande...'; $messages['copyingcontact'] = 'Kopierar kontakter...'; -$messages['movingcontact'] = 'Flyttar kontakter...'; $messages['deletingmessage'] = 'Tar bort meddelande...'; $messages['markingmessage'] = 'Markerar meddelande...'; $messages['addingmember'] = 'Lägger till kontakter i gruppen...'; $messages['removingmember'] = 'Tar bort kontakter frÃ¥n gruppen...'; -$messages['receiptsent'] = 'Mottagarkvitto har skickats.'; +$messages['receiptsent'] = 'Mottagarkvitto har skickats'; $messages['errorsendingreceipt'] = 'Mottagarkvitto kunde inte skickas'; $messages['deleteidentityconfirm'] = 'Vill du verkligen ta bort denna identitet?'; $messages['nodeletelastidentity'] = 'Du kan inte ta bort identiteten, den är din sista.'; $messages['forbiddencharacter'] = 'Katalognamnet innehÃ¥ller otillÃ¥tna tecken'; $messages['selectimportfile'] = 'Välj en fil att ladda upp'; $messages['addresswriterror'] = 'Angiven adressbok är skrivskyddad'; -$messages['contactaddedtogroup'] = 'Kontakterna har lagts till i gruppen.'; -$messages['contactremovedfromgroup'] = 'Kontakterna har tagits bort frÃ¥n gruppen.'; +$messages['contactaddedtogroup'] = 'Kontakterna har lagts till i gruppen'; +$messages['contactremovedfromgroup'] = 'Kontakterna har tagits bort frÃ¥n gruppen'; $messages['nogroupassignmentschanged'] = 'Ingen grupptillhörighet ändrades.'; $messages['importwait'] = 'Importerar, var god vänta...'; $messages['importformaterror'] = 'Importen misslyckades! Filen har inte korrekt dataformat.'; $messages['importconfirm'] = '<b>Lyckad import av $inserted kontakter</b>'; $messages['importconfirmskipped'] = '<b>Hoppade över $skipped befintliga poster</b>'; -$messages['importmessagesuccess'] = '$nr meddelanden har importerats.'; -$messages['importmessageerror'] = 'Importen misslyckades! Filen innehÃ¥ller inte nÃ¥got meddelande eller nÃ¥gon brevlÃ¥da'; $messages['opnotpermitted'] = 'OtillÃ¥ten operation!'; $messages['nofromaddress'] = 'Adress saknas i den valda identiteten'; $messages['editorwarning'] = 'Genom att växla till text-läge gÃ¥r formateringen förlorad. Vill du fortsätta?'; @@ -146,26 +141,26 @@ $messages['toomanyrecipients'] = 'FörmÃ¥nga mottagare. Minska antalet till hög $messages['maxgroupmembersreached'] = 'Antalet gruppmedlemmar fÃ¥r inte överstiga $max'; $messages['internalerror'] = 'Ett internt fel uppstod. Försök igen.'; $messages['contactdelerror'] = 'Kontakt kunde inte tas bort'; -$messages['contactdeleted'] = 'Kontakt borttagen.'; +$messages['contactdeleted'] = 'Kontakt borttagen'; $messages['contactrestoreerror'] = 'Borttagna kontakter kunde inte Ã¥terskapas'; -$messages['contactrestored'] = 'Kontakter Ã¥terskapade.'; -$messages['groupdeleted'] = 'Grupp borttagen.'; -$messages['grouprenamed'] = 'Gruppnamn ändrat.'; -$messages['groupcreated'] = 'Grupp skapad.'; -$messages['savedsearchdeleted'] = 'Sparad sökning borttagen.'; +$messages['contactrestored'] = 'Kontakter Ã¥terskapade'; +$messages['groupdeleted'] = 'Grupp borttagen'; +$messages['grouprenamed'] = 'Gruppnamn ändrat'; +$messages['groupcreated'] = 'Grupp skapad'; +$messages['savedsearchdeleted'] = 'Sparad sökning borttagen'; $messages['savedsearchdeleteerror'] = 'Kunde inte ta bort sparad sökning'; -$messages['savedsearchcreated'] = 'Sparad sökning tillagd.'; +$messages['savedsearchcreated'] = 'Sparad sökning tillagd'; $messages['savedsearchcreateerror'] = 'Kunde inte lägga till sparad sökning'; -$messages['messagedeleted'] = 'Meddelande borttaget.'; -$messages['messagemoved'] = 'Meddelande flyttat.'; -$messages['messagecopied'] = 'Meddelande kopierat.'; -$messages['messagemarked'] = 'Meddelande markerat.'; +$messages['messagedeleted'] = 'Meddelande borttaget'; +$messages['messagemoved'] = 'Meddelande flyttat'; +$messages['messagecopied'] = 'Meddelande kopierat'; +$messages['messagemarked'] = 'Meddelande markerat'; $messages['autocompletechars'] = 'Ange minst $min tecken för automatisk komplettering'; $messages['autocompletemore'] = 'Flera passande informationsposter funna. Skriv fler tecken.'; $messages['namecannotbeempty'] = 'Namnet fÃ¥r inte vara tomt'; $messages['nametoolong'] = 'Namnet är för lÃ¥ngt'; -$messages['folderupdated'] = 'Katalog uppdaterad.'; -$messages['foldercreated'] = 'Katalog skapad.'; +$messages['folderupdated'] = 'Katalog uppdaterad'; +$messages['foldercreated'] = 'Katalog skapad'; $messages['invalidimageformat'] = 'Ogiltigt bildfilsformat'; $messages['mispellingsfound'] = 'Stavfel hittades i meddelandet'; $messages['parentnotwritable'] = 'Katalogen kunde inte skapas eller flyttas. Ã…tkomsträttighet saknas.'; diff --git a/program/localization/ta_IN/labels.inc b/program/localization/ta_IN/labels.inc index 197e80606..bc1db7d00 100644 --- a/program/localization/ta_IN/labels.inc +++ b/program/localization/ta_IN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'வரைவà¯à®•à®³à¯'; $labels['sent'] = 'அனà¯à®ªà¯à®ªà®¿à®¯ அஞà¯à®šà®²à¯'; $labels['trash'] = 'கà¯à®ªà¯à®ªà¯ˆ'; $labels['junk'] = 'எரிதமà¯'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'தலைபà¯à®ªà¯'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'கà¯à®±à¯à®•à®¿à®¯'; $labels['empty'] = 'காலி'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'பயனà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ அளவà¯'; $labels['unknown'] = 'தெரியாத'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'தேடலை மறà¯à®…மை'; $labels['searchmod'] = 'மாறà¯à®±à®¿à®•à®³à¯ˆ தேடà¯'; $labels['msgtext'] = 'à®®à¯à®´à¯ செயà¯à®¤à®¿'; $labels['body'] = 'Body'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'பà¯à®¤à¯ சாளரதà¯à®¤à®¿à®²à¯ திற'; $labels['emlsave'] = 'பதிவிறகà¯à®•à¯ (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'கடைசி கà¯à®´à¯à®µà¯ˆ காடà¯à®Ÿà $labels['group'] = 'Group'; $labels['groups'] = 'கà¯à®´à¯à®•à¯à®•à®³à¯'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'சà¯à®¯ à®®à¯à®•à®µà®°à®¿'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'as attachment'; diff --git a/program/localization/ta_IN/messages.inc b/program/localization/ta_IN/messages.inc index 22466351a..65e611f88 100644 --- a/program/localization/ta_IN/messages.inc +++ b/program/localization/ta_IN/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'வடிவதà¯à®¤à¯ˆ நீகà¯à®•à¯à®•à®¿à®±à $messages['messageopenerror'] = 'சேவையகதà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ செயà¯à®¤à®¿à®¯à¯ˆ à®à®±à¯à®± à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ'; $messages['fileuploaderror'] = 'கோபà¯à®ªà¯ à®à®±à¯à®±à®®à¯ தோலà¯à®µà®¿à®¯à®Ÿà®¾à®¨à¯à®¤à®¤à¯'; $messages['filesizeerror'] = 'à®à®±à¯à®±à®¿à®¯ கோபà¯à®ªà¯ அதிகபடà¯à®š அளவான $size-஠மீறியதà¯'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'வெறà¯à®±à®¿à®•à®°à®®à®¾à®• $nr à®®à¯à®•à®µà®°à®¿à®•à¯à®•à®³à¯ˆ நகலெடà¯à®¤à¯à®¤à®¤à¯'; +$messages['copyerror'] = 'எநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¯à¯à®®à¯ நகலெடà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ'; $messages['sourceisreadonly'] = 'இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à®¿à®©à¯ மூலதà¯à®¤à¯ˆ படிகà¯à®• மடà¯à®Ÿà¯à®®à¯à®¤à®¾à®©à¯ à®®à¯à®Ÿà®¿à®¯à¯à®®à¯'; $messages['errorsavingcontact'] = 'தொடரà¯à®ªà¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ சேமிகà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ'; $messages['movingmessage'] = 'செயà¯à®¤à®¿à®¯à¯ˆ நகரà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯...'; $messages['copyingmessage'] = 'Copying message(s)...'; $messages['copyingcontact'] = 'Copying contact(s)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Deleting message(s)...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'à®à®±à¯à®±à¯à®•à®¿à®±à®¤à¯, தயவ௠செ஠$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>வெறà¯à®±à®¿à®•à®°à®®à®¾à®• $inserted தொடரà¯à®ªà¯à®•à®³à¯ à®à®±à¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯, à®à®±à¯à®•à®©à®µà¯‡ உளà¯à®³ $skipped தொடரà¯à®ªà¯à®•à®³à¯ தவிரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</b>: <p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'பணி அனà¯à®®à®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ!'; $messages['nofromaddress'] = 'நீஙà¯à®•à®³à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®¤à¯à®¤ அடையாளதà¯à®¤à®¿à®²à¯ மினà¯à®©à®žà¯à®šà®²à¯ இலà¯à®²à¯ˆ'; $messages['editorwarning'] = 'எளிய உரை திரà¯à®¤à¯à®¤à®¿à®•à¯à®•à¯ மாறà¯à®µà®¤à®©à¯ மூலம௠எலà¯à®²à®¾ உரை வடிவஙà¯à®•à®³à¯à®®à¯ தொலைநà¯à®¤à¯ போகக௠கூடà¯à®®à¯. தொடர விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à®¾ ?'; diff --git a/program/localization/th_TH/labels.inc b/program/localization/th_TH/labels.inc index 85b091e5b..03b4161fb 100644 --- a/program/localization/th_TH/labels.inc +++ b/program/localization/th_TH/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'à¸à¸¥à¹ˆà¸à¸‡à¸ˆà¸”หมายร่าง'; $labels['sent'] = 'à¸à¸¥à¹ˆà¸à¸‡à¸‚าà¸à¸à¸'; $labels['trash'] = 'ถังขยะ'; $labels['junk'] = 'à¸à¸¥à¹ˆà¸à¸‡à¸ˆà¸”หมายขยะ'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'หัวจดหมาย'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'à¹à¸šà¸šà¸¢à¹ˆà¸'; $labels['empty'] = 'ว่างเปล่า'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'พื้นที่ใช้งาน'; $labels['unknown'] = 'ไม่ทราบ'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'ล้างà¸à¸²à¸£à¸„้นหา'; $labels['searchmod'] = 'Search modifiers'; $labels['msgtext'] = 'Entire message'; $labels['body'] = 'เนื้à¸à¸«à¸²'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Open in new window'; $labels['emlsave'] = 'Download (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Show last page'; $labels['group'] = 'Group'; $labels['groups'] = 'Groups'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Personal Addresses'; $labels['searchsave'] = 'Save search'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Ignore words with numbers'; $labels['spellcheckignorecaps'] = 'Ignore words with all letters capitalized'; $labels['addtodict'] = 'Add to dictionary'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Messages forwarding'; $labels['inline'] = 'inline'; $labels['asattachment'] = 'เป็นไฟล์à¹à¸™à¸š'; diff --git a/program/localization/th_TH/messages.inc b/program/localization/th_TH/messages.inc index cf9a1cde8..826930c0e 100644 --- a/program/localization/th_TH/messages.inc +++ b/program/localization/th_TH/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'นำเà¸à¸²à¸«à¸²à¸£à¸ˆà¸±à¸”รูปà¹à¸šà¸šà¹ $messages['messageopenerror'] = 'ไม่สามารถà¸à¹ˆà¸²à¸™à¸ˆà¸”หมายจาภServer ได้'; $messages['fileuploaderror'] = 'à¸à¸²à¸£à¸à¸±à¸žà¹‚หลดล้มเหลว'; $messages['filesizeerror'] = 'ไฟล์มีขนาดใหà¸à¹ˆà¹€à¸à¸´à¸™ $size'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'คัดลà¸à¸à¸ˆà¸”หมายจำนวน $nr ฉบับเรียบร้à¸à¸¢'; +$messages['copyerror'] = 'ไม่สามารถคัดลà¸à¸à¹„ด้'; $messages['sourceisreadonly'] = 'จดหมายนี้เป็นà¹à¸šà¸šà¸à¹ˆà¸²à¸™à¸à¸¢à¹ˆà¸²à¸‡à¹€à¸”ียว'; $messages['errorsavingcontact'] = 'ไม่สามารถบันทึà¸à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸à¹„ด้'; $messages['movingmessage'] = 'à¸à¸³à¸¥à¸±à¸‡à¸¢à¹‰à¸²à¸¢à¸‚้à¸à¸„วาม...'; $messages['copyingmessage'] = 'à¸à¸³à¸¥à¸±à¸‡à¸„ัดลà¸à¸à¸‚้à¸à¸„วาม...'; $messages['copyingcontact'] = 'à¸à¸³à¸¥à¸±à¸‡à¸„ัดลà¸à¸à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸à¸œà¸¹à¹‰à¸•à¸´à¸”ต่à¸...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'à¸à¸³à¸¥à¸±à¸‡à¸¥à¸šà¸‚้à¸à¸„วาม...'; $messages['markingmessage'] = 'Marking message(s)...'; $messages['addingmember'] = 'Adding contact(s) to the group...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้าข้à¸à¸¡à¸¹à¸¥, $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = '<b>Successfully imported $inserted contacts</b>'; $messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/localization/tr_TR/labels.inc b/program/localization/tr_TR/labels.inc index c62c5c079..9e78ea3fa 100644 --- a/program/localization/tr_TR/labels.inc +++ b/program/localization/tr_TR/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'Taslaklar'; $labels['sent'] = 'Giden'; $labels['trash'] = 'Çöp'; $labels['junk'] = 'Ä°stenmeyen'; -$labels['show_real_foldernames'] = 'Özel klasörler için gerçek isimleri göster'; // message listing $labels['subject'] = 'Konu'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Liste görünümü'; $labels['folderactions'] = 'Klasör eylemleri...'; $labels['compact'] = 'SıklaÅŸtır'; $labels['empty'] = 'BoÅŸalt'; -$labels['importmessages'] = 'Mesajları içe aktar'; $labels['quota'] = 'Disk kullanımı'; $labels['unknown'] = 'bilinmeyen'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Aramayı bitir'; $labels['searchmod'] = 'Arama detayları'; $labels['msgtext'] = 'Tüm posta gövdesi'; $labels['body'] = 'Gövde'; -$labels['type'] = 'Tip'; $labels['openinextwin'] = 'Yeni pencerede aç'; $labels['emlsave'] = 'Ä°ndir (.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Sonuncuyu göster'; $labels['group'] = 'Grup'; $labels['groups'] = 'Gruplar'; -$labels['listgroup'] = 'Grup üyelerini listele'; $labels['personaladrbook'] = 'Adresler'; $labels['searchsave'] = 'Aramayı kaydet'; @@ -406,7 +402,7 @@ $labels['htmleditor'] = 'HTML postaları oluÅŸtur'; $labels['htmlonreply'] = 'sadece HTML postaları yanıtlarken'; $labels['htmlonreplyandforward'] = 'HTML biçimindeki posta yanıtlandığında veye iletildiÄŸinde'; $labels['htmlsignature'] = 'HTML imza'; -$labels['showemail'] = 'Eposta adresini görünüm ismi ile görüntüle'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Önizleme panelini göster'; $labels['skin'] = 'Arayüz görünümü'; $labels['logoutclear'] = 'Oturumu kapatınca Çöpü temizle'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'İçinde rakam geçen kelimleri göz ardı et $labels['spellcheckignorecaps'] = 'Tümü büyük harf olan kelimleri göz ardı et'; $labels['addtodict'] = 'Sözlüğe Ekle'; $labels['mailtoprotohandler'] = 'mailto: baÄŸlantıları için protokol iÅŸleyici kayıt et'; -$labels['standardwindows'] = 'Popup pencerelerini standart pencere olarak yönet'; $labels['forwardmode'] = 'Posta yönlendirme'; $labels['inline'] = 'postanın içinde'; $labels['asattachment'] = 'ek olarak'; diff --git a/program/localization/tr_TR/messages.inc b/program/localization/tr_TR/messages.inc index 3f728b523..3b451d556 100644 --- a/program/localization/tr_TR/messages.inc +++ b/program/localization/tr_TR/messages.inc @@ -126,8 +126,6 @@ $messages['importwait'] = 'Aktarılıyor, lütfen bekleyin...'; $messages['importformaterror'] = 'İçe aktarım baÅŸarısız. Yüklenen dosya geçerli bir içe aktarım dosyası deÄŸil.'; $messages['importconfirm'] = '<b>$inserted kiÅŸi baÅŸarıyla aktarıldı</b>'; $messages['importconfirmskipped'] = '<b>Var olan $skipped girdi atlandı</b>'; -$messages['importmessagesuccess'] = '$nr adet mesaj baÅŸarıyla içe aktarıldı'; -$messages['importmessageerror'] = 'İçe aktarım baÅŸarısız. Yüklenen dosya geçerli bir içe aktarım dosyası deÄŸil.'; $messages['opnotpermitted'] = 'Bu iÅŸleme izin verilmedi!'; $messages['nofromaddress'] = 'Seçili kimlikte e-posta adresi yok'; $messages['editorwarning'] = 'Düz metin düzenleyiciye geçmek, metin üzerindeki bütün biçimlendirmeleri kaldıracak. Devam etmek istiyor musunuz?'; diff --git a/program/localization/uk_UA/labels.inc b/program/localization/uk_UA/labels.inc index 6ff37ee21..6675e177e 100644 --- a/program/localization/uk_UA/labels.inc +++ b/program/localization/uk_UA/labels.inc @@ -19,11 +19,11 @@ $labels = array(); // login page -$labels['welcome'] = 'ЛаÑкаво проÑимо до $product'; -$labels['username'] = 'Ім\'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача'; -$labels['password'] = 'Пароль'; -$labels['server'] = 'Сервер'; -$labels['login'] = 'Увійти'; +$labels['welcome'] = 'ЛаÑкаво проÑимо!'; +$labels['username'] = 'Ім\'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача'; +$labels['password'] = 'Пароль'; +$labels['server'] = 'Сервер'; +$labels['login'] = 'Увійти'; // taskbar $labels['logout'] = 'Вийти'; @@ -35,37 +35,36 @@ $labels['addressbook'] = 'Контакти'; $labels['inbox'] = 'Вхідні'; $labels['drafts'] = 'Чернетки'; $labels['sent'] = 'ÐадіÑлані'; -$labels['trash'] = 'Кошик'; +$labels['trash'] = 'Видалені'; $labels['junk'] = 'Спам'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing -$labels['subject'] = 'Тема'; -$labels['from'] = 'Відправник'; -$labels['sender'] = 'Відправник'; -$labels['to'] = 'Кому'; -$labels['cc'] = 'КопіÑ'; -$labels['bcc'] = 'Прихована'; -$labels['replyto'] = 'Ð—Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ñ Ð°Ð´Ñ€ÐµÑа'; -$labels['followupto'] = 'Followup-To'; -$labels['date'] = 'Дата'; -$labels['size'] = 'Розмір'; +$labels['subject'] = 'Тема'; +$labels['from'] = 'Від'; +$labels['sender'] = 'Відправник'; +$labels['to'] = 'Кому'; +$labels['cc'] = 'КопіÑ'; +$labels['bcc'] = 'Прихована'; +$labels['replyto'] = 'Ð—Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ñ Ð°Ð´Ñ€ÐµÑа'; +$labels['followupto'] = 'У відповідь'; +$labels['date'] = 'Дата'; +$labels['size'] = 'Розмір'; $labels['priority'] = 'Пріоритет'; $labels['organization'] = 'ОрганізаціÑ'; $labels['readstatus'] = 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ'; -$labels['listoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÑпиÑку...'; +$labels['listoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð³Ð»Ñду...'; $labels['mailboxlist'] = 'Папки'; -$labels['messagesfromto'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· $from по $to із $count'; +$labels['messagesfromto'] = 'ЛиÑÑ‚ з $from по $to із $count'; $labels['threadsfromto'] = 'ÐžÐ±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð· $from по $to із $count'; $labels['messagenrof'] = 'ЛиÑÑ‚ $nr із $count'; $labels['fromtoshort'] = '$from – $to з $count'; $labels['copy'] = 'Копіювати'; $labels['move'] = 'ПереміÑтити'; -$labels['moveto'] = 'ПереміÑтити до...'; +$labels['moveto'] = 'ПереміÑтити лиÑÑ‚ у...'; $labels['download'] = 'Завантажити'; -$labels['open'] = 'Open'; +$labels['open'] = 'Відкрити'; $labels['showattachment'] = 'Показати'; $labels['showanyway'] = 'Ð’Ñе одно показати'; @@ -93,238 +92,236 @@ $labels['friday'] = 'П\'ÑтницÑ'; $labels['saturday'] = 'Субота'; // months short -$labels['jan'] = 'Ñіч'; -$labels['feb'] = 'лют'; -$labels['mar'] = 'бер'; -$labels['apr'] = 'квіт'; -$labels['may'] = 'Травень'; -$labels['jun'] = 'чер'; -$labels['jul'] = 'лип'; -$labels['aug'] = 'Ñер'; -$labels['sep'] = 'вер'; -$labels['oct'] = 'жов'; -$labels['nov'] = 'лиÑ'; -$labels['dec'] = 'гр'; +$labels['jan'] = 'Ñіч'; +$labels['feb'] = 'лют'; +$labels['mar'] = 'бер'; +$labels['apr'] = 'кві'; +$labels['may'] = 'тра'; +$labels['jun'] = 'чер'; +$labels['jul'] = 'лип'; +$labels['aug'] = 'Ñер'; +$labels['sep'] = 'вер'; +$labels['oct'] = 'жов'; +$labels['nov'] = 'лиÑ'; +$labels['dec'] = 'гру'; // months long -$labels['longjan'] = 'Січень'; -$labels['longfeb'] = 'Лютий'; -$labels['longmar'] = 'Березень'; -$labels['longapr'] = 'Квітень'; -$labels['longmay'] = 'Травень'; -$labels['longjun'] = 'Червень'; -$labels['longjul'] = 'Липень'; -$labels['longaug'] = 'Серпень'; -$labels['longsep'] = 'ВереÑень'; -$labels['longoct'] = 'Жовтень'; -$labels['longnov'] = 'ЛиÑтопад'; -$labels['longdec'] = 'Грудень'; +$labels['longjan'] = 'Січень'; +$labels['longfeb'] = 'Лютий'; +$labels['longmar'] = 'Березень'; +$labels['longapr'] = 'Квітень'; +$labels['longmay'] = 'Травень'; +$labels['longjun'] = 'Червень'; +$labels['longjul'] = 'Липень'; +$labels['longaug'] = 'Серпень'; +$labels['longsep'] = 'ВереÑень'; +$labels['longoct'] = 'Жовтень'; +$labels['longnov'] = 'ЛиÑтопад'; +$labels['longdec'] = 'Грудень'; $labels['today'] = 'Сьогодні'; // toolbar buttons -$labels['refresh'] = 'Оновити'; -$labels['checkmail'] = 'Перевірити пошту'; -$labels['compose'] = 'ÐапиÑати лиÑта'; -$labels['writenewmessage'] = 'ÐапиÑати лиÑта'; -$labels['reply'] = 'ВідповіÑти'; -$labels['replytomessage'] = 'ВідповіÑти відправнику'; -$labels['replytoallmessage'] = 'ВідповіÑти до лиÑта або відправнику та уÑім отримувачам'; -$labels['replyall'] = 'ВідповіÑти уÑім'; -$labels['replylist'] = 'ВідповіÑти до лиÑта'; -$labels['forward'] = 'ПереÑлати'; -$labels['forwardinline'] = 'ПереÑлати у тілі лиÑта'; -$labels['forwardattachment'] = 'ПереÑлати Ñк прикріпленнÑ'; -$labels['forwardmessage'] = 'ПереÑлати повідомленнÑ'; -$labels['deletemessage'] = 'У кошик'; -$labels['movemessagetotrash'] = 'ПереміÑтити лиÑÑ‚ у кошик'; -$labels['printmessage'] = 'Друкувати'; -$labels['previousmessage'] = 'Показати попередній лиÑÑ‚'; -$labels['firstmessage'] = 'Показати перший лиÑÑ‚'; -$labels['nextmessage'] = 'Показати наÑтупний лиÑÑ‚'; -$labels['lastmessage'] = 'Показати оÑтанній лиÑÑ‚'; -$labels['backtolist'] = 'До переліку лиÑтів'; -$labels['viewsource'] = 'Вихідний текÑÑ‚'; -$labels['mark'] = 'Помітити'; -$labels['markmessages'] = 'Позначити лиÑти'; -$labels['markread'] = 'Позначити Ñк прочитане'; -$labels['markunread'] = 'Позначити Ñк непрочитане'; -$labels['markflagged'] = 'Додати зірочку'; -$labels['markunflagged'] = 'ЗнÑти зірочку'; -$labels['moreactions'] = 'Інші дії...'; -$labels['more'] = 'Ще'; -$labels['back'] = 'Ðазад'; -$labels['options'] = 'Параметри'; - -$labels['select'] = 'Вибрати'; -$labels['all'] = 'Ð’ÑÑ–'; -$labels['none'] = 'Ðе Ñортувати'; -$labels['currpage'] = 'Поточна Ñторінка'; -$labels['unread'] = 'Ðепрочитані'; -$labels['flagged'] = 'Із зірочкою'; +$labels['refresh'] = 'Оновити'; +$labels['checkmail'] = 'Перевірити пошту'; +$labels['compose'] = 'ÐапиÑати лиÑта'; +$labels['writenewmessage'] = 'ÐапиÑати лиÑта'; +$labels['reply'] = 'ВідповіÑти'; +$labels['replytomessage'] = 'ВідповіÑти відправнику'; +$labels['replytoallmessage'] = 'ВідповіÑти відправнику та уÑім отримувачам'; +$labels['replyall'] = 'ВідповіÑти уÑім'; +$labels['replylist'] = 'ВідповіÑти уÑім отримувачам'; +$labels['forward'] = 'ПереÑлати'; +$labels['forwardinline'] = 'ПереÑлати у тілі лиÑта'; +$labels['forwardattachment'] = 'ПереÑлати Ñк додаток'; +$labels['forwardmessage'] = 'ПереÑлати лиÑÑ‚'; +$labels['deletemessage'] = 'Видалити'; +$labels['movemessagetotrash'] = 'ПереміÑтити у Видалені'; +$labels['printmessage'] = 'Друкувати'; +$labels['previousmessage'] = 'Показати попередній лиÑÑ‚'; +$labels['firstmessage'] = 'Показати перший лиÑÑ‚'; +$labels['nextmessage'] = 'Показати наÑтупний лиÑÑ‚'; +$labels['lastmessage'] = 'Показати оÑтанній лиÑÑ‚'; +$labels['backtolist'] = 'До переліку лиÑтів'; +$labels['viewsource'] = 'Вихідний текÑÑ‚'; +$labels['mark'] = 'Позначити'; +$labels['markmessages'] = 'Позначити лиÑти'; +$labels['markread'] = 'Позначити Ñк прочитаний'; +$labels['markunread'] = 'Позначити Ñк непрочитаний'; +$labels['markflagged'] = 'ПоÑтавити позначку'; +$labels['markunflagged'] = 'ЗнÑти позначку'; +$labels['moreactions'] = 'Інші дії...'; +$labels['more'] = 'Ще'; +$labels['back'] = 'Ðазад'; +$labels['options'] = 'Параметри'; + +$labels['select'] = 'Вибрати'; +$labels['all'] = 'УÑÑ–'; +$labels['none'] = 'Ðе Ñортувати'; +$labels['currpage'] = 'Поточна Ñторінка'; +$labels['unread'] = 'Ðепрочитані'; +$labels['flagged'] = 'З позначкою'; $labels['unanswered'] = 'Без відповіді'; -$labels['withattachment'] = 'With attachment'; -$labels['deleted'] = 'Видалені'; -$labels['undeleted'] = 'Ðе видалено'; -$labels['invert'] = 'Інвертувати виділеннÑ'; -$labels['filter'] = 'Фільтр'; -$labels['list'] = 'СпиÑком'; -$labels['threads'] = 'Гілки'; -$labels['expand-all'] = 'Розкрити вÑÑ–'; -$labels['expand-unread'] = 'Розкрити непрочитані'; -$labels['collapse-all'] = 'Згорнути вÑÑ–'; -$labels['threaded'] = 'Гілками'; - -$labels['autoexpand_threads'] = 'Розкривати гілки'; +$labels['withattachment'] = 'З додатком'; +$labels['deleted'] = 'Видалені'; +$labels['undeleted'] = 'Ðе видалені'; +$labels['invert'] = 'Інвертувати вибір'; +$labels['filter'] = 'Фільтр'; +$labels['list'] = 'СпиÑок'; +$labels['threads'] = 'Гілки'; +$labels['expand-all'] = 'Розгорнути уÑÑ–'; +$labels['expand-unread'] = 'Розгорнути непрочитані'; +$labels['collapse-all'] = 'Згорнути уÑÑ–'; +$labels['threaded'] = 'Гілками'; + +$labels['autoexpand_threads'] = 'Ðвтоматично розгортати гілки'; $labels['do_expand'] = 'уÑÑ– гілки'; $labels['expand_only_unread'] = 'тільки з непрочитаними лиÑтами'; -$labels['fromto'] = 'Відправник/Одержувач'; -$labels['flag'] = 'Позначка'; -$labels['attachment'] = 'ВкладеннÑ'; -$labels['nonesort'] = 'Ðе Ñортувати'; -$labels['sentdate'] = 'Дата відправленнÑ'; -$labels['arrival'] = 'Дата ориманнÑ'; -$labels['asc'] = 'за зроÑтаннÑм'; -$labels['desc'] = 'за ÑпаданнÑм'; +$labels['fromto'] = 'Відправник/Одержувач'; +$labels['flag'] = 'Позначка'; +$labels['attachment'] = 'Додаток'; +$labels['nonesort'] = 'Ðе Ñортувати'; +$labels['sentdate'] = 'Дата відправленнÑ'; +$labels['arrival'] = 'Дата отриманнÑ'; +$labels['asc'] = 'За зроÑтаннÑм'; +$labels['desc'] = 'За ÑпаданнÑм'; $labels['listcolumns'] = 'Ðтрибути Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ'; $labels['listsorting'] = 'Сортувати за атрибутом'; $labels['listorder'] = 'ПорÑдок ÑортуваннÑ'; -$labels['listmode'] = 'Режим переглÑду'; +$labels['listmode'] = 'Режим переглÑду'; $labels['folderactions'] = 'Операції з папкою...'; $labels['compact'] = 'СтиÑнути'; $labels['empty'] = 'Спорожнити'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ВикориÑтано'; -$labels['unknown'] = 'невідомо'; -$labels['unlimited'] = 'без обмеженнÑ'; +$labels['unknown'] = 'невідомо'; +$labels['unlimited'] = 'без обмеженнÑ'; -$labels['quicksearch'] = 'Швидкий пошук'; -$labels['resetsearch'] = 'ОчиÑтити пошук'; -$labels['searchmod'] = 'Де шукати'; -$labels['msgtext'] = 'Ð’ уÑьому лиÑÑ‚Ñ–'; -$labels['body'] = 'Тіло повідомленнÑ'; -$labels['type'] = 'Type'; +$labels['quicksearch'] = 'Швидкий пошук'; +$labels['resetsearch'] = 'ОчиÑтити пошук'; +$labels['searchmod'] = 'Де шукати'; +$labels['msgtext'] = 'ВеÑÑŒ лиÑÑ‚'; +$labels['body'] = 'ТекÑÑ‚ лиÑта'; -$labels['openinextwin'] = 'Відкрити в новому вікні'; +$labels['openinextwin'] = 'Відкрити у новому вікні'; $labels['emlsave'] = 'Зберегти (.eml)'; -$labels['changeformattext'] = 'Display in plain text format'; -$labels['changeformathtml'] = 'Display in HTML format'; +$labels['changeformattext'] = 'Показати Ñк звичайний текÑÑ‚'; +$labels['changeformathtml'] = 'Показати Ñк HTML'; // message compose -$labels['editasnew'] = 'Редагувати Ñк новий'; -$labels['send'] = 'Відправлено'; -$labels['sendmessage'] = 'ÐадіÑлати зараз'; -$labels['savemessage'] = 'Зберегти чернетку'; -$labels['addattachment'] = 'ВклаÑти файл'; -$labels['charset'] = 'КодуваннÑ'; -$labels['editortype'] = 'Редактор'; -$labels['returnreceipt'] = 'Запит відповіді'; -$labels['dsn'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ доÑтавку'; +$labels['editasnew'] = 'Редагувати Ñк новий'; +$labels['send'] = 'Відправлено'; +$labels['sendmessage'] = 'ÐадіÑлати зараз'; +$labels['savemessage'] = 'Зберегти чернетку'; +$labels['addattachment'] = 'Додати файл'; +$labels['charset'] = 'КодуваннÑ'; +$labels['editortype'] = 'Редактор'; +$labels['returnreceipt'] = 'Повідомити про прочитаннÑ'; +$labels['dsn'] = 'Повідомити про доÑтавку'; $labels['mailreplyintro'] = '$date, $sender напиÑав:'; -$labels['originalmessage'] = 'Оригінальне повідомленнÑ'; +$labels['originalmessage'] = 'Оригінальний лиÑÑ‚'; -$labels['editidents'] = 'Змінити данні'; -$labels['spellcheck'] = 'ОрфографіÑ'; +$labels['editidents'] = 'Змінити дані'; +$labels['spellcheck'] = 'ОрфографіÑ'; $labels['checkspelling'] = 'Перевірити орфографію'; $labels['resumeediting'] = 'Продовжити редагуваннÑ'; -$labels['revertto'] = 'Відмінити редагуваннÑ'; +$labels['revertto'] = 'Відмінити редагуваннÑ'; -$labels['attach'] = 'ВклаÑти'; -$labels['attachments'] = 'Вкладені файли'; -$labels['upload'] = 'ВклаÑти'; +$labels['attach'] = 'Додати'; +$labels['attachments'] = 'Додані файли'; +$labels['upload'] = 'Завантажити'; $labels['uploadprogress'] = '$percent ($current з $total)'; -$labels['close'] = 'Закрити'; -$labels['messageoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð»Ð¸Ñтів'; +$labels['close'] = 'Закрити'; +$labels['messageoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð»Ð¸Ñта'; -$labels['low'] = 'Ðизький'; -$labels['lowest'] = 'Ðайнижчий'; -$labels['normal'] = 'Ðормальний'; -$labels['high'] = 'ВиÑокий'; -$labels['highest'] = 'Ðайвищий'; +$labels['low'] = 'низький'; +$labels['lowest'] = 'найнижчий'; +$labels['normal'] = 'нормальний'; +$labels['high'] = 'виÑокий'; +$labels['highest'] = 'найвищий'; $labels['nosubject'] = '(без теми)'; $labels['showimages'] = 'Показувати зображеннÑ'; $labels['alwaysshow'] = 'Завжди показувати Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ $sender'; $labels['isdraft'] = 'Це чернетка.'; $labels['andnmore'] = 'ще $nr...'; -$labels['togglemoreheaders'] = 'Завантажити ще заголовки повідомлень'; -$labels['togglefullheaders'] = 'Показати оригінальні заголовки повідомленнÑ'; +$labels['togglemoreheaders'] = 'Показати більше заголовків лиÑта'; +$labels['togglefullheaders'] = 'Показати уÑÑ– заголовки лиÑта'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Звичайний текÑÑ‚'; -$labels['savesentmessagein'] = 'зберегти надіÑланого лиÑта в'; +$labels['savesentmessagein'] = 'Зберегти надіÑланого лиÑта у'; $labels['dontsave'] = 'не зберігати'; $labels['maxuploadsize'] = 'МакÑимальний розмір файлу $size'; $labels['addcc'] = 'Додати копію'; $labels['addbcc'] = 'Додати приховану копію'; $labels['addreplyto'] = 'Додати зворотню адреÑу'; -$labels['addfollowupto'] = 'Додати Followup-To'; +$labels['addfollowupto'] = 'Додати у відповідь'; // mdn -$labels['mdnrequest'] = 'Відправник цього лиÑта запитав про прочитаннÑ. Повідомити відправника?'; +$labels['mdnrequest'] = 'Відправник цього лиÑта запитує про його прочитаннÑ. Повідомити відправника?'; $labels['receiptread'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ прочитаннÑ'; $labels['yourmessage'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð’Ð°ÑˆÐ¾Ð³Ð¾ лиÑта'; -$labels['receiptnote'] = 'ЗауваженнÑ: Це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¾Ð·Ð½Ð°Ñ‡Ð°Ñ” лише, що лиÑта було відкрито одержувачем, Ñ– не гарантує того, що його було прочитано.'; +$labels['receiptnote'] = 'ЗауваженнÑ: Це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¾Ð·Ð½Ð°Ñ‡Ð°Ñ” лише те, що лиÑта було відкрито одержувачем, Ñ– не гарантує того, що його було прочитано.'; // address boook -$labels['name'] = 'Ім`Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ'; -$labels['firstname'] = 'Ім`Ñ'; -$labels['surname'] = 'Прізвище'; -$labels['middlename'] = 'По-батькові'; -$labels['nameprefix'] = 'ПрефікÑ'; -$labels['namesuffix'] = 'СуфікÑ'; -$labels['nickname'] = 'Ðікнейм'; -$labels['jobtitle'] = 'ПоÑада'; -$labels['department'] = 'Відділ'; -$labels['gender'] = 'Стать'; -$labels['maidenname'] = 'Дівоче прізвище'; -$labels['email'] = 'Електронна адреÑа'; -$labels['phone'] = 'Телефон'; -$labels['address'] = 'ÐдреÑа'; -$labels['street'] = 'ВулицÑ'; -$labels['locality'] = 'МіÑто'; -$labels['zipcode'] = 'ІндекÑ'; -$labels['region'] = 'ОблаÑÑ‚ÑŒ'; -$labels['country'] = 'Страна'; -$labels['birthday'] = 'Дата народженнÑ'; -$labels['anniversary'] = 'Ювілей'; -$labels['website'] = 'Веб-Ñайт'; +$labels['name'] = 'Ім\'Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ'; +$labels['firstname'] = 'Ім\'Ñ'; +$labels['surname'] = 'Прізвище'; +$labels['middlename'] = 'По-батькові'; +$labels['nameprefix'] = 'ПрефікÑ'; +$labels['namesuffix'] = 'СуфікÑ'; +$labels['nickname'] = 'ПрізвиÑько'; +$labels['jobtitle'] = 'ПоÑада'; +$labels['department'] = 'Відділ'; +$labels['gender'] = 'Стать'; +$labels['maidenname'] = 'Дівоче прізвище'; +$labels['email'] = 'Електронна адреÑа'; +$labels['phone'] = 'Телефон'; +$labels['address'] = 'ÐдреÑа'; +$labels['street'] = 'ВулицÑ'; +$labels['locality'] = 'МіÑто'; +$labels['zipcode'] = 'ІндекÑ'; +$labels['region'] = 'ОблаÑÑ‚ÑŒ'; +$labels['country'] = 'Країна'; +$labels['birthday'] = 'День народженнÑ'; +$labels['anniversary'] = 'Ювілей'; +$labels['website'] = 'Веб-Ñайт'; $labels['instantmessenger'] = 'IM'; -$labels['notes'] = 'Примітки'; -$labels['male'] = 'чоловічий'; -$labels['female'] = 'жіночий'; -$labels['manager'] = 'Менеждер'; -$labels['assistant'] = 'Помічник'; -$labels['spouse'] = 'Шлюбний партнер'; -$labels['allfields'] = 'УÑÑ– полÑ'; -$labels['search'] = 'Пошук'; -$labels['advsearch'] = 'Розширений пошук'; -$labels['advanced'] = 'Додатково'; -$labels['other'] = 'Інше'; +$labels['notes'] = 'Примітки'; +$labels['male'] = 'чоловіча'; +$labels['female'] = 'жіноча'; +$labels['manager'] = 'Менеджер'; +$labels['assistant'] = 'Помічник'; +$labels['spouse'] = 'У шлюбі з'; +$labels['allfields'] = 'УÑÑ– полÑ'; +$labels['search'] = 'Пошук'; +$labels['advsearch'] = 'Розширений пошук'; +$labels['advanced'] = 'Додатково'; +$labels['other'] = 'Інше'; $labels['typehome'] = 'Дім'; $labels['typework'] = 'Робота'; $labels['typeother'] = 'Інше'; -$labels['typemobile'] = 'Мобільний'; -$labels['typemain'] = 'ОÑновний'; -$labels['typehomefax'] = 'Домашній факÑ'; -$labels['typeworkfax'] = 'Робочий факÑ'; -$labels['typecar'] = 'Ðвтомобіль'; +$labels['typemobile'] = 'Мобільний'; +$labels['typemain'] = 'ОÑновний'; +$labels['typehomefax'] = 'Домашній факÑ'; +$labels['typeworkfax'] = 'Робочий факÑ'; +$labels['typecar'] = 'Ðвтомобіль'; $labels['typepager'] = 'Пейджер'; $labels['typevideo'] = 'Відео'; -$labels['typeassistant'] = 'Помічник'; -$labels['typehomepage'] = 'Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка'; -$labels['typeblog'] = 'Блог'; +$labels['typeassistant'] = 'Помічник'; +$labels['typehomepage'] = 'Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка'; +$labels['typeblog'] = 'Блог'; $labels['typeprofile'] = 'Профіль'; $labels['addfield'] = 'Додати поле...'; -$labels['addcontact'] = 'Додати вибрані контакти до ÑпиÑку контактів'; +$labels['addcontact'] = 'Додати обрані контакти до ÑпиÑку контактів'; $labels['editcontact'] = 'Редагувати контакт'; $labels['contacts'] = 'Контакти'; -$labels['contactproperties'] = 'ВлаÑтивоÑÑ‚Ñ– контакта'; +$labels['contactproperties'] = 'ВлаÑтивоÑÑ‚Ñ– контакту'; $labels['personalinfo'] = 'ОÑобова інформаціÑ'; $labels['edit'] = 'Правка'; @@ -336,39 +333,38 @@ $labels['addphoto'] = 'Додати'; $labels['replacephoto'] = 'Замінити'; $labels['uploadphoto'] = 'Завантажити фотографію'; -$labels['newcontact'] = 'Створити новий контакт'; -$labels['deletecontact'] = 'Видалити вибрані контакти'; -$labels['composeto'] = 'Створити лиÑта Ð´Ð»Ñ Ð²Ð¸Ð±Ñ€Ð°Ð½Ð½Ð¸Ñ… контактів'; +$labels['newcontact'] = 'Створити новий контакт'; +$labels['deletecontact'] = 'Видалити обрані контакти'; +$labels['composeto'] = 'ÐапиÑати лиÑта до обраних контактів'; $labels['contactsfromto'] = 'Контакти $from - $to / $count'; -$labels['print'] = 'Друкувати'; -$labels['export'] = 'ЕкÑпортувати'; -$labels['exportall'] = 'ЕкÑпортувати вÑе'; -$labels['exportsel'] = 'ЕкÑпортувати виділені'; -$labels['exportvcards'] = 'ЕкÑпортувати контакти у формат vCard'; +$labels['print'] = 'Друкувати'; +$labels['export'] = 'ЕкÑпортувати'; +$labels['exportall'] = 'ЕкÑпортувати вÑе'; +$labels['exportsel'] = 'ЕкÑпортувати обрані'; +$labels['exportvcards'] = 'ЕкÑпортувати контакти у формат vCard'; $labels['newcontactgroup'] = 'Створити нову групу контактів'; -$labels['grouprename'] = 'Перейменувати групу'; -$labels['groupdelete'] = 'Видалити групу'; +$labels['grouprename'] = 'Перейменувати групу'; +$labels['groupdelete'] = 'Видалити групу'; $labels['groupremoveselected'] = 'Видалити обрані контакти з групи'; -$labels['previouspage'] = 'ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ Ñторінка'; -$labels['firstpage'] = 'Перша Ñторінка'; -$labels['nextpage'] = 'ÐаÑтупна Ñторінка'; -$labels['lastpage'] = 'ОÑÑ‚Ð°Ð½Ð½Ñ Ñторінка'; +$labels['previouspage'] = 'ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ Ñторінка'; +$labels['firstpage'] = 'Перша Ñторінка'; +$labels['nextpage'] = 'ÐаÑтупна Ñторінка'; +$labels['lastpage'] = 'ОÑÑ‚Ð°Ð½Ð½Ñ Ñторінка'; $labels['group'] = 'Група'; $labels['groups'] = 'Групи'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'ПерÑональні адреÑи'; -$labels['searchsave'] = 'Зберегти пошук'; -$labels['searchdelete'] = 'Видалити пошук'; +$labels['searchsave'] = 'Зберегти пошуковий запит'; +$labels['searchdelete'] = 'Видалити пошуковий запит'; $labels['import'] = 'Імпорт'; $labels['importcontacts'] = 'Імпортувати контакти'; $labels['importfromfile'] = 'Імпортувати з файлу:'; $labels['importtarget'] = 'Додати нові контакти до адреÑної книги'; $labels['importreplace'] = 'Замінити вÑÑŽ адреÑну книгу'; -$labels['importdesc'] = 'Ви можете завантажити контакти з Ñ–Ñнуючої адреÑної книги.<br/>Ð’ даний Ñ‡Ð°Ñ Ð¼Ð¸ підтримуємо імпорт Ð°Ð´Ñ€ÐµÑ Ð² форматі візитної картки <a href="http://en.wikipedia.org/wiki/VCard"> vCard</ a> або CSV (дані розділені комами).'; +$labels['importdesc'] = 'Ви можете завантажити контакти з Ñ–Ñнуючої адреÑної книги.<br/>Ð’ даний Ñ‡Ð°Ñ Ð¼Ð¸ підтримуємо імпорт Ð°Ð´Ñ€ÐµÑ Ñƒ форматі візитної картки <a href="http://en.wikipedia.org/wiki/VCard"> vCard</ a> або CSV (дані розділені комами).'; $labels['done'] = 'Готово'; // settings @@ -385,31 +381,31 @@ $labels['newidentity'] = 'Ðовий профіль'; $labels['newitem'] = 'Ðовий'; $labels['edititem'] = 'Редагувати'; -$labels['preferhtml'] = 'Показувати в HTML'; -$labels['defaultcharset'] = 'ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуванннÑм'; +$labels['preferhtml'] = 'Показувати у HTML'; +$labels['defaultcharset'] = 'ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм'; $labels['htmlmessage'] = 'ЛиÑÑ‚ у HTML'; $labels['messagepart'] = 'ЧаÑтина'; $labels['digitalsig'] = 'Цифровий підпиÑ'; $labels['dateformat'] = 'Формат дати'; $labels['timeformat'] = 'Формат чаÑу'; $labels['prettydate'] = 'Дати у зручному форматі'; -$labels['setdefault'] = 'Ð’Ñтановити за замовчуваннÑм'; -$labels['autodetect'] = 'Визначати автоматично'; -$labels['language'] = 'Мова'; -$labels['timezone'] = 'ЧаÑовий поÑÑ'; -$labels['pagesize'] = 'Ð Ñдків на Ñторінці'; +$labels['setdefault'] = 'Ð’Ñтановити за замовчуваннÑм'; +$labels['autodetect'] = 'визначити автоматично'; +$labels['language'] = 'Мова'; +$labels['timezone'] = 'ЧаÑовий поÑÑ'; +$labels['pagesize'] = 'Ð Ñдків на Ñторінці'; $labels['signature'] = 'ПідпиÑ'; -$labels['dstactive'] = 'Літній/зимовий чаÑ'; -$labels['showinextwin'] = 'Відкрити Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² новому вікні'; -$labels['composeextwin'] = 'Створити в новому вікні'; -$labels['htmleditor'] = 'Створювати лиÑти в HTML'; -$labels['htmlonreply'] = 'тільки у відповідь на HTML повідомленнÑ'; -$labels['htmlonreplyandforward'] = 'під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ відповіді на Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ HTML'; -$labels['htmlsignature'] = 'ÐŸÑ–Ð´Ð¿Ð¸Ñ Ð² HTML'; -$labels['showemail'] = 'Show email address with display name'; +$labels['dstactive'] = 'Літній/зимовий чаÑ'; +$labels['showinextwin'] = 'Відкрити лиÑÑ‚ у новому вікні'; +$labels['composeextwin'] = 'Створити у новому вікні'; +$labels['htmleditor'] = 'Створювати лиÑти у HTML'; +$labels['htmlonreply'] = 'тільки у відповідь на лиÑÑ‚ у HTML'; +$labels['htmlonreplyandforward'] = 'під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ відповіді на лиÑÑ‚ у HTML'; +$labels['htmlsignature'] = 'ÐŸÑ–Ð´Ð¿Ð¸Ñ Ñƒ HTML'; +$labels['showemail'] = 'Показати адреÑу з ім\'Ñм Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ'; $labels['previewpane'] = 'Показати панель переглÑду'; $labels['skin'] = 'Тема'; -$labels['logoutclear'] = 'Очищати кошик при виході'; +$labels['logoutclear'] = 'Очищати папку Видалені при виході'; $labels['logoutcompact'] = 'СтиÑкати папку Вхідні при завершенні'; $labels['uisettings'] = 'Ð†Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ñ€Ð¸Ñтувача'; $labels['serversettings'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñервера'; @@ -417,43 +413,43 @@ $labels['mailboxview'] = 'Вид інтерфейÑу'; $labels['mdnrequests'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ прочитаннÑ'; $labels['askuser'] = 'запитати кориÑтувача'; $labels['autosend'] = 'відправлÑти автоматично'; -$labels['autosendknown'] = 'відправити Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¸Ð¼ контактам, в іншому випадку запитати мене'; -$labels['autosendknownignore'] = 'відправити Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¸Ð¼ контактам, в іншому випадку ігнорувати'; +$labels['autosendknown'] = 'відправити лиÑÑ‚ моїм контактам, у іншому випадку запитати мене'; +$labels['autosendknownignore'] = 'відправити лиÑÑ‚ моїм контактам, у іншому випадку ігнорувати'; $labels['ignore'] = 'ігнорувати'; $labels['readwhendeleted'] = 'Позначати Ñк прочитане при видаленні'; $labels['flagfordeletion'] = 'Позначати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¼Ñ–ÑÑ‚ÑŒ видаленнÑ'; $labels['skipdeleted'] = 'Ðе показувати видалені лиÑти'; -$labels['deletealways'] = 'ВидалÑти лиÑти при невдалому переміщенні до кошика'; -$labels['deletejunk'] = 'ВидалÑти Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· папки СПÐÐœ минаючи Корзину'; +$labels['deletealways'] = 'ВидалÑти лиÑти при невдалому переміщенні у Видалені'; +$labels['deletejunk'] = 'ВидалÑти лиÑти з папки СПÐÐœ минаючи Видалені'; $labels['showremoteimages'] = 'Показувати віддалені зображеннÑ'; $labels['fromknownsenders'] = 'від відомих відправників'; $labels['always'] = 'завжди'; -$labels['showinlineimages'] = 'Показувати вкладені Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð½Ð¸Ð·Ñƒ лиÑта'; -$labels['autosavedraft'] = 'ÐÐ²Ñ‚Ð¾Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡ÐµÑ€Ð½ÐµÑ‚ÐºÐ¸'; -$labels['everynminutes'] = 'кожні $n хвилин'; -$labels['refreshinterval'] = 'Оновити (перевірити нові повідомленнÑ, тощо)'; -$labels['never'] = 'ніколи'; -$labels['immediately'] = 'одразу'; +$labels['showinlineimages'] = 'Показувати додані Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð½Ð¸Ð·Ñƒ лиÑта'; +$labels['autosavedraft'] = 'ÐÐ²Ñ‚Ð¾Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡ÐµÑ€Ð½ÐµÑ‚ÐºÐ¸'; +$labels['everynminutes'] = 'кожні $n хвилин'; +$labels['refreshinterval'] = 'Оновити (перевірити нові лиÑти, тощо)'; +$labels['never'] = 'ніколи'; +$labels['immediately'] = 'одразу'; $labels['messagesdisplaying'] = 'Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð»Ð¸Ñтів'; $labels['messagescomposition'] = 'Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð»Ð¸Ñтів'; -$labels['mimeparamfolding'] = 'Імена вкладень'; -$labels['2231folding'] = 'Повний RFC 2231 (Thunderbird)'; +$labels['mimeparamfolding'] = 'Імена додатків'; +$labels['2231folding'] = 'повний RFC 2231 (Thunderbird)'; $labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; $labels['2047folding'] = 'RFC 2047 (інші поштові клієнти)'; $labels['force7bit'] = 'ВикориÑтовувати MIME ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ 8-бітних Ñимволів'; $labels['advancedoptions'] = 'Додаткові параметри'; -$labels['focusonnewmessage'] = 'ФокуÑувати вікно браузера при новому лиÑÑ‚Ñ–'; +$labels['focusonnewmessage'] = 'ФокуÑувати вікно переглÑдача при новому лиÑÑ‚Ñ–'; $labels['checkallfolders'] = 'ПеревірÑти нові лиÑти у вÑÑ–Ñ… папках'; $labels['displaynext'] = 'ПіÑÐ»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ/Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð»Ð¸Ñта відображати наÑтупний'; -$labels['defaultfont'] = 'Шрифт за замовчуваннÑм HTML повідомленнÑ'; +$labels['defaultfont'] = 'Шрифт Ð´Ð»Ñ HTML за замовчуваннÑм'; $labels['mainoptions'] = 'ОÑновні налаштуваннÑ'; -$labels['browseroptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ð°'; +$labels['browseroptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñдача'; $labels['section'] = 'Розділ'; $labels['maintenance'] = 'Додатково'; $labels['newmessage'] = 'Ðовий лиÑÑ‚'; $labels['signatureoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñу'; $labels['whenreplying'] = 'При відповіді'; -$labels['replyempty'] = 'не цитувати оригінальне повідомленнÑ'; +$labels['replyempty'] = 'не цитувати оригінальний лиÑÑ‚'; $labels['replytopposting'] = 'починати новий лиÑÑ‚ перед цитованим'; $labels['replybottomposting'] = 'починати новий лиÑÑ‚ піÑÐ»Ñ Ñ†Ð¸Ñ‚Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾'; $labels['replyremovesignature'] = 'При відповіді видалÑти первинний Ð¿Ñ–Ð´Ð¿Ð¸Ñ Ð· лиÑта'; @@ -461,34 +457,33 @@ $labels['autoaddsignature'] = 'Ðвтоматично додавати підпР$labels['newmessageonly'] = 'тільки до нових лиÑтів'; $labels['replyandforwardonly'] = 'тільки при відповідÑÑ… та переÑилках'; $labels['insertsignature'] = 'Додати підпиÑ'; -$labels['previewpanemarkread'] = 'Позначити переглÑнуті лиÑти Ñк прочитані'; -$labels['afternseconds'] = 'через $n Ñекунд'; -$labels['reqmdn'] = 'Завжди вимагати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ доÑтавку'; -$labels['reqdsn'] = 'Завжди вимагати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð´Ð¾Ñтавки'; -$labels['replysamefolder'] = 'РозміÑтити відповіді у тій же папці, де знаходитьÑÑ Ð¾Ñ€Ð¸Ð³Ñ–Ð½Ð°Ð»'; +$labels['previewpanemarkread'] = 'Позначити переглÑнуті лиÑти Ñк прочитані'; +$labels['afternseconds'] = 'через $n Ñекунд'; +$labels['reqmdn'] = 'Завжди повідомлÑти про прочитаннÑ'; +$labels['reqdsn'] = 'Завжди повідомлÑти про доÑтавку'; +$labels['replysamefolder'] = 'Розміщувати відповіді у папці вихідного лиÑта'; $labels['defaultabook'] = 'ÐдреÑна книга за замовчуваннÑм'; -$labels['autocompletesingle'] = 'ПропуÑкати додаткові адреÑи в автозавершенні'; +$labels['autocompletesingle'] = 'ПропуÑкати додаткові адреÑи у автозавершенні'; $labels['listnamedisplay'] = 'Виводити ÑпиÑок контактів Ñк'; -$labels['spellcheckbeforesend'] = 'Перевірити орфографію перед відправкою повідомленнÑ'; +$labels['spellcheckbeforesend'] = 'ПеревірÑти орфографію перед відправкою'; $labels['spellcheckoptions'] = 'ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ орфографії'; -$labels['spellcheckignoresyms'] = 'Ігнорувати Ñлова із Ñимволами'; -$labels['spellcheckignorenums'] = 'Ігнорувати Ñлова із чиÑлами'; -$labels['spellcheckignorecaps'] = 'Ігнорувати Ñлова із великими буквами'; +$labels['spellcheckignoresyms'] = 'Ігнорувати Ñлова з Ñимволами'; +$labels['spellcheckignorenums'] = 'Ігнорувати Ñлова з чиÑлами'; +$labels['spellcheckignorecaps'] = 'Ігнорувати Ñлова з великими літерами'; $labels['addtodict'] = 'Додати до Ñловника'; -$labels['mailtoprotohandler'] = 'ЗареєÑтрувати обробник Ð´Ð»Ñ Ð¿Ð¾Ñилань mailto'; -$labels['standardwindows'] = 'Handle popups as standard windows'; -$labels['forwardmode'] = 'ПереÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½ÑŒ'; +$labels['mailtoprotohandler'] = 'ЗареєÑтрувати цей Ñервер Ñк обробник поÑилань mailto:'; +$labels['forwardmode'] = 'ПереÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð»Ð¸Ñтів'; $labels['inline'] = 'у текÑÑ‚Ñ–'; -$labels['asattachment'] = 'Ñк вкладеннÑ'; +$labels['asattachment'] = 'Ñк додаток'; -$labels['folder'] = 'Папка'; -$labels['folders'] = 'Папки'; -$labels['foldername'] = 'Ðазва папки'; -$labels['subscribed'] = 'ПідпиÑані'; +$labels['folder'] = 'Папка'; +$labels['folders'] = 'Папки'; +$labels['foldername'] = 'Ðазва папки'; +$labels['subscribed'] = 'ПідпиÑані'; $labels['messagecount'] = 'ЛиÑти'; -$labels['create'] = 'Створити'; -$labels['createfolder'] = 'Створити нову папку'; -$labels['managefolders'] = 'ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ°Ð¼Ð¸'; +$labels['create'] = 'Створити'; +$labels['createfolder'] = 'Створити нову папку'; +$labels['managefolders'] = 'ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ°Ð¼Ð¸'; $labels['specialfolders'] = 'ОÑобливі папки'; $labels['properties'] = 'ВлаÑтивоÑÑ‚Ñ–'; $labels['folderproperties'] = 'ВлаÑтивоÑÑ‚Ñ– папки'; @@ -498,12 +493,12 @@ $labels['info'] = 'ІнформаціÑ'; $labels['getfoldersize'] = 'Показати розмір папки'; $labels['changesubscription'] = 'Змінити підпиÑку'; $labels['foldertype'] = 'Тип каталогу'; -$labels['personalfolder'] = 'Приватний каталог'; -$labels['otherfolder'] = 'Каталог іншого кориÑтувача'; -$labels['sharedfolder'] = 'Публічний каталог'; +$labels['personalfolder'] = 'Приватний каталог'; +$labels['otherfolder'] = 'Каталог іншого кориÑтувача'; +$labels['sharedfolder'] = 'Публічний каталог'; $labels['sortby'] = 'ВідÑортувати за'; -$labels['sortasc'] = 'Сортувати за зроÑтаннÑм'; +$labels['sortasc'] = 'Сортувати за зроÑтаннÑм'; $labels['sortdesc'] = 'Сортувати за ÑпаданнÑм'; $labels['undo'] = 'Відмінити'; @@ -515,10 +510,10 @@ $labels['license'] = 'ЛіцензіÑ'; $labels['support'] = 'Отримати підтримку'; // units -$labels['B'] = 'б'; -$labels['KB'] = 'Кб'; -$labels['MB'] = 'Мб'; -$labels['GB'] = 'Гб'; +$labels['B'] = 'Б'; +$labels['KB'] = 'кБ'; +$labels['MB'] = 'МБ'; +$labels['GB'] = 'ГБ'; // character sets $labels['unicode'] = 'Юнікод'; diff --git a/program/localization/uk_UA/messages.inc b/program/localization/uk_UA/messages.inc index 2a114803f..0b52e4d6c 100644 --- a/program/localization/uk_UA/messages.inc +++ b/program/localization/uk_UA/messages.inc @@ -17,23 +17,23 @@ */ $messages = array(); -$messages['errortitle'] = 'Виникла помилка!'; -$messages['loginfailed'] = 'Ðевдала Ñпроба входу'; +$messages['errortitle'] = 'Виникла помилка!'; +$messages['loginfailed'] = 'Ðевдала Ñпроба входу'; $messages['cookiesdisabled'] = 'Ваш переглÑдач не приймає cookie'; $messages['sessionerror'] = 'Ваша ÑеÑÑ–Ñ Ð·Ð°Ñтаріла'; -$messages['storageerror'] = 'Ðевдале з`Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· IMAP Ñервером'; +$messages['storageerror'] = 'Ðевдале з\'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· IMAP Ñервером'; $messages['servererror'] = 'Помилка Ñервера!'; $messages['servererrormsg'] = 'Помилка Ñервера: $msg'; $messages['dberror'] = 'Помилка бази даних!'; $messages['requesttimedout'] = 'Тайм-аут запиту'; -$messages['errorreadonly'] = 'Ðеможливо виконати операцію. Папка доÑтупна тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ.'; -$messages['errornoperm'] = 'Ðеможливо виконати операцію. ДоÑтуп заборонено'; -$messages['erroroverquota'] = 'Unable to perform operation. No free disk space.'; -$messages['erroroverquotadelete'] = 'No free disk space. Use SHIFT+DEL to delete a message.'; +$messages['errorreadonly'] = 'Ðеможливо виконати операцію - папка доÑтупна тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ'; +$messages['errornoperm'] = 'Ðеможливо виконати операцію - доÑтуп заборонено'; +$messages['erroroverquota'] = 'Ðеможливо виконати операцію - немає вільного міÑÑ†Ñ Ð½Ð° диÑку'; +$messages['erroroverquotadelete'] = 'Ðемає вільного міÑÑ†Ñ Ð½Ð° диÑку - натиÑніть SHIFT+DEL Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð»Ð¸Ñта'; $messages['invalidrequest'] = 'Ðевірний запит! Дані не збережено.'; -$messages['invalidhost'] = 'Ðевірне ім\'Ñ Ñерверу.'; +$messages['invalidhost'] = 'Ðевірне ім\'Ñ Ñервера'; $messages['nomessagesfound'] = 'ЛиÑтів не знайдено'; -$messages['loggedout'] = 'Вашу ÑеÑÑ–ÑŽ завершено. Ð’Ñього найкращого!'; +$messages['loggedout'] = 'Вашу ÑеÑÑ–ÑŽ завершено. УÑього найкращого!'; $messages['mailboxempty'] = 'Поштова Ñкринька порожнÑ'; $messages['refreshing'] = 'ОновленнÑ...'; $messages['loading'] = 'ЗавантаженнÑ...'; @@ -44,16 +44,16 @@ $messages['checkingmail'] = 'Перевірка нових лиÑтів...'; $messages['sendingmessage'] = 'Відправка лиÑта...'; $messages['messagesent'] = 'ЛиÑÑ‚ уÑпішно відправлено'; $messages['savingmessage'] = 'Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð»Ð¸Ñта...'; -$messages['messagesaved'] = 'Збережено в Чернетках'; +$messages['messagesaved'] = 'Збережено у Чернетках'; $messages['successfullysaved'] = 'Збережено'; $messages['addedsuccessfully'] = 'Контакт уÑпішно доданий до ÑпиÑку контактів'; $messages['contactexists'] = 'Контакт з такою електронною адреÑою вже Ñ–Ñнує'; -$messages['contactnameexists'] = 'Контакт з таким Ñамим іменем вже Ñ–Ñнує.'; -$messages['blockedimages'] = 'З метою безпеки Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð· зовнішніх джерел заблоковано у цьому лиÑÑ‚Ñ–.'; -$messages['encryptedmessage'] = 'ЛиÑÑ‚ зашифровано Ñ– не може бути відображено.'; +$messages['contactnameexists'] = 'Контакт з таким ім\'Ñм вже Ñ–Ñнує'; +$messages['blockedimages'] = 'З метою безпеки у цьому лиÑÑ‚Ñ– заблоковано Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð· зовнішніх джерел'; +$messages['encryptedmessage'] = 'ЛиÑÑ‚ зашифровано Ñ– не може бути відображено'; $messages['nocontactsfound'] = 'Контакти не знайдені'; $messages['contactnotfound'] = 'Запитаний контакт не знайдений'; -$messages['contactsearchonly'] = 'Введіть деÑкі критерії пошуку, щоб знайти контакти'; +$messages['contactsearchonly'] = 'Щоб знайти контакти введіть критерії пошуку'; $messages['sendingfailed'] = 'Ðе вдалоÑÑ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð¸Ñ‚Ð¸ лиÑта'; $messages['senttooquickly'] = 'Будь лаÑка, зачекайте $sec Ñекунд Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²ÐºÐ¸ лиÑта'; $messages['errorsavingsent'] = 'Помилка при збереженні відправленого лиÑта'; @@ -62,20 +62,20 @@ $messages['errormoving'] = 'Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити лиÑÑ‚Ð $messages['errorcopying'] = 'Ðе вдалоÑÑ Ð·ÐºÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ñ‚Ð¸ лиÑти'; $messages['errordeleting'] = 'Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ лиÑти'; $messages['errormarking'] = 'Ðе вдалоÑÑ Ð¿Ð¾Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ лиÑти'; -$messages['deletecontactconfirm'] = 'Ви дійÑно бажаєте видалити вибрані контакти?'; +$messages['deletecontactconfirm'] = 'Ви дійÑно бажаєте видалити обрані контакти?'; $messages['deletegroupconfirm'] = 'Ви дійÑно хочете видалити обрану групу?'; -$messages['deletemessagesconfirm'] = 'Ви дійÑно бажаєте видалити вибрані лиÑти?'; +$messages['deletemessagesconfirm'] = 'Ви дійÑно бажаєте видалити обрані лиÑти?'; $messages['deletefolderconfirm'] = 'Ви дійÑно бажаєте видалити цю папку?'; -$messages['purgefolderconfirm'] = 'Ви дійÑно бажаєте видалити вÑÑ– лиÑти у цій папці?'; +$messages['purgefolderconfirm'] = 'Ви дійÑно бажаєте видалити уÑÑ– лиÑти у цій папці?'; $messages['contactdeleting'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ñƒ(ів)...'; $messages['groupdeleting'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸...'; $messages['folderdeleting'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸...'; $messages['foldermoving'] = 'ÐŸÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸...'; $messages['foldersubscribing'] = 'ПідпиÑати папку...'; $messages['folderunsubscribing'] = 'ВідпиÑати папку...'; -$messages['formincomplete'] = 'Заповнено не вÑÑ– полÑ'; +$messages['formincomplete'] = 'Заповнено не уÑÑ– полÑ'; $messages['noemailwarning'] = 'Будь лаÑка, введіть коректну адреÑу електронної пошти'; -$messages['nonamewarning'] = 'Будь лаÑка, введіть ім`Ñ'; +$messages['nonamewarning'] = 'Будь лаÑка, введіть ім\'Ñ'; $messages['nopagesizewarning'] = 'Будь лаÑка, введіть розмір Ñторінки'; $messages['nosenderwarning'] = 'Будь лаÑка, введіть адреÑу електронної пошти відправника'; $messages['norecipientwarning'] = 'Будь лаÑка, вкажіть принаймні одного отримувача'; @@ -83,10 +83,10 @@ $messages['nosubjectwarning'] = 'Ðе вказано тему лиÑта. БаР$messages['nobodywarning'] = 'Відправити лиÑта без текÑту?'; $messages['notsentwarning'] = 'ЛиÑÑ‚ не було відправлено. Ви бажаєте відхилити відправку?'; $messages['noldapserver'] = 'Будь лаÑка, виберіть LDAP Ñервер Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ'; -$messages['nosearchname'] = 'Будь лаÑка, введіть ім`Ñ Ñ‡Ð¸ електронну адреÑу'; -$messages['notuploadedwarning'] = 'ДеÑкі Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ð½Ñ Ð½Ðµ було завантажено. Будь лаÑка, почекайте або відмініть завантаженнÑ.'; -$messages['searchsuccessful'] = 'Зайдено $nr лиÑтів'; -$messages['contactsearchsuccessful'] = '$nr контактів знайдено.'; +$messages['nosearchname'] = 'Будь лаÑка, введіть ім\'Ñ Ñ‡Ð¸ електронну адреÑу'; +$messages['notuploadedwarning'] = 'ДеÑкі додатки не було завантажено. Будь лаÑка, почекайте або відмініть завантаженнÑ.'; +$messages['searchsuccessful'] = 'Знайдено $nr лиÑтів'; +$messages['contactsearchsuccessful'] = '$nr контактів знайдено'; $messages['searchnomatch'] = 'ЛиÑтів не знайдено'; $messages['searching'] = 'Пошук...'; $messages['checking'] = 'Перевірка...'; @@ -98,43 +98,38 @@ $messages['folderpurged'] = 'Папка видалена'; $messages['folderexpunged'] = 'Папка очищена'; $messages['deletedsuccessfully'] = 'Видалено уÑпішно'; $messages['converting'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ...'; -$messages['messageopenerror'] = 'Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· Ñервера'; +$messages['messageopenerror'] = 'Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ лиÑÑ‚ з Ñервера'; $messages['fileuploaderror'] = 'Ðе вдалоÑÑ Ð²ÐºÐ»Ð°Ñти файл'; -$messages['filesizeerror'] = 'Розмір вибраного файлу перевищує макÑимально дозволений ($size)'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['filesizeerror'] = 'Розмір обраного файлу перевищує макÑимально дозволений ($size)'; +$messages['copysuccess'] = 'Скопійовано $nr адреÑ'; +$messages['copyerror'] = 'Ðе вдалоÑÑ Ñкопіювати жодну адреÑу'; $messages['sourceisreadonly'] = 'Дане джерело Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ñтупне лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ'; $messages['errorsavingcontact'] = 'Ðеможливо зберегти адреÑу контакту'; $messages['movingmessage'] = 'ÐŸÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð»Ð¸Ñта...'; $messages['copyingmessage'] = 'ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ð»Ð¸Ñта...'; $messages['copyingcontact'] = 'ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ñƒ(ів)...'; -$messages['movingcontact'] = 'Moving contact(s)...'; -$messages['deletingmessage'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð»Ð¸Ñта (ів)'; -$messages['markingmessage'] = 'ÐŸÐ¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð»Ð¸Ñта (ів)'; +$messages['deletingmessage'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð»Ð¸Ñта(ів)'; +$messages['markingmessage'] = 'ÐŸÐ¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð»Ð¸Ñта(ів)'; $messages['addingmember'] = 'Ð”Ð¾Ð´Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ñƒ(ів) до групи...'; $messages['removingmember'] = 'Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ñƒ(ів) з групи...'; $messages['receiptsent'] = 'ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¾'; $messages['errorsendingreceipt'] = 'Ðе вдалоÑÑ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð¸Ñ‚Ð¸ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ прочитаннÑ'; $messages['deleteidentityconfirm'] = 'Ви дійÑно бажаєте видалити цей профіль?'; -$messages['nodeletelastidentity'] = 'Ви не можете видалити цей профіль, він у Ð’Ð°Ñ Ð¾Ñтанній.'; -$messages['forbiddencharacter'] = 'Ім\'Ñ Ð¿Ð°Ð¿ÐºÐ¸ міÑтить заборонені Ñимволи'; +$messages['nodeletelastidentity'] = 'Ви не можете видалити оÑтанній профіль'; +$messages['forbiddencharacter'] = 'Ім\'Ñ Ð¿Ð°Ð¿ÐºÐ¸ міÑтить неприпуÑтимі Ñимволи'; $messages['selectimportfile'] = 'Виберіть файл Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ'; $messages['addresswriterror'] = 'Обрана адреÑна книга недоÑтупна Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу'; $messages['contactaddedtogroup'] = 'Контакти уÑпішно додано до цієї групи'; -$messages['contactremovedfromgroup'] = 'УКонтакти уÑпішно видалено з цієї групи'; -$messages['nogroupassignmentschanged'] = 'Розподіл за групами не змінено.'; -$messages['importwait'] = 'ІмпортуваннÑ, будь лаÑка, зачекайте...'; +$messages['contactremovedfromgroup'] = 'Контакти уÑпішно видалено з цієї групи'; +$messages['nogroupassignmentschanged'] = 'Розподіл за групами не змінено'; +$messages['importwait'] = 'Зачекайте, будь лаÑка, відбуваєтьÑÑ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ...'; $messages['importformaterror'] = 'Помилка імпорту! Завантажений файл має невідомий формат даних.'; $messages['importconfirm'] = '<b>УÑпішно імпортовано $inserted контактів, пропущено $skipped Ñ–Ñнуючих</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>Пропущені $skipped наÑвні запиÑи</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Ð”Ñ–Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½ÐµÐ½Ð°!'; -$messages['nofromaddress'] = 'Ð’ обраному профілі не виÑтачає адреÑи електронної пошти'; -$messages['editorwarning'] = 'ÐŸÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð² режим звичайного текÑту Ñпричинить втрату вÑього форматуваннÑ. Продовжити?'; -$messages['httpreceivedencrypterror'] = 'Помилка конфігурації. Ðегайно звернітьÑÑ Ð´Ð¾ адмініÑтратора. <b>Ваше Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ðµ буде відправлено.</b>'; +$messages['nofromaddress'] = 'У обраному профілі не виÑтачає адреÑи електронної пошти'; +$messages['editorwarning'] = 'ÐŸÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ñƒ режим звичайного текÑту Ñпричинить втрату вÑього форматуваннÑ. Продовжити?'; +$messages['httpreceivedencrypterror'] = 'Помилка конфігурації. Ðегайно звернітьÑÑ Ð´Ð¾ адмініÑтратора. <b>Ваш лиÑÑ‚ не буде відправлено.</b>'; $messages['smtpconnerror'] = 'Помилка SMTP-Ñервера ($code): Ðе вдалоÑÑ Ð·\'єднатиÑÑ Ð· Ñервером'; $messages['smtpautherror'] = 'Помилка SMTP-Ñервера ($code): Ðевдала Ñпроба автентифікації'; $messages['smtpfromerror'] = 'Помилка SMTP-Ñервера ($code): Ðе вдалоÑÑ Ð²ÐºÐ°Ð·Ð°Ñ‚Ð¸ відправника "$from" ($msg)'; @@ -142,35 +137,35 @@ $messages['smtptoerror'] = 'Помилка SMTP-Ñервера ($code): Ðе вР$messages['smtprecipientserror'] = 'Помилка SMTP: Ðе вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ ÑпиÑок отримувачів'; $messages['smtperror'] = 'Помилка SMTP: $msg'; $messages['emailformaterror'] = 'Ðевірна електронна адреÑа: $email'; -$messages['toomanyrecipients'] = 'Занадто багато отримувачів. Зменшіть Ñ—Ñ… чиÑло до $max.'; -$messages['maxgroupmembersreached'] = 'ЧиÑло Ð°Ð´Ñ€ÐµÑ Ñƒ групі перевищило макÑимум у $max.'; -$messages['internalerror'] = 'Виникла Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз'; +$messages['toomanyrecipients'] = 'Занадто багато отримувачів. Зменшіть Ñ—Ñ… чиÑло до $max'; +$messages['maxgroupmembersreached'] = 'ЧиÑло Ð°Ð´Ñ€ÐµÑ Ñƒ групі перевищило макÑимум у $max'; +$messages['internalerror'] = 'Виникла Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз.'; $messages['contactdelerror'] = 'Ðеможливо видалити контакт(и)'; $messages['contactdeleted'] = 'Контакт(и) видалено уÑпішно'; -$messages['contactrestoreerror'] = 'Ðеможливо відновити видалений(Ñ–) контакт(и).'; -$messages['contactrestored'] = 'Контакт(и) вдало відновлено.'; +$messages['contactrestoreerror'] = 'Ðеможливо відновити видалений(Ñ–) контакт(и)'; +$messages['contactrestored'] = 'Контакт(и) уÑпішно відновлено'; $messages['groupdeleted'] = 'Група видалена уÑпішно'; $messages['grouprenamed'] = 'Група перейменована уÑпішно'; $messages['groupcreated'] = 'Група Ñтворена уÑпішно'; -$messages['savedsearchdeleted'] = 'Збережений пошук вдало видалено.'; -$messages['savedsearchdeleteerror'] = 'Ðеможливо видалити збережений пошук.'; -$messages['savedsearchcreated'] = 'Збережений пошук вдало Ñтворено.'; -$messages['savedsearchcreateerror'] = 'Ðе вдалоÑÑŒ Ñтворити збережений пошук.'; +$messages['savedsearchdeleted'] = 'Збережений пошуковий запит уÑпішно видалено'; +$messages['savedsearchdeleteerror'] = 'Ðеможливо видалити збережений пошуковий запит'; +$messages['savedsearchcreated'] = 'Пошуковий запит уÑпішно збережено'; +$messages['savedsearchcreateerror'] = 'Ðе вдалоÑÑŒ зберегти пошуковий запит'; $messages['messagedeleted'] = 'ЛиÑÑ‚(и) видалено уÑпішно'; $messages['messagemoved'] = 'ЛиÑÑ‚(и) переміщено уÑпішно'; $messages['messagecopied'] = 'ЛиÑÑ‚(и) Ñкопійовано уÑпішно'; -$messages['messagemarked'] = 'ЛиÑÑ‚(и) помічено уÑпішно'; -$messages['autocompletechars'] = 'Введіть щонайменьше $min Ñимволів Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ'; +$messages['messagemarked'] = 'ЛиÑÑ‚(и) позначено уÑпішно'; +$messages['autocompletechars'] = 'Введіть щонайменше $min Ñимволів Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ'; $messages['autocompletemore'] = 'Знайдено багато відповідних запиÑів. Будь лаÑка введіть більше Ñимволів.'; -$messages['namecannotbeempty'] = 'Ð†Ð¼â€™Ñ Ð½Ðµ може бути пуÑтим'; -$messages['nametoolong'] = 'Занадто довге ім’Ñ'; +$messages['namecannotbeempty'] = 'Ім\'Ñ Ð½Ðµ може бути пуÑтим'; +$messages['nametoolong'] = 'Занадто довге ім\'Ñ'; $messages['folderupdated'] = 'Папка відновлена'; $messages['foldercreated'] = 'Папка Ñтворена'; $messages['invalidimageformat'] = 'Ðевірний формат зображеннÑ'; -$messages['mispellingsfound'] = 'Знайдено орфографічні помилки у повідомленні.'; -$messages['parentnotwritable'] = 'Ðеможливо Ñтворити/переміÑтити папку до обраної батьківÑької папки. Ðема прав доÑтупу.'; -$messages['messagetoobig'] = 'ЧаÑтина Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ велика Ð´Ð»Ñ Ð¾Ð¿Ñ€Ð°Ñ†ÑŽÐ²Ð°Ð½Ð½Ñ.'; -$messages['attachmentvalidationerror'] = 'УВÐГÐ! Це Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ð½Ñ Ñ” підозрілим, тому що його тип не збігаєтьÑÑ Ð· типом, оголошеним у повідомленні. Якщо ви не довірÑєте відправнику, ви не повинні відкривати його в браузері, оÑкільки його вміÑÑ‚ може бути шкідливим.<br/><br/><em>Очікуване: $expected; знайдене: $detected </em>'; -$messages['noscriptwarning'] = 'Увага: Даний клієнт електронної пошти потрібує Javascript! Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб викориÑтовувати його необхідно включити підтримку Javascript в налаштуваннÑÑ… вашого браузера.'; +$messages['mispellingsfound'] = 'У лиÑÑ‚Ñ– знайдено орфографічні помилки'; +$messages['parentnotwritable'] = 'Ðеможливо Ñтворити/переміÑтити папку до обраної батьківÑької папки - немає прав доÑтупу'; +$messages['messagetoobig'] = 'ЧаÑтина лиÑта занадто велика Ð´Ð»Ñ Ð¾Ð¿Ñ€Ð°Ñ†ÑŽÐ²Ð°Ð½Ð½Ñ'; +$messages['attachmentvalidationerror'] = 'УВÐГÐ! Цей додаток Ñ” підозрілим бо його тип (визначений Ñк <em>$detected</em>) не збігаєтьÑÑ Ð· оголошеним у лиÑÑ‚Ñ– типом (<em>$expected</em>). Ðе відкривайте цей додаток Ñкщо Ñ” Ñумніви - його вміÑÑ‚ може бути шкідливим!<br/><br/>'; +$messages['noscriptwarning'] = 'Увага: Цей клієнт електронної пошти потрібує JavaScript. Ð”Ð»Ñ Ð¹Ð¾Ð³Ð¾ викориÑÑ‚Ð°Ð½Ð½Ñ Ð½ÐµÐ¾Ð±Ñ…Ñ–Ð´Ð½Ð¾ включити підтримку JavaScript у налаштуваннÑÑ… переглÑдача.'; ?> diff --git a/program/localization/ur_PK/labels.inc b/program/localization/ur_PK/labels.inc new file mode 100644 index 000000000..797c98f11 --- /dev/null +++ b/program/localization/ur_PK/labels.inc @@ -0,0 +1,40 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | localization/<lang>/labels.inc | + | | + | Localization file of the Roundcube Webmail client | + | Copyright (C) 2005-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + +-----------------------------------------------------------------------+ + + For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/labels/ +*/ +$labels['welcome'] = ' $product میں خوش آمدید'; +$labels['server'] = 'سَروَر'; +$labels['mail'] = 'میل'; +$labels['settings'] = 'ترتیبات'; +$labels['download'] = 'ڈاؤن لوڈ'; +$labels['showanyway'] = 'جیسا بھی ÛÛ’ ظاÛر کر دیں'; +$labels['markread'] = 'جیسے Ù¾Ú‘Ú¾ لیا ÛÙˆ'; +$labels['markunread'] = 'جیسے ابھی Ù†Û Ù¾Ú‘Ú¾Ø§ ÛÙˆ'; +$labels['more'] = 'مزید'; +$labels['back'] = 'واپس'; +$labels['select'] = 'مۃنتخب کریں'; +$labels['all'] = 'تمام'; +$labels['none'] = 'کوئی Ù†Ûیں'; +$labels['currpage'] = 'Ù…ÙˆØ¬ÙˆØ¯Û ØÙØÛ'; +$labels['unread'] = 'Ù†Ûیں پڑھا'; +$labels['deleted'] = 'ختم ÛÙˆ گیا'; +$labels['undeleted'] = 'ختم Ù†Ûیں ÛÙوا'; +$labels['invert'] = 'Ø´Ú©Ù„ تبدیل کریں'; +$labels['list'] = 'Ù„Ùسٹ'; +$labels['expand-all'] = 'تمام کھولیں'; +$labels['attachment'] = 'Ù…Ùنسلَک Ø´ÙدÛ'; +$labels['nonesort'] = 'کوئی Ù†Ûیں'; +?> diff --git a/program/localization/ur_PK/messages.inc b/program/localization/ur_PK/messages.inc new file mode 100644 index 000000000..da4e39679 --- /dev/null +++ b/program/localization/ur_PK/messages.inc @@ -0,0 +1,18 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | localization/<lang>/messages.inc | + | | + | Localization file of the Roundcube Webmail client | + | Copyright (C) 2005-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + +-----------------------------------------------------------------------+ + + For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/messages/ +*/ +?> diff --git a/program/localization/vi_VN/labels.inc b/program/localization/vi_VN/labels.inc index aad0dafe6..f1cf95149 100644 --- a/program/localization/vi_VN/labels.inc +++ b/program/localization/vi_VN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'ThÆ° nháp'; $labels['sent'] = 'Äã gá»i'; $labels['trash'] = 'Sá»t rác'; $labels['junk'] = 'ThÆ° rác'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = 'Tiêu Ä‘á»'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'Xem dạng danh sách'; $labels['folderactions'] = 'Thao tác vá»›i thÆ° mục'; $labels['compact'] = 'Nén'; $labels['empty'] = 'Trống'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Lượng Ä‘Ä©a sá» dụng'; $labels['unknown'] = 'Không rõ'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'Thiết láºp lại tìm kiếm'; $labels['searchmod'] = 'Tìm kiếm vá»›i từ khóa và ký tá»± đặc biệt [() : " - ]'; $labels['msgtext'] = 'Toà n bá»™ thÆ°'; $labels['body'] = 'Ná»™i dung thÆ°'; -$labels['type'] = 'Type'; $labels['openinextwin'] = 'Mở trong khung cá»a má»›i'; $labels['emlsave'] = 'Tải vá» theo định dạng .eml'; @@ -357,7 +354,6 @@ $labels['lastpage'] = 'Hiển thị trang cuối'; $labels['group'] = 'Nhóm'; $labels['groups'] = 'Các nhóm'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = 'Các địa chỉ cá nhân'; $labels['searchsave'] = 'LÆ°u tìm kiếm'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = 'Bá» qua các từ kèm số'; $labels['spellcheckignorecaps'] = 'Bá» qua các từ được viết hoa'; $labels['addtodict'] = 'Thêm và o từ Ä‘iển'; $labels['mailtoprotohandler'] = 'Xác định cách xá» lý giao thức mailto: liên kết'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = 'Chuyển tiếp thÆ°'; $labels['inline'] = 'ná»™i tuyến'; $labels['asattachment'] = 'dạng gá»i kèm'; diff --git a/program/localization/vi_VN/messages.inc b/program/localization/vi_VN/messages.inc index 769a21afd..50bf71846 100644 --- a/program/localization/vi_VN/messages.inc +++ b/program/localization/vi_VN/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'Loại bỠđịnh dạng...'; $messages['messageopenerror'] = 'Không thể tải thÆ° từ máy chủ'; $messages['fileuploaderror'] = 'Tải táºp tin lên thất bại'; $messages['filesizeerror'] = 'Táºp tin được tải lên vượt quá dung lượng tối Ä‘a....'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = 'Sao chép thà nh công $nr địa chỉ.'; +$messages['copyerror'] = 'Không thể sao chép đỉa chỉ nà o.'; $messages['sourceisreadonly'] = 'Nguồn địa chỉ nà y chỉ cho Ä‘á»c'; $messages['errorsavingcontact'] = 'Không thể lÆ°u địa chỉ liên lạc'; $messages['movingmessage'] = 'Äang chuyển thÆ°...'; $messages['copyingmessage'] = 'Äang sao chép thÆ°...'; $messages['copyingcontact'] = 'Äang sao chép liên lạc...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = 'Äang xóa thÆ°...'; $messages['markingmessage'] = 'Äánh dấu thÆ°...'; $messages['addingmember'] = 'Äang thêm liên lạc và o nhóm...'; @@ -129,8 +126,6 @@ $messages['importwait'] = 'Äang nháºp, xin chá»...'; $messages['importformaterror'] = 'Nháºp dữ liệu lá»—i. Tệp tin vừa tải lên không phải tệp dữ liệu chÃnh xác.'; $messages['importconfirm'] = 'Äã nháºp $inserted liên hệ đã chèn và o thà nh công.'; $messages['importconfirmskipped'] = 'Äã bá» qua được $skipped mục tồn tại.'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Thao tác không được cho phép!'; $messages['nofromaddress'] = 'Äịa chỉ email mất ở trong nháºn dạng đã chá»n'; $messages['editorwarning'] = 'Việc chuyển soạn thảo text gốc sẽ gây ra toà n bá»™ định dạng text đã có bị mất. Bạn có muốn tiếp tục không?'; diff --git a/program/localization/zh_CN/labels.inc b/program/localization/zh_CN/labels.inc index b568a7008..23a42b96d 100644 --- a/program/localization/zh_CN/labels.inc +++ b/program/localization/zh_CN/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'è‰ç¨¿ç®±'; $labels['sent'] = 'å·²å‘é€é‚®ä»¶'; $labels['trash'] = 'å·²åˆ é™¤é‚®ä»¶'; $labels['junk'] = '垃圾邮件'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = '主题'; @@ -194,7 +193,6 @@ $labels['listmode'] = 'åˆ—è¡¨è§†å›¾æ ·å¼'; $labels['folderactions'] = '文件夹æ“作...'; $labels['compact'] = '压缩'; $labels['empty'] = '清空'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = '邮箱容é‡'; $labels['unknown'] = '未知'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = '清空'; $labels['searchmod'] = '修改æœç´¢'; $labels['msgtext'] = 'æ•´å°é‚®ä»¶'; $labels['body'] = 'æ£æ–‡'; -$labels['type'] = 'Type'; $labels['openinextwin'] = '在新窗å£ä¸æ‰“å¼€'; $labels['emlsave'] = '下载(.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = '最åŽä¸€é¡µ'; $labels['group'] = '分组'; $labels['groups'] = '分组'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = '个人通讯录'; $labels['searchsave'] = 'ä¿å˜æœç´¢'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = '忽略带数å—çš„å•è¯'; $labels['spellcheckignorecaps'] = '忽略所有大写å—æ¯çš„å•è¯'; $labels['addtodict'] = 'æ·»åŠ åˆ°å—å…¸ä¸'; $labels['mailtoprotohandler'] = 'Register protocol handler for mailto: links'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = '邮件转å‘æ–¹å¼'; $labels['inline'] = '内嵌'; $labels['asattachment'] = '作为附件'; diff --git a/program/localization/zh_CN/messages.inc b/program/localization/zh_CN/messages.inc index 4c47f833e..43703e311 100644 --- a/program/localization/zh_CN/messages.inc +++ b/program/localization/zh_CN/messages.inc @@ -19,115 +19,117 @@ $messages = array(); $messages['errortitle'] = 'å‘生错误ï¼'; $messages['loginfailed'] = '登录失败。'; -$messages['cookiesdisabled'] = '您的æµè§ˆå™¨ä¸æŽ¥å— cookies。'; -$messages['sessionerror'] = '会è¯å·²è¿‡æœŸã€‚'; -$messages['storageerror'] = '连接到邮件æœåŠ¡å™¨å¤±è´¥ã€‚'; +$messages['cookiesdisabled'] = '您的æµè§ˆå™¨ä¸æ”¯æŒ Cookies。'; +$messages['sessionerror'] = '会è¯æ— 效或已过期。'; +$messages['storageerror'] = '连接至 IMAP æœåŠ¡å™¨å¤±è´¥ã€‚'; $messages['servererror'] = 'æœåŠ¡å™¨é”™è¯¯ï¼'; -$messages['servererrormsg'] = 'æœåŠ¡å™¨é”™è¯¯: $msg'; +$messages['servererrormsg'] = 'æœåŠ¡å™¨é”™è¯¯ï¼š$msg'; $messages['dberror'] = 'æ•°æ®åº“错误ï¼'; $messages['requesttimedout'] = '请求超时'; -$messages['errorreadonly'] = 'ä¸å¯å¯¹åªè¯»æ–‡ä»¶å¤¹è¿›è¡Œæ“作。'; -$messages['errornoperm'] = 'æ— æƒé™æ“作'; -$messages['invalidrequest'] = 'æ— æ•ˆçš„è¯·æ±‚ï¼æ•°æ®ä¿å˜å¤±è´¥ã€‚'; -$messages['invalidhost'] = 'éžæ³•ä¸»æœºå。'; +$messages['errorreadonly'] = 'æ— æ³•å®Œæˆæ“作。文件夹为åªè¯»ã€‚'; +$messages['errornoperm'] = 'æ— æ³•å®Œæˆæ“作。没有æƒé™ã€‚'; +$messages['erroroverquota'] = 'æ— æ³•å®Œæˆæ“作。没有足够的ç£ç›˜ç©ºé—´ã€‚'; +$messages['erroroverquotadelete'] = '没有足够的ç£ç›˜ç©ºé—´ã€‚请使用 SHIFT+DEL åˆ é™¤ä¸€éƒ¨åˆ†é‚®ä»¶ã€‚'; +$messages['invalidrequest'] = 'è¯·æ±‚æ— æ•ˆï¼æœªä¿å˜æ•°æ®ã€‚'; +$messages['invalidhost'] = 'æ— æ•ˆçš„ä¸»æœºå。'; $messages['nomessagesfound'] = 'æ¤é‚®ä»¶å¤¹å†…æ— é‚®ä»¶ã€‚'; $messages['loggedout'] = '您已æˆåŠŸæ³¨é”€ï¼Œå†è§ï¼'; -$messages['mailboxempty'] = '邮件夹为空'; -$messages['refreshing'] = '刷新ä¸...'; -$messages['loading'] = 'æ£åœ¨è½½å…¥...'; +$messages['mailboxempty'] = '邮件夹为空。'; +$messages['refreshing'] = 'æ£åœ¨åˆ·æ–°...'; +$messages['loading'] = 'æ£åœ¨ç™»å½•...'; $messages['uploading'] = 'æ£åœ¨ä¸Šä¼ 文件...'; $messages['uploadingmany'] = 'æ£åœ¨ä¸Šä¼ 文件...'; $messages['loadingdata'] = 'æ£åœ¨è½½å…¥æ•°æ®...'; $messages['checkingmail'] = 'æ£åœ¨æ£€æŸ¥æ–°é‚®ä»¶...'; -$messages['sendingmessage'] = 'æ£åœ¨å‘é€é‚®ä»¶...'; -$messages['messagesent'] = '邮件å‘é€æˆåŠŸã€‚'; +$messages['sendingmessage'] = 'æ£åœ¨å‘é€...'; +$messages['messagesent'] = '邮件已å‘é€ã€‚'; $messages['savingmessage'] = 'æ£åœ¨ä¿å˜é‚®ä»¶...'; -$messages['messagesaved'] = '邮件已暂å˜åˆ°è‰ç¨¿ç®±ã€‚'; +$messages['messagesaved'] = '邮件已暂å˜è‡³è‰ç¨¿ç®±ã€‚'; $messages['successfullysaved'] = 'ä¿å˜æˆåŠŸã€‚'; -$messages['addedsuccessfully'] = 'æˆåŠŸæ·»åŠ è”系人。'; +$messages['addedsuccessfully'] = 'è”ç³»äººå·²æ·»åŠ ã€‚'; $messages['contactexists'] = '当å‰è”系人的电å邮件地å€å·²å˜åœ¨ã€‚'; -$messages['contactnameexists'] = 'å·²å˜åœ¨åŒåçš„è”系人。'; -$messages['blockedimages'] = '为ä¿æŠ¤éšç§ï¼Œæ¤é‚®ä»¶ä¸çš„远程图片未显示。'; +$messages['contactnameexists'] = 'å·²å˜åœ¨åŒåè”系人。'; +$messages['blockedimages'] = '由于ä¿æŠ¤éšç§ï¼Œæ¤é‚®ä»¶ä¸çš„远程图片未予显示。'; $messages['encryptedmessage'] = '抱æ‰ï¼è¯¥é‚®ä»¶å·²è¢«åŠ å¯†ï¼Œæ— æ³•æ˜¾ç¤ºã€‚'; $messages['nocontactsfound'] = '未找到è”系人。'; $messages['contactnotfound'] = '未找到指定的è”系人。'; $messages['contactsearchonly'] = '请输入è”系人的æœç´¢æ¡ä»¶'; $messages['sendingfailed'] = 'å‘é€å¤±è´¥ã€‚'; -$messages['senttooquickly'] = '您需è¦ç‰å¾… $sec 秒æ‰èƒ½å‘é€é‚®ä»¶ã€‚'; +$messages['senttooquickly'] = '您需è¦ç‰å¾…$sec秒æ‰èƒ½å‘é€é‚®ä»¶ã€‚'; $messages['errorsavingsent'] = 'ä¿å˜å·²å‘é€é‚®ä»¶æ—¶å‘生错误。'; $messages['errorsaving'] = 'ä¿å˜æ—¶å‘生错误。'; $messages['errormoving'] = 'æ— æ³•ç§»åŠ¨é‚®ä»¶ã€‚'; $messages['errorcopying'] = 'æ— æ³•å¤åˆ¶é‚®ä»¶ã€‚'; $messages['errordeleting'] = 'æ— æ³•åˆ é™¤é‚®ä»¶ã€‚'; $messages['errormarking'] = 'æ— æ³•æ ‡è®°é‚®ä»¶ã€‚'; -$messages['deletecontactconfirm'] = '确定è¦åˆ 除已选ä¸çš„è”系人?'; -$messages['deletegroupconfirm'] = '确定è¦åˆ 除以选ä¸çš„组?'; -$messages['deletemessagesconfirm'] = '确定è¦åˆ 除已选ä¸çš„邮件?'; -$messages['deletefolderconfirm'] = '确定è¦åˆ 除已选ä¸çš„邮件夹?'; -$messages['purgefolderconfirm'] = '是å¦ç¡®è®¤è¦åˆ 除当å‰é‚®ä»¶å¤¹ä¸çš„所有邮件?'; +$messages['deletecontactconfirm'] = '是å¦åˆ 除选ä¸çš„è”系人?'; +$messages['deletegroupconfirm'] = '是å¦åˆ 除选ä¸çš„群组?'; +$messages['deletemessagesconfirm'] = '是å¦åˆ 除选ä¸çš„邮件?'; +$messages['deletefolderconfirm'] = '是å¦åˆ 除选ä¸çš„邮件夹?'; +$messages['purgefolderconfirm'] = '是å¦åˆ 除当å‰é‚®ä»¶å¤¹ä¸çš„全部邮件?'; $messages['contactdeleting'] = 'æ£åœ¨åˆ 除è”系人...'; -$messages['groupdeleting'] = 'æ£åœ¨åˆ 除组...'; +$messages['groupdeleting'] = 'æ£åœ¨åˆ 除群组...'; $messages['folderdeleting'] = 'æ£åœ¨åˆ 除文件夹...'; $messages['foldermoving'] = 'æ£åœ¨ç§»åŠ¨æ–‡ä»¶å¤¹...'; $messages['foldersubscribing'] = '订阅文件夹ä¸...'; $messages['folderunsubscribing'] = '退订ä¸...'; -$messages['formincomplete'] = '当å‰è¡¨å•æœªå¡«å†™å®Œæ•´ï¼Œè¯·å®Œæ•´å¡«å†™ã€‚'; +$messages['formincomplete'] = '表å•æœªå¡«å†™å®Œæ•´ã€‚'; $messages['noemailwarning'] = '请输入一个有效的邮件地å€ã€‚'; -$messages['nonamewarning'] = '请输入åå—。'; -$messages['nopagesizewarning'] = '请输入æ¯é¡µæ˜¾ç¤ºçš„邮件数é‡'; +$messages['nonamewarning'] = '请输入å称。'; +$messages['nopagesizewarning'] = '请输入æ¯é¡µæ˜¾ç¤ºçš„邮件数é‡ã€‚'; $messages['nosenderwarning'] = '请输入å‘件人地å€ã€‚'; -$messages['norecipientwarning'] = '至少需è¦ä¸€ä¸ªæ”¶ä»¶äººã€‚'; +$messages['norecipientwarning'] = '至少输入一个收件人。'; $messages['nosubjectwarning'] = '主题为空。您è¦è¾“入一个主题å—?'; -$messages['nobodywarning'] = 'è¦å‘é€æ— æ£æ–‡çš„邮件å—?'; +$messages['nobodywarning'] = 'è¦å‘é€æ²¡æœ‰æ£æ–‡çš„邮件å—?'; $messages['notsentwarning'] = '邮件未å‘é€ã€‚您确定è¦ç¦»å¼€å¹¶èˆå¼ƒå½“å‰é‚®ä»¶å—?'; -$messages['noldapserver'] = '请选择一个LDAPæœåŠ¡å™¨è¿›è¡ŒæŸ¥æ‰¾ã€‚'; -$messages['nosearchname'] = '请输入一个è”系人姓å或电å邮件地å€ã€‚'; -$messages['notuploadedwarning'] = 'é™„ä»¶è¿˜æ²¡æœ‰å…¨éƒ¨ä¸Šä¼ ï¼Œè¯·ç‰å¾…或者å–æ¶ˆä¸Šä¼ ã€‚'; +$messages['noldapserver'] = '请选择一个用æ¥æŸ¥æ‰¾çš„ LDAP æœåŠ¡å™¨ã€‚'; +$messages['nosearchname'] = '请输入è”系人姓å或电å邮件地å€ã€‚'; +$messages['notuploadedwarning'] = 'é™„ä»¶å°šæœªå…¨éƒ¨ä¸Šä¼ ï¼Œè¯·è€å¿ƒç‰å¾…或者å–æ¶ˆä¸Šä¼ ã€‚'; $messages['searchsuccessful'] = '共找到 $nr å°é‚®ä»¶ã€‚'; $messages['contactsearchsuccessful'] = '共找到 $nr ä½è”系人。'; -$messages['searchnomatch'] = '未找到任何符åˆæ¡ä»¶çš„邮件'; +$messages['searchnomatch'] = '未找到任何符åˆæ¡ä»¶çš„邮件。'; $messages['searching'] = 'æ£åœ¨æœç´¢...'; $messages['checking'] = 'æ£åœ¨æ£€æŸ¥...'; -$messages['nospellerrors'] = '未å‘现拼写错误'; -$messages['folderdeleted'] = '文件夹已被æˆåŠŸåˆ 除。'; -$messages['foldersubscribed'] = 'æˆåŠŸè®¢é˜…文件夹。'; -$messages['folderunsubscribed'] = 'æˆåŠŸé€€è®¢çš„文件夹。'; -$messages['folderpurged'] = 'æˆåŠŸæ¸…空文件夹。'; +$messages['nospellerrors'] = '未å‘现拼写错误。'; +$messages['folderdeleted'] = 'åˆ é™¤æ–‡ä»¶å¤¹æˆåŠŸã€‚'; +$messages['foldersubscribed'] = '订阅文件夹æˆåŠŸã€‚'; +$messages['folderunsubscribed'] = '退订文件夹æˆåŠŸã€‚'; +$messages['folderpurged'] = '清空文件夹æˆåŠŸã€‚'; $messages['folderexpunged'] = '文件夹已清空。'; $messages['deletedsuccessfully'] = 'åˆ é™¤æˆåŠŸã€‚'; $messages['converting'] = 'æ ¼å¼è½¬æ¢ä¸...'; -$messages['messageopenerror'] = 'æ— æ³•ä»ŽæœåŠ¡å™¨ä¸ŠåŠ 载邮件内容。'; +$messages['messageopenerror'] = 'æ— æ³•ä»ŽæœåŠ¡å™¨åŠ 载邮件内容。'; $messages['fileuploaderror'] = 'æ–‡ä»¶ä¸Šä¼ å¤±è´¥ã€‚'; $messages['filesizeerror'] = 'ä¸Šä¼ çš„æ–‡ä»¶è¶…è¿‡äº† $size 的大å°é™åˆ¶ã€‚'; $messages['copysuccess'] = 'æˆåŠŸå¤åˆ¶ $nr 个地å€ã€‚'; $messages['copyerror'] = 'æ— æ³•å¤åˆ¶åœ°å€ã€‚'; $messages['sourceisreadonly'] = 'æºåœ°å€ä¸ºåªè¯»ã€‚'; -$messages['errorsavingcontact'] = 'æ— æ³•ä¿å˜è”系人的地å€ã€‚'; -$messages['movingmessage'] = '移动邮件到...'; -$messages['copyingmessage'] = 'å¤åˆ¶é‚®ä»¶åˆ°...'; -$messages['copyingcontact'] = 'å¤åˆ¶è”系人...'; +$messages['errorsavingcontact'] = 'æ— æ³•ä¿å˜è”系人地å€ã€‚'; +$messages['movingmessage'] = 'æ£åœ¨ç§»åŠ¨é‚®ä»¶...'; +$messages['copyingmessage'] = 'æ£åœ¨å¤åˆ¶é‚®ä»¶...'; +$messages['copyingcontact'] = 'æ£åœ¨å¤åˆ¶è”系人...'; $messages['deletingmessage'] = 'æ£åœ¨åˆ 除邮件...'; $messages['markingmessage'] = 'æ£åœ¨æ ‡è®°é‚®ä»¶...'; -$messages['addingmember'] = 'æ£åœ¨æ·»åŠ è”系人到组...'; -$messages['removingmember'] = 'æ£åœ¨ä»Žç»„ä¸åˆ 除è”系人...'; -$messages['receiptsent'] = 'æˆåŠŸå‘é€äº†ä¸€ä¸ªå·²è¯»å›žæ‰§ã€‚'; -$messages['errorsendingreceipt'] = 'æ— æ³•å‘é€å›žæ‰§ã€‚'; -$messages['deleteidentityconfirm'] = 'æ‚¨çœŸçš„æƒ³åˆ é™¤è¿™ä¸ªéªŒè¯ä¿¡æ¯å—?'; -$messages['nodeletelastidentity'] = 'æ— æ³•åˆ é™¤è¿™ä¸ªèº«ä»½ï¼Œè¿™æ˜¯æœ€åŽä¸€ä¸ªã€‚'; -$messages['forbiddencharacter'] = '目录å包å«éšè—å—符。'; +$messages['addingmember'] = 'æ£åœ¨æ·»åŠ è”系人至群组...'; +$messages['removingmember'] = 'æ£åœ¨ä»Žç¾¤ç»„ä¸åˆ 除è”系人...'; +$messages['receiptsent'] = 'æˆåŠŸå‘é€ä¸€ä¸ªå·²è¯»å›žæ‰§ã€‚'; +$messages['errorsendingreceipt'] = 'æ— æ³•å‘é€å·²è¯»å›žæ‰§ã€‚'; +$messages['deleteidentityconfirm'] = '是å¦åˆ 除该身份?'; +$messages['nodeletelastidentity'] = 'æ— æ³•åˆ é™¤è¯¥èº«ä»½ï¼Œè¿™æ˜¯æœ€åŽä¸€ä¸ªã€‚'; +$messages['forbiddencharacter'] = '目录å包å«ç¦æ¢å—符。'; $messages['selectimportfile'] = '请选择è¦ä¸Šä¼ 的文件。'; -$messages['addresswriterror'] = '已选择的地å€ç°¿ä¸å¯å†™ã€‚'; -$messages['contactaddedtogroup'] = 'æˆåŠŸæ·»åŠ è”系人至该分组。'; -$messages['contactremovedfromgroup'] = 'æˆåŠŸä»Žè¯¥åˆ†ç»„移除è”系人。'; -$messages['nogroupassignmentschanged'] = 'No group assignments changed.'; +$messages['addresswriterror'] = '选ä¸çš„通讯录ä¸å¯å†™ã€‚'; +$messages['contactaddedtogroup'] = 'æ·»åŠ è”系人至该群组æˆåŠŸã€‚'; +$messages['contactremovedfromgroup'] = '从该群组移除è”系人æˆåŠŸã€‚'; +$messages['nogroupassignmentschanged'] = '群组资料没有å˜æ›´ã€‚'; $messages['importwait'] = 'æ£åœ¨å¯¼å…¥ï¼Œè¯·ç¨åŽ...'; -$messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; +$messages['importformaterror'] = '导入失败ï¼æ–‡ä»¶æ— 效。'; $messages['importconfirm'] = '<b>æˆåŠŸå¯¼å…¥ $inserted è”系人</b>'; $messages['importconfirmskipped'] = '<b>跳过已å˜åœ¨çš„ $skipped 项目</b>'; $messages['opnotpermitted'] = 'ä¸å…许的æ“作!'; -$messages['nofromaddress'] = '选ä¸çš„身份ä¸æ²¡æœ‰é‚®ä»¶åœ°å€ã€‚'; -$messages['editorwarning'] = '切æ¢åˆ°çº¯æ–‡æœ¬ç¼–辑器将导致邮件æ£æ–‡ä¸çš„æ‰€æœ‰æ–‡æœ¬æ ¼å¼å¤±æ•ˆï¼Œæ‚¨ç¡®å®šè¦è¿™æ ·åšå—?'; -$messages['httpreceivedencrypterror'] = 'å‘生了一个致命的é…置错误,请立å³è”系管ç†å‘˜ã€‚<b>æ‚¨çš„é‚®ä»¶æ— æ³•å‘é€ã€‚</b>'; +$messages['nofromaddress'] = '选ä¸çš„身份没有邮件地å€ã€‚'; +$messages['editorwarning'] = '切æ¢è‡³çº¯æ–‡æœ¬ç¼–辑器将导致邮件æ£æ–‡ä¸çš„æ‰€æœ‰æ–‡æœ¬æ ¼å¼å¤±æ•ˆï¼Œæ‚¨ç¡®å®šè¦è¿™æ ·åšå—?'; +$messages['httpreceivedencrypterror'] = '<b>æ‚¨çš„é‚®ä»¶æ— æ³•å‘é€</b>ï¼Œå› ä¸ºå‘生了一个严é‡çš„é…置错误,请立å³è”系管ç†å‘˜ã€‚'; $messages['smtpconnerror'] = 'SMTP 错误 ($code):连接æœåŠ¡å™¨å¤±è´¥ã€‚'; $messages['smtpautherror'] = 'SMTP 错误 ($code): 认è¯å¤±è´¥ã€‚'; $messages['smtpfromerror'] = 'SMTP 错误 ($code):æ·»åŠ å‘件人失败 "$from" ($msg)。'; @@ -137,17 +139,17 @@ $messages['smtperror'] = 'SMTP 错误: $msg'; $messages['emailformaterror'] = 'æ— æ•ˆçš„é‚®ä»¶åœ°å€ï¼š$email'; $messages['toomanyrecipients'] = '收件人太多,请å‡å°‘人数至 $max。'; $messages['maxgroupmembersreached'] = '组员数é‡è¶…过最大值 $max。'; -$messages['internalerror'] = 'é‡åˆ°ä¸€ä¸ªå†…部错误,请é‡è¯•ã€‚'; +$messages['internalerror'] = 'å‘生一个内部错误,请é‡è¯•ã€‚'; $messages['contactdelerror'] = 'æ— æ³•åˆ é™¤è”系人。'; $messages['contactdeleted'] = 'åˆ é™¤è”系人æˆåŠŸã€‚'; $messages['contactrestoreerror'] = 'æ— æ³•æ¢å¤å·²åˆ 除的è”系人。'; $messages['contactrestored'] = 'è”系人æ¢å¤æˆåŠŸã€‚'; -$messages['groupdeleted'] = 'æˆåŠŸåˆ 除组。'; -$messages['grouprenamed'] = '组改åæˆåŠŸã€‚'; -$messages['groupcreated'] = 'æˆåŠŸåˆ›å»ºç»„'; +$messages['groupdeleted'] = 'åˆ é™¤ç¾¤ç»„æˆåŠŸã€‚'; +$messages['grouprenamed'] = '群组改åæˆåŠŸã€‚'; +$messages['groupcreated'] = 'æˆåŠŸåˆ›å»ºç¾¤ç»„'; $messages['savedsearchdeleted'] = 'æˆåŠŸåˆ 除ä¿å˜çš„æœç´¢'; $messages['savedsearchdeleteerror'] = 'æ— æ³•åˆ é™¤ä¿å˜çš„æœç´¢'; -$messages['savedsearchcreated'] = 'æˆåŠŸå»ºç«‹ä¿å˜çš„æœç´¢'; +$messages['savedsearchcreated'] = 'æˆåŠŸåˆ›å»ºä¿å˜çš„æœç´¢'; $messages['savedsearchcreateerror'] = 'æ— æ³•åˆ›å»ºä¿å˜çš„æœç´¢ã€‚'; $messages['messagedeleted'] = 'åˆ é™¤é‚®ä»¶æˆåŠŸã€‚'; $messages['messagemoved'] = '移动邮件æˆåŠŸã€‚'; @@ -161,9 +163,9 @@ $messages['folderupdated'] = 'æˆåŠŸæ›´æ–°æ–‡ä»¶å¤¹'; $messages['foldercreated'] = 'æˆåŠŸåˆ›å»ºæ–‡ä»¶å¤¹'; $messages['invalidimageformat'] = 'éžæ³•çš„图åƒç±»åž‹ã€‚'; $messages['mispellingsfound'] = '检查到拼写错误。'; -$messages['parentnotwritable'] = 'æ— æ³•åˆ›å»ºå’Œè½¬ç§»åˆ°æ‰€é€‰çš„ç›®å½•,æƒé™ä¸è¶³ã€‚'; -$messages['messagetoobig'] = 'ç”±äºŽé‚®ä»¶éƒ¨åˆ†è¿‡å¤§æ— æ³•å¤„ç†ã€‚'; -$messages['attachmentvalidationerror'] = 'WARNING! This attachment is suspicious because its type doesn\'t match the type declared in the message. If you do not trust the sender, you shouldn\'t open it in the browser because it may contain malicious contents.<br/><br/><em>Expected: $expected; found: $detected</em>'; -$messages['noscriptwarning'] = 'Warning: This webmail service requires Javascript! In order to use it please enable Javascript in your browser\'s settings.'; +$messages['parentnotwritable'] = 'æ— æ³•åˆ›å»º/转移文件夹至指定的上级目录,æƒé™ä¸è¶³ã€‚'; +$messages['messagetoobig'] = 'é‚®ä»¶è¿‡å¤§æ— æ³•å¤„ç†ã€‚'; +$messages['attachmentvalidationerror'] = 'è¦å‘Šï¼è¯¥é™„件很å¯ç–‘ï¼Œå› ä¸ºå…¶è‡ªèº«çš„æ ¼å¼ä¸Žé‚®ä»¶ä¸å£°æ˜Žçš„æ ¼å¼ä¸ç¬¦ã€‚如果您ä¸ä¿¡ä»»å‘é€äººï¼Œåˆ™ä¸åº”该在æµè§ˆå™¨ä¸æ‰“开该附件。<br/><br/><em>å£°æ˜Žæ ¼å¼ï¼š$expectedï¼›å®žé™…æ ¼å¼ï¼š$detected</em>'; +$messages['noscriptwarning'] = 'è¦å‘Šï¼šæœ¬ç¨‹åºéœ€è¦ Javascript 支æŒï¼è¯·åœ¨æµè§ˆå™¨è®¾ç½®ä¸å¯ç”¨ Javascript。'; ?> diff --git a/program/localization/zh_TW/labels.inc b/program/localization/zh_TW/labels.inc index 7726da5dd..a545f2f81 100644 --- a/program/localization/zh_TW/labels.inc +++ b/program/localization/zh_TW/labels.inc @@ -37,7 +37,6 @@ $labels['drafts'] = 'è‰ç¨¿åŒ£'; $labels['sent'] = '寄件備份'; $labels['trash'] = '垃圾桶'; $labels['junk'] = '垃圾郵件'; -$labels['show_real_foldernames'] = 'Show real names for special folders'; // message listing $labels['subject'] = '主旨'; @@ -194,7 +193,6 @@ $labels['listmode'] = '清單檢視模å¼'; $labels['folderactions'] = '資料夾動作...'; $labels['compact'] = '壓縮'; $labels['empty'] = '清空'; -$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'ç£ç¢Ÿä½¿ç”¨é‡'; $labels['unknown'] = '未知'; @@ -205,7 +203,6 @@ $labels['resetsearch'] = 'é‡è¨æœå°‹'; $labels['searchmod'] = '修改æœå°‹'; $labels['msgtext'] = 'æ•´å°éƒµä»¶'; $labels['body'] = '內文'; -$labels['type'] = 'Type'; $labels['openinextwin'] = '在新視窗開啟'; $labels['emlsave'] = '下載(.eml)'; @@ -357,7 +354,6 @@ $labels['lastpage'] = '顯示最後一é '; $labels['group'] = '群組'; $labels['groups'] = '群組'; -$labels['listgroup'] = 'List group members'; $labels['personaladrbook'] = '個人通訊錄'; $labels['searchsave'] = '儲å˜æœå°‹çµæžœ'; @@ -476,7 +472,6 @@ $labels['spellcheckignorenums'] = '忽略數å—'; $labels['spellcheckignorecaps'] = '忽略大寫å—æ¯'; $labels['addtodict'] = 'åŠ å…¥è©žå…¸'; $labels['mailtoprotohandler'] = '註冊mailto:å”定處ç†ç¨‹å¼'; -$labels['standardwindows'] = 'Handle popups as standard windows'; $labels['forwardmode'] = '郵件轉寄方å¼'; $labels['inline'] = '放入內文'; $labels['asattachment'] = '當æˆé™„件'; diff --git a/program/localization/zh_TW/messages.inc b/program/localization/zh_TW/messages.inc index b6fdcccae..5605ba815 100644 --- a/program/localization/zh_TW/messages.inc +++ b/program/localization/zh_TW/messages.inc @@ -101,16 +101,13 @@ $messages['converting'] = 'ç§»é™¤éƒµä»¶æ ¼å¼ä¸...'; $messages['messageopenerror'] = '無法從伺æœå™¨è¼‰å…¥éƒµä»¶'; $messages['fileuploaderror'] = '檔案上傳失敗'; $messages['filesizeerror'] = '上傳的檔案超éŽäº† $size 的大å°é™åˆ¶'; -$messages['copysuccess'] = 'Successfully copied $nr contacts.'; -$messages['movesuccess'] = 'Successfully moved $nr contacts.'; -$messages['copyerror'] = 'Could not copy any contacts.'; -$messages['moveerror'] = 'Could not move any contacts.'; +$messages['copysuccess'] = '複製 $nr 個ä½å€æˆåŠŸ'; +$messages['copyerror'] = '無法複製任何ä½å€'; $messages['sourceisreadonly'] = 'æ¤ä¾†æºä½å€æ˜¯å”¯è®€çš„'; $messages['errorsavingcontact'] = '無法儲å˜é€£çµ¡äººçš„ä½å€'; $messages['movingmessage'] = '移動郵件ä¸...'; $messages['copyingmessage'] = '複製訊æ¯...'; $messages['copyingcontact'] = '複製群組...'; -$messages['movingcontact'] = 'Moving contact(s)...'; $messages['deletingmessage'] = '刪除訊æ¯...'; $messages['markingmessage'] = '標示訊æ¯...'; $messages['addingmember'] = '新增連絡人至群組'; @@ -129,8 +126,6 @@ $messages['importwait'] = '匯入ä¸ï¼Œè«‹ç¨å€™...'; $messages['importformaterror'] = '匯入失敗ï¼ä¸Šè¼‰çš„æª”æ¡ˆæ ¼å¼ä¸æ”¯æ´'; $messages['importconfirm'] = '<b>æˆåŠŸåŒ¯å…¥ $inserted ç†è³‡æ–™ï¼Œç•¥éŽ $skipped ç†å·²å˜åœ¨çš„資料</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>ç•¥éŽ $skipped 個已å˜åœ¨çš„é …ç›®</b>'; -$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; -$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'ä¸å…許的æ“作'; $messages['nofromaddress'] = '在é¸æ“‡çš„身分ä¸éºå¤±äº†é›»å郵件ä½å€'; $messages['editorwarning'] = '切æ›åˆ°ç´”æ–‡å—編輯模å¼å°‡æœƒéºå¤±æ‰€æœ‰è¨å®šçš„樣å¼ã€‚您確定è¦ç¹¼çºŒå—Žï¼Ÿ'; diff --git a/program/steps/addressbook/copy.inc b/program/steps/addressbook/copy.inc index d4387194a..480a9b52e 100644 --- a/program/steps/addressbook/copy.inc +++ b/program/steps/addressbook/copy.inc @@ -57,16 +57,10 @@ foreach ($cids as $source => $cid) foreach ($cid as $cid) { $a_record = $CONTACTS->get_record($cid, true); - // avoid copying groups - if ($a_record['_type'] == 'group') - continue; - // Check if contact exists, if so, we'll need it's ID // Note: Some addressbooks allows empty email address field - // @TODO: should we check all email addresses? - $email = $CONTACTS->get_col_values('email', $a_record, true); - if (!empty($email)) - $result = $TARGET->search('email', $email[0], 1, true, true); + if (!empty($a_record['email'])) + $result = $TARGET->search('email', $a_record['email'], 1, true, true); else if (!empty($a_record['name'])) $result = $TARGET->search('name', $a_record['name'], 1, true, true); else @@ -120,7 +114,7 @@ foreach ($cids as $source => $cid) } } -if (!$success) +if ($success == 0) $OUTPUT->show_message($errormsg, 'error'); else $OUTPUT->show_message('copysuccess', 'notice', array('nr' => $success)); diff --git a/program/steps/addressbook/delete.inc b/program/steps/addressbook/delete.inc index 3bb2ef500..56118583c 100644 --- a/program/steps/addressbook/delete.inc +++ b/program/steps/addressbook/delete.inc @@ -68,14 +68,48 @@ foreach ($cids as $source => $cid) $page = isset($_SESSION['page']) ? $_SESSION['page'] : 1; // update saved search after data changed -if (($records = rcmail_search_update(true)) !== false) { +if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) { + $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); + $afields = $RCMAIL->config->get('contactlist_fields'); + $search = (array)$_SESSION['search'][$search_request]; + $records = array(); + + // Get records from all sources (refresh search) + foreach ($search as $s => $set) { + $source = $RCMAIL->get_address_book($s); + + // reset page + $source->set_page(1); + $source->set_pagesize(9999); + $source->set_search_set($set); + + // get records + $result = $source->list_records($afields); + + if (!$result->count) { + unset($search[$s]); + continue; + } + + while ($row = $result->next()) { + $row['sourceid'] = $s; + $key = rcube_addressbook::compose_contact_key($row, $sort_col); + $records[$key] = $row; + } + unset($result); + + $search[$s] = $source->get_search_set(); + } + + $_SESSION['search'][$search_request] = $search; + // create resultset object $count = count($records); $first = ($page-1) * $PAGE_SIZE; $result = new rcube_result_set($count, $first); - $pages = ceil((count($records) + $delcnt) / $PAGE_SIZE); // get records from the next page to add to the list + $pages = ceil((count($records) + $delcnt) / $PAGE_SIZE); if ($_GET['_from'] != 'show' && $pages > 1 && $page < $pages) { // sort the records ksort($records, SORT_LOCALE_STRING); diff --git a/program/steps/addressbook/export.inc b/program/steps/addressbook/export.inc index 1e988feab..11c9ca493 100644 --- a/program/steps/addressbook/export.inc +++ b/program/steps/addressbook/export.inc @@ -5,7 +5,7 @@ | program/steps/addressbook/export.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2013, The Roundcube Dev Team | + | Copyright (C) 2008-2011, The Roundcube Dev Team | | Copyright (C) 2011, Kolab Systems AG | | | | Licensed under the GNU General Public License version 3 or | @@ -21,46 +21,6 @@ +-----------------------------------------------------------------------+ */ - -/** - * Copy contact record properties into a vcard object - */ -function prepare_for_export(&$record, $source = null) -{ - $groups = $source && $source->groups && $source->export_groups ? $source->get_record_groups($record['ID']) : null; - - if (empty($record['vcard'])) { - $vcard = new rcube_vcard(); - if ($source) { - $vcard->extend_fieldmap($source->vcard_map); - } - $vcard->load($record['vcard']); - $vcard->reset(); - - foreach ($record as $key => $values) { - list($field, $section) = explode(':', $key); - foreach ((array)$values as $value) { - if (is_array($value) || @strlen($value)) { - $vcard->set($field, $value, strtoupper($section)); - } - } - } - - // append group names - if ($groups) { - $vcard->set('groups', join(',', $groups), null); - } - - $record['vcard'] = $vcard->export(true); - } - // patch categories to alread existing vcard block - else if ($record['vcard'] && !empty($groups) && !strpos($record['vcard'], 'CATEGORIES:')) { - $vgroups = 'CATEGORIES:' . rcube_vcard::vcard_quote(join(',', $groups)); - $record['vcard'] = str_replace('END:VCARD', $vgroups . rcube_vcard::$eol . 'END:VCARD', $record['vcard']); - } -} - - // Use search result if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) { @@ -80,15 +40,11 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search // get records $result = $source->list_records(); - while ($record = $result->next()) { - // because vcard_map is per-source we need to create vcard here - prepare_for_export($record, $source); - - $record['sourceid'] = $s; - $key = rcube_addressbook::compose_contact_key($record, $sort_col); - $records[$key] = $record; + while ($row = $result->next()) { + $row['sourceid'] = $s; + $key = rcube_addressbook::compose_contact_key($row, $sort_col); + $records[$key] = $row; } - unset($result); } @@ -100,35 +56,6 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search $result = new rcube_result_set($count); $result->records = array_values($records); } -// selected contacts -else if (!empty($_REQUEST['_cid'])) { - $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); - $records = array(); - - // Selected contact IDs (with multi-source support) - $cids = rcmail_get_cids(); - - foreach ($cids as $s => $ids) { - $source = $RCMAIL->get_address_book($s); - $result = $source->search('ID', $ids, 1, true, true); - - while ($record = $result->next()) { - // because vcard_map is per-source we need to create vcard here - prepare_for_export($record, $source); - - $record['sourceid'] = $s; - $key = rcube_addressbook::compose_contact_key($record, $sort_col); - $records[$key] = $record; - } - } - - ksort($records, SORT_LOCALE_STRING); - - // create resultset object - $count = count($records); - $result = new rcube_result_set($count); - $result->records = array_values($records); -} // selected directory/group else { $CONTACTS = rcmail_contact_source(null, true); @@ -141,15 +68,33 @@ else { // send downlaod headers header('Content-Type: text/x-vcard; charset='.RCMAIL_CHARSET); -header('Content-Disposition: attachment; filename="contacts.vcf"'); +header('Content-Disposition: attachment; filename="rcube_contacts.vcf"'); while ($result && ($row = $result->next())) { - prepare_for_export($row, $CONTACTS); + // we already have a vcard record + if ($row['vcard'] && $row['name']) { + // fix folding and end-of-line chars + $row['vcard'] = preg_replace('/\r|\n\s+/', '', $row['vcard']); + $row['vcard'] = preg_replace('/\n/', rcube_vcard::$eol, $row['vcard']); + echo rcube_vcard::rfc2425_fold($row['vcard']) . rcube_vcard::$eol; + } + // copy values into vcard object + else { + $vcard = new rcube_vcard(); + $vcard->extend_fieldmap($CONTACTS->vcard_map); + $vcard->load($row['vcard']); + $vcard->reset(); + + foreach ($row as $key => $values) { + list($field, $section) = explode(':', $key); + foreach ((array)$values as $value) { + if (is_array($value) || @strlen($value)) + $vcard->set($field, $value, strtoupper($section)); + } + } - // fix folding and end-of-line chars - $row['vcard'] = preg_replace('/\r|\n\s+/', '', $row['vcard']); - $row['vcard'] = preg_replace('/\n/', rcube_vcard::$eol, $row['vcard']); - echo rcube_vcard::rfc2425_fold($row['vcard']) . rcube_vcard::$eol; + echo $vcard->export(true) . rcube_vcard::$eol; + } } exit; diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index f94d15338..989b7c1c4 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -183,10 +183,11 @@ function rcmail_directory_list($attrib) $attrib['id'] = 'rcmdirectorylist'; $out = ''; + $local_id = '0'; $jsdata = array(); $line_templ = html::tag('li', array( - 'id' => 'rcmli%s', 'class' => '%s', 'noclose' => true), + 'id' => 'rcmli%s', 'class' => '%s'), html::a(array('href' => '%s', 'rel' => '%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s')); @@ -212,7 +213,7 @@ function rcmail_directory_list($attrib) $name = !empty($source['name']) ? $source['name'] : $id; $out .= sprintf($line_templ, - rcube_utils::html_identifier($id, true), + html_identifier($id), $class_name, Q(rcmail_url(null, array('_source' => $id))), $source['id'], @@ -223,11 +224,10 @@ function rcmail_directory_list($attrib) $groupdata = rcmail_contact_groups($groupdata); $jsdata = $groupdata['jsdata']; $out = $groupdata['out']; - $out .= '</li>'; } $line_templ = html::tag('li', array( - 'id' => 'rcmli%s', 'class' => '%s'), + 'id' => 'rcmliS%s', 'class' => '%s'), html::a(array('href' => '#', 'rel' => 'S%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('listsearch', '%s', this)"), '%s')); @@ -245,17 +245,14 @@ function rcmail_directory_list($attrib) $class_name .= ' ' . $source['class_name']; $out .= sprintf($line_templ, - rcube_utils::html_identifier('S'.$id, true), + html_identifier($id), $class_name, $id, $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id))); } $OUTPUT->set_env('contactgroups', $jsdata); - $OUTPUT->set_env('collapsed_abooks', (string)$RCMAIL->config->get('collapsed_abooks','')); $OUTPUT->add_gui_object('folderlist', $attrib['id']); - $OUTPUT->include_script('treelist.js'); - // add some labels to client $OUTPUT->add_label('deletegroupconfirm', 'groupdeleting', 'addingmember', 'removingmember'); @@ -267,23 +264,19 @@ function rcmail_contact_groups($args) { global $RCMAIL; - $groups_html = ''; $groups = $RCMAIL->get_address_book($args['source'])->list_groups(); if (!empty($groups)) { $line_templ = html::tag('li', array( - 'id' => 'rcmli%s', 'class' => 'contactgroup'), + 'id' => 'rcmliG%s', 'class' => 'contactgroup'), html::a(array('href' => '#', 'rel' => '%s:%s', 'onclick' => "return ".JS_OBJECT_NAME.".command('listgroup',{'source':'%s','id':'%s'},this)"), '%s')); - // append collapse/expand toggle and open a new <ul> - $is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false; - $args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), ' '); - + $jsdata = array(); foreach ($groups as $group) { - $groups_html .= sprintf($line_templ, - rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true), + $args['out'] .= sprintf($line_templ, + html_identifier($args['source'] . $group['ID']), $args['source'], $group['ID'], $args['source'], $group['ID'], Q($group['name']) ); @@ -293,10 +286,6 @@ function rcmail_contact_groups($args) } } - $args['out'] .= html::tag('ul', - array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)), - $groups_html); - return $args; } @@ -307,7 +296,7 @@ function rcmail_contacts_list($attrib) global $CONTACTS, $OUTPUT; // define list of cols to be displayed - $a_show_cols = array('name','action'); + $a_show_cols = array('name'); // add id to message list table if not specified if (!strlen($attrib['id'])) @@ -322,7 +311,7 @@ function rcmail_contacts_list($attrib) $OUTPUT->include_script('list.js'); // add some labels to client - $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'movingcontact', 'contactdeleting'); + $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'contactdeleting'); return $out; } @@ -336,73 +325,31 @@ function rcmail_js_contacts_list($result, $prefix='') return; // define list of cols to be displayed - $a_show_cols = array('name','action'); + $a_show_cols = array('name'); while ($row = $result->next()) { - $row['CID'] = $row['ID']; - $row['email'] = reset(rcube_addressbook::get_col_values('email', $row, true)); - - $source_id = $OUTPUT->get_env('source'); $a_row_cols = array(); - $classes = array($row['_type'] ? $row['_type'] : 'person'); + $classes = array('person'); // org records will follow some day // build contact ID with source ID if (isset($row['sourceid'])) { $row['ID'] = $row['ID'].'-'.$row['sourceid']; - $source_id = $row['sourceid']; } // format each col foreach ($a_show_cols as $col) { - $val = ''; - switch ($col) { - case 'name': - $val = Q(rcube_addressbook::compose_list_name($row)); - break; - - case 'action': - if ($row['_type'] == 'group') { - $val = html::a(array( - 'href' => '#list', - 'rel' => $row['ID'], - 'title' => rcube_label('listgroup'), - 'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)", JS_OBJECT_NAME, $source_id, $row['CID']), - ), '»'); - } - else - $val = ' '; - break; - - default: - $val = Q($row[$col]); - break; - } - - $a_row_cols[$col] = $val; + $val = $col == 'name' ? rcube_addressbook::compose_list_name($row) : $row[$col]; + $a_row_cols[$col] = Q($val); } if ($row['readonly']) $classes[] = 'readonly'; - $OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols, join(' ', $classes), array_intersect_key($row, array('ID'=>1,'readonly'=>1,'_type'=>1,'email'=>1,'name'=>1))); + $OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols, join(' ', $classes)); } } -function rcmail_contacts_list_title($attrib) -{ - global $OUTPUT; - - $attrib += array('label' => 'contacts', 'id' => 'rcmabooklisttitle', 'tag' => 'span'); - unset($attrib['name']); - - $OUTPUT->add_gui_object('addresslist_title', $attrib['id']); - $OUTPUT->add_label('contacts'); - - return html::tag($attrib['tag'], $attrib, rcube_label($attrib['label']), html::$common_attrib); -} - - // similar function as /steps/settings/identities.inc::rcmail_identity_frame() function rcmail_contact_frame($attrib) { @@ -471,7 +418,7 @@ function rcmail_get_type_label($type) function rcmail_contact_form($form, $record, $attrib = null) { - global $RCMAIL; + global $RCMAIL, $CONFIG; // Allow plugins to modify contact form content $plugin = $RCMAIL->plugins->exec_hook('contact_form', array( @@ -480,7 +427,7 @@ function rcmail_contact_form($form, $record, $attrib = null) $form = $plugin['form']; $record = $plugin['record']; $edit_mode = $RCMAIL->action != 'show'; - $del_button = $attrib['deleteicon'] ? html::img(array('src' => $RCMAIL->output->get_skin_file($attrib['deleteicon']), 'alt' => rcube_label('delete'))) : rcube_label('delete'); + $del_button = $attrib['deleteicon'] ? html::img(array('src' => $CONFIG['skin_path'] . $attrib['deleteicon'], 'alt' => rcube_label('delete'))) : rcube_label('delete'); unset($attrib['deleteicon']); $out = ''; @@ -593,13 +540,22 @@ function rcmail_contact_form($form, $record, $attrib = null) // iterate over possible subtypes and collect values with their subtype if (is_array($colprop['subtypes'])) { $values = $subtypes = array(); - foreach (rcube_addressbook::get_col_values($field, $record) as $st => $vals) { - foreach((array)$vals as $value) { - $i = count($values); - $subtypes[$i] = $st; - $values[$i] = $value; + foreach ($colprop['subtypes'] as $i => $st) { + $newval = false; + if ($record[$field.':'.$st]) { + $subtypes[count($values)] = $st; + $newval = $record[$field.':'.$st]; + } + else if ($i == 0 && $record[$field]) { + $subtypes[count($values)] = $st; + $newval = $record[$field]; + } + if ($newval !== false) { + if (is_array($newval) && isset($newval[0])) + $values = array_merge($values, $newval); + else + $values[] = $newval; } - // TODO: add $st to $select_subtype if missing ? } } else { @@ -737,42 +693,23 @@ function rcmail_contact_form($form, $record, $attrib = null) function rcmail_contact_photo($attrib) { - global $SOURCE_ID, $CONTACTS, $CONTACT_COLTYPES, $RCMAIL; + global $SOURCE_ID, $CONTACTS, $CONTACT_COLTYPES, $RCMAIL, $CONFIG; if ($result = $CONTACTS->get_result()) $record = $result->first(); - $photo_img = $attrib['placeholder'] ? $RCMAIL->output->get_skin_file($attrib['placeholder']) : 'program/resources/blank.gif'; - if ($record['_type'] == 'group' && $attrib['placeholdergroup']) - $photo_img = $RCMAIL->output->get_skin_file($attrib['placeholdergroup']); - + $photo_img = $attrib['placeholder'] ? $CONFIG['skin_path'] . $attrib['placeholder'] : 'program/resources/blank.gif'; $RCMAIL->output->set_env('photo_placeholder', $photo_img); unset($attrib['placeholder']); $plugin = $RCMAIL->plugins->exec_hook('contact_photo', array('record' => $record, 'data' => $record['photo'])); - // check if we have photo data from contact form - if ($GLOBALS['EDIT_RECORD']) { - $rec = $GLOBALS['EDIT_RECORD']; - if ($rec['photo'] == '-del-') { - $record['photo'] = ''; - } - else if ($_SESSION['contacts']['files'][$rec['photo']]) { - $record['photo'] = $file_id = $rec['photo']; - } - } - if ($plugin['url']) $photo_img = $plugin['url']; else if (preg_match('!^https?://!i', $record['photo'])) $photo_img = $record['photo']; - else if ($record['photo']) { - $url = array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID); - if ($file_id) { - $url['_photo'] = $ff_value = $file_id; - } - $photo_img = $RCMAIL->url($url); - } + else if ($record['photo']) + $photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID)); else $ff_value = '-del-'; // will disable delete-photo action @@ -795,54 +732,6 @@ function rcmail_format_date_col($val) return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false); } -/** - * Updates saved search after data changed - */ -function rcmail_search_update($return = false) -{ - global $RCMAIL; - - if (($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) { - $search = (array)$_SESSION['search'][$search_request]; - $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); - $afields = $return ? $RCMAIL->config->get('contactlist_fields') : array('name', 'email'); - $records = array(); - - foreach ($search as $s => $set) { - $source = $RCMAIL->get_address_book($s); - - // reset page - $source->set_page(1); - $source->set_pagesize(9999); - $source->set_search_set($set); - - // get records - $result = $source->list_records($afields); - - if (!$result->count) { - unset($search[$s]); - continue; - } - - if ($return) { - while ($row = $result->next()) { - $row['sourceid'] = $s; - $key = rcube_addressbook::compose_contact_key($row, $sort_col); - $records[$key] = $row; - } - unset($result); - } - - $search[$s] = $source->get_search_set(); - } - - $_SESSION['search'][$search_request] = $search; - - return $records; - } - - return false; -} /** * Returns contact ID(s) and source(s) from GET/POST data @@ -900,7 +789,6 @@ $OUTPUT->add_handlers(array( 'directorylist' => 'rcmail_directory_list', // 'groupslist' => 'rcmail_contact_groups', 'addresslist' => 'rcmail_contacts_list', - 'addresslisttitle' => 'rcmail_contacts_list_title', 'addressframe' => 'rcmail_contact_frame', 'recordscountdisplay' => 'rcmail_rowcount_display', 'searchform' => array($OUTPUT, 'search_form') @@ -909,6 +797,7 @@ $OUTPUT->add_handlers(array( // register action aliases $RCMAIL->register_action_map(array( 'add' => 'edit.inc', + 'photo' => 'show.inc', 'group-create' => 'groups.inc', 'group-rename' => 'groups.inc', 'group-delete' => 'groups.inc', diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 60f5d7b61..915aac884 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -40,7 +40,6 @@ function rcmail_import_form($attrib) 'multiple' => 'multiple', )); $form = html::p(null, html::label('rcmimportfile', rcube_label('importfromfile')) . $upload->show()); - $table = new html_table(array('cols' => 2)); // addressbook selector if (count($writable_books) > 1) { @@ -49,31 +48,17 @@ function rcmail_import_form($attrib) foreach ($writable_books as $book) $select->add($book['name'], $book['id']); - $table->add('title', html::label('rcmimporttarget', rcube_label('importtarget'))); - $table->add(null, $select->show($target)); + $form .= html::p(null, html::label('rcmimporttarget', rcube_label('importtarget')) + . $select->show($target)); } else { $abook = new html_hiddenfield(array('name' => '_target', 'value' => key($writable_books))); $form .= $abook->show(); } - // selector for group import options - if (count($writable_books) >= 1 || $writable_books[0]->groups) { - $select = new html_select(array('name' => '_groups', 'id' => 'rcmimportgroups', 'is_escaped' => true)); - $select->add(rcube_label('none'), '0'); - $select->add(rcube_label('importgroupsall'), '1'); - $select->add(rcube_label('importgroupsexisting'), '2'); - - $table->add('title', html::label('rcmimportgroups', rcube_label('importgroups'))); - $table->add(null, $select->show(get_input_value('_groups', RCUBE_INPUT_GPC))); - } - - // checkbox to replace the entire address book $check_replace = new html_checkbox(array('name' => '_replace', 'value' => 1, 'id' => 'rcmimportreplace')); - $table->add('title', html::label('rcmimportreplace', rcube_label('importreplace'))); - $table->add(null, $check_replace->show(get_input_value('_replace', RCUBE_INPUT_GPC))); - - $form .= $table->show(array('id' => null) + $attrib); + $form .= html::p(null, $check_replace->show(get_input_value('_replace', RCUBE_INPUT_GPC)) . + html::label('rcmimportreplace', rcube_label('importreplace'))); $OUTPUT->set_env('writable_source', !empty($writable_books)); $OUTPUT->add_label('selectimportfile','importwait'); @@ -149,50 +134,19 @@ function rcmail_import_buttons($attrib) } -/** - * Returns the matching group id. If group doesn't exist, it'll be created if allowed. - */ -function rcmail_import_group_id($group_name, $CONTACTS, $create, &$import_groups) -{ - $group_id = 0; - foreach ($import_groups as $key => $group) { - if (strtolower($group['name']) == strtolower($group_name)) { - $group_id = $group['ID']; - break; - } - } - - // create a new group - if (!$group_id && $create) { - $new_group = $CONTACTS->create_group($group_name); - if (!$new_group['ID']) - $new_group['ID'] = $new_group['id']; - $import_groups[] = $new_group; - $group_id = $new_group['ID']; - } - - return $group_id; -} - - /** The import process **/ $importstep = 'rcmail_import_form'; if (is_array($_FILES['_file'])) { - $replace = (bool)get_input_value('_replace', RCUBE_INPUT_GPC); - $target = get_input_value('_target', RCUBE_INPUT_GPC); - $with_groups = intval(get_input_value('_groups', RCUBE_INPUT_GPC)); + $replace = (bool)get_input_value('_replace', RCUBE_INPUT_GPC); + $target = get_input_value('_target', RCUBE_INPUT_GPC); $vcards = array(); $upload_error = null; $CONTACTS = $RCMAIL->get_address_book($target, true); - if (!$CONTACTS->groups) { - $with_groups = false; - } - if ($CONTACTS->readonly) { $OUTPUT->show_message('addresswriterror', 'error'); } @@ -252,10 +206,6 @@ if (is_array($_FILES['_file'])) { $CONTACTS->delete_all(); } - if ($with_groups) { - $import_groups = $CONTACTS->list_groups(); - } - foreach ($vcards as $vcard) { $a_record = $vcard->get_assoc(); @@ -308,15 +258,6 @@ if (is_array($_FILES['_file'])) { $success = $plugin['result']; if ($success) { - // assign groups for this contact (if enabled) - if ($with_groups && !empty($a_record['groups'])) { - foreach (explode(',', $a_record['groups'][0]) as $group_name) { - if ($group_id = rcmail_import_group_id($group_name, $CONTACTS, $with_groups == 1, $import_groups)) { - $CONTACTS->add_to_group($group_id, $success); - } - } - } - $IMPORT_STATS->inserted++; $IMPORT_STATS->names[] = $a_record['name'] ? $a_record['name'] : $email; } diff --git a/program/steps/addressbook/list.inc b/program/steps/addressbook/list.inc index aca58d279..1bb28658b 100644 --- a/program/steps/addressbook/list.inc +++ b/program/steps/addressbook/list.inc @@ -19,20 +19,47 @@ +-----------------------------------------------------------------------+ */ -if (!empty($_GET['_page'])) - $page = intval($_GET['_page']); -else - $page = !empty($_SESSION['page']) ? $_SESSION['page'] : 1; - -$_SESSION['page'] = $page; +$afields = $RCMAIL->config->get('contactlist_fields'); // Use search result -if (($records = rcmail_search_update(true)) !== false) { +if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) +{ + $search = (array)$_SESSION['search'][$_REQUEST['_search']]; + $records = array(); + + if (!empty($_GET['_page'])) + $page = intval($_GET['_page']); + else + $page = isset($_SESSION['page']) ? $_SESSION['page'] : 1; + + $_SESSION['page'] = $page; + $sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name'); + + // Get records from all sources + foreach ($search as $s => $set) { + $source = $RCMAIL->get_address_book($s); + + // reset page + $source->set_page(1); + $source->set_pagesize(9999); + $source->set_search_set($set); + + // get records + $result = $source->list_records($afields); + + while ($row = $result->next()) { + $row['sourceid'] = $s; + $key = rcube_addressbook::compose_contact_key($row, $sort_col); + $records[$key] = $row; + } + unset($result); + } + // sort the records ksort($records, SORT_LOCALE_STRING); // create resultset object - $count = count($records); + $count = count($records); $first = ($page-1) * $PAGE_SIZE; $result = new rcube_result_set($count, $first); @@ -45,7 +72,6 @@ if (($records = rcmail_search_update(true)) !== false) { } // List selected directory else { - $afields = $RCMAIL->config->get('contactlist_fields'); $CONTACTS = rcmail_contact_source(null, true); // get contacts for this user @@ -55,11 +81,6 @@ else { $OUTPUT->show_message('contactsearchonly', 'notice'); $OUTPUT->command('command', 'advanced-search'); } - - if ($CONTACTS->group_id) { - $OUTPUT->command('set_group_prop', array('ID' => $CONTACTS->group_id) - + array_intersect_key((array)$CONTACTS->get_group($CONTACTS->group_id), array('name'=>1,'email'=>1))); - } } // update message count display diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc index 2adc53bcf..25bfbd48b 100644 --- a/program/steps/addressbook/save.inc +++ b/program/steps/addressbook/save.inc @@ -59,34 +59,15 @@ foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) { } // assign values and subtypes else if (is_array($_POST[$fname])) { - $values = get_input_value($fname, RCUBE_INPUT_POST, true); + $values = get_input_value($fname, RCUBE_INPUT_POST, true); $subtypes = get_input_value('_subtype_' . $col, RCUBE_INPUT_POST); - foreach ($values as $i => $val) { - if ($col == 'email') { - // extract email from full address specification, e.g. "Name" <addr@domain.tld> - $addr = rcube_mime::decode_address_list($val, 1, false); - if (!empty($addr) && ($addr = array_pop($addr)) && $addr['mailto']) { - $val = $addr['mailto']; - } - } - $subtype = $subtypes[$i] ? ':'.$subtypes[$i] : ''; $a_record[$col.$subtype][] = $val; } } else if (isset($_POST[$fname])) { $a_record[$col] = get_input_value($fname, RCUBE_INPUT_POST, true); - - // normalize the submitted date strings - if ($colprop['type'] == 'date') { - if ($timestamp = rcube_utils::strtotime($a_record[$col])) { - $a_record[$col] = date('Y-m-d', $timestamp); - } - else { - unset($a_record[$col]); - } - } } } @@ -94,10 +75,8 @@ foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) { if (empty($a_record['name'])) { $a_record['name'] = rcube_addressbook::compose_display_name($a_record, true); // Reset it if equals to email address (from compose_display_name()) - $email = rcube_addressbook::get_col_values('email', $a_record, true); - if ($a_record['name'] == $email[0]) { + if ($a_record['name'] == $a_record['email'][0]) $a_record['name'] = ''; - } } // do input checks (delegated to $CONTACTS instance) @@ -155,11 +134,11 @@ if (!empty($cid)) $record['email'] = reset($CONTACTS->get_col_values('email', $record, true)); $record['name'] = rcube_addressbook::compose_list_name($record); - foreach (array('name') as $col) + foreach (array('name', 'email') as $col) $a_js_cols[] = Q((string)$record[$col]); // update the changed col in list - $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid, $source, $record); + $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid, $source); // show confirmation $OUTPUT->show_message('successfullysaved', 'confirmation', null, false); diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index efab5e9e5..d583a6d36 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -38,6 +38,58 @@ if ($cid && ($record = $CONTACTS->get_record($cid, true))) { // get address book name (for display) rcmail_set_sourcename($CONTACTS); +// return raw photo of the given contact +if ($RCMAIL->action == 'photo') { + // search for contact first + if (!$record && ($email = get_input_value('_email', RCUBE_INPUT_GPC))) { + foreach ($RCMAIL->get_address_sources() as $s) { + $abook = $RCMAIL->get_address_book($s['id']); + $result = $abook->search(array('email'), $email, 1, true, true, 'photo'); + while ($result && ($record = $result->iterate())) { + if ($record['photo']) + break 2; + } + } + } + + // read the referenced file + if (($file_id = get_input_value('_photo', RCUBE_INPUT_GPC)) && ($tempfile = $_SESSION['contacts']['files'][$file_id])) { + $tempfile = $RCMAIL->plugins->exec_hook('attachment_display', $tempfile); + if ($tempfile['status']) { + if ($tempfile['data']) + $data = $tempfile['data']; + else if ($tempfile['path']) + $data = file_get_contents($tempfile['path']); + } + } + else if ($record['photo']) { + $data = is_array($record['photo']) ? $record['photo'][0] : $record['photo']; + if (!preg_match('![^a-z0-9/=+-]!i', $data)) + $data = base64_decode($data, true); + } + + // let plugins do fancy things with contact photos + $plugin = $RCMAIL->plugins->exec_hook('contact_photo', array('record' => $record, 'email' => $email, 'data' => $data)); + + // redirect to url provided by a plugin + if ($plugin['url']) + $RCMAIL->output->redirect($plugin['url']); + else + $data = $plugin['data']; + + // deliver alt image + if (!$data && ($alt_img = get_input_value('_alt', RCUBE_INPUT_GPC)) && is_file($alt_img)) + $data = file_get_contents($alt_img); + + // cache for one day if requested by email + if (!$cid && $email) + $RCMAIL->output->future_expire_header(86400); + + header('Content-Type: ' . rc_image_content_type($data)); + echo $data ? $data : file_get_contents('program/resources/blank.gif'); + exit; +} + function rcmail_contact_head($attrib) { @@ -49,6 +101,8 @@ function rcmail_contact_head($attrib) return false; } + $microformats = array('name' => 'fn', 'email' => 'email'); + $form = array( 'head' => array( // section 'head' is magic! 'content' => array( @@ -123,7 +177,7 @@ function rcmail_contact_details($attrib) } -function rcmail_render_email_value($email) +function rcmail_render_email_value($email, $col) { return html::a(array( 'href' => 'mailto:' . $email, @@ -134,7 +188,7 @@ function rcmail_render_email_value($email) } -function rcmail_render_url_value($url) +function rcmail_render_url_value($url, $col) { $prefix = preg_match('!^(http|ftp)s?://!', $url) ? '' : 'http://'; return html::a(array( @@ -155,8 +209,9 @@ function rcmail_contact_record_groups($contact_id) return ''; } - $members = $CONTACTS->get_record_groups($contact_id); - $table = new html_table(array('cols' => 2, 'cellspacing' => 0, 'border' => 0)); + $table = new html_table(array('cols' => 2, 'cellspacing' => 0, 'border' => 0)); + + $members = $CONTACTS->get_record_groups($contact_id); $checkbox = new html_checkbox(array('name' => '_gid[]', 'class' => 'groupmember', 'disabled' => $CONTACTS->readonly)); diff --git a/program/steps/addressbook/undo.inc b/program/steps/addressbook/undo.inc index c23bd1cb6..9c171143c 100644 --- a/program/steps/addressbook/undo.inc +++ b/program/steps/addressbook/undo.inc @@ -46,7 +46,30 @@ foreach ((array)$undo['data'] as $source => $cid) } // update saved search after data changed -rcmail_search_update(); +if ($delcnt && ($search_request = $_REQUEST['_search']) && isset($_SESSION['search'][$search_request])) { + $search = (array)$_SESSION['search'][$search_request]; + + foreach ($search as $s => $set) { + $source = $RCMAIL->get_address_book($s); + + // reset page + $source->set_page(1); + $source->set_pagesize(9999); + $source->set_search_set($set); + + // get records + $result = $source->list_records(array('name', 'email')); + + if (!$result->count) { + unset($search[$s]); + continue; + } + + $search[$s] = $source->get_search_set(); + } + + $_SESSION['search'][$search_request] = $search; +} $RCMAIL->session->remove('contact_undo'); diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc index f83f6892e..85aa9542b 100644 --- a/program/steps/mail/attachments.inc +++ b/program/steps/mail/attachments.inc @@ -118,9 +118,12 @@ if (is_array($_FILES['_attachments']['tmp_name'])) { 'alt' => rcube_label('delete') )); } - else { + else if ($COMPOSE['textbuttons']) { $button = Q(rcube_label('delete')); } + else { + $button = ''; + } $content = html::a(array( 'href' => "#delete", diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index 8c0b1ffc0..d3c14a38d 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -52,12 +52,12 @@ foreach ($a_mailboxes as $mbox_name) { } // Get mailbox status - $status = $RCMAIL->storage->folder_status($mbox_name, $diff); + $status = $RCMAIL->storage->folder_status($mbox_name); if ($status & 1) { // trigger plugin hook $RCMAIL->plugins->exec_hook('new_messages', - array('mailbox' => $mbox_name, 'is_current' => $is_current, 'diff' => $diff)); + array('mailbox' => $mbox_name, 'is_current' => $is_current)); } rcmail_send_unread_count($mbox_name, true, null, @@ -81,10 +81,9 @@ foreach ($a_mailboxes as $mbox_name) { if (empty($_GET['_list'])) continue; - // get overall message count; allow caching because rcube_storage::folder_status() - // did a refresh but only in list mode + // get overall message count; allow caching because rcube_storage::folder_status() did a refresh $list_mode = $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'; - $all_count = $RCMAIL->storage->count($mbox_name, $list_mode, $list_mode == 'THREADS', false); + $all_count = $RCMAIL->storage->count($mbox_name, $list_mode, false, false); $page = $RCMAIL->storage->get_page(); $page_size = $RCMAIL->storage->get_pagesize(); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index e9f638cb1..0130b1c55 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -165,8 +165,6 @@ else if ($msg_uid = $COMPOSE['param']['forward_uid']) { else if ($msg_uid = $COMPOSE['param']['uid']) { $compose_mode = RCUBE_COMPOSE_EDIT; } - -$COMPOSE['mode'] = $compose_mode; $OUTPUT->set_env('compose_mode', $compose_mode); $config_show_sig = $RCMAIL->config->get('show_sig', 1); @@ -188,18 +186,9 @@ $LINE_LENGTH = $RCMAIL->config->get('line_length', 72); if (!empty($msg_uid) && empty($COMPOSE['as_attachment'])) { - $mbox_name = $RCMAIL->storage->get_folder(); - - // set format before rcube_message construction - // use the same format as for the message view - if (isset($_SESSION['msg_formats'][$mbox_name.':'.$msg_uid])) { - $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$msg_uid]); - } - else { - $prefer_html = $CONFIG['prefer_html'] || $CONFIG['htmleditor'] || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT; - $RCMAIL->config->set('prefer_html', $prefer_html); - } - + // similar as in program/steps/mail/show.inc + // re-set 'prefer_html' to have possibility to use html part for compose + $CONFIG['prefer_html'] = $CONFIG['prefer_html'] || $CONFIG['htmleditor'] || $compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT; $MESSAGE = new rcube_message($msg_uid); // make sure message is marked as read @@ -324,8 +313,8 @@ foreach ($parts as $header) { else if (!empty($MESSAGE->headers->from)) $fvalue = $MESSAGE->headers->from; - // Reply to message sent by yourself (#1487074, #1489230) - if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) { + // Reply to message sent by yourself (#1487074) + if (!empty($ident) && $fvalue == $ident['ident']) { $fvalue = $MESSAGE->headers->to; } } @@ -413,7 +402,7 @@ function rcmail_compose_headers($attrib) { global $MESSAGE; - list($form_start,) = get_form_tags($attrib); + list($form_start, $form_end) = get_form_tags($attrib); $out = ''; $part = strtolower($attrib['part']); @@ -477,7 +466,7 @@ function rcmail_compose_headers($attrib) function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; + global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -488,7 +477,6 @@ function rcmail_compose_header_from($attrib) if (count($MESSAGE->identities)) { $a_signatures = array(); - $identities = array(); $separator = intval($RCMAIL->config->get('reply_mode')) > 0 && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; @@ -526,21 +514,12 @@ function rcmail_compose_header_from($attrib) $a_signatures[$identity_id]['text'] = $text; $a_signatures[$identity_id]['html'] = $html; } - - // add bcc and reply-to - if (!empty($sql_arr['reply-to'])) { - $identities[$identity_id]['replyto'] = $sql_arr['reply-to']; - } - if (!empty($sql_arr['bcc'])) { - $identities[$identity_id]['bcc'] = $sql_arr['bcc']; - } } $out = $select_from->show($MESSAGE->compose['from']); // add signatures to client $OUTPUT->set_env('signatures', $a_signatures); - $OUTPUT->set_env('identities', $identities); } // no identities, display text input field else { @@ -584,13 +563,13 @@ function rcmail_compose_editor_mode() function rcmail_message_is_html() { - global $RCMAIL, $MESSAGE; - return $RCMAIL->config->get('prefer_html') && ($MESSAGE instanceof rcube_message) && $MESSAGE->has_html_part(true); + global $MESSAGE; + return ($MESSAGE instanceof rcube_message) && $MESSAGE->has_html_part(false, true); } function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { @@ -717,11 +696,6 @@ function rcmail_compose_part_body($part, $isHtml = false) $body = rcmail_remove_signature($body); } } - - if ($part->ctype_parameters['format'] == 'flowed') { - $body = rcube_mime::unfold_flowed($body); - } - // add HTML formatting $body = rcmail_plain_body($body); if ($body) { @@ -742,6 +716,9 @@ function rcmail_compose_part_body($part, $isHtml = false) $txt = new rcube_html2text($body, false, true, $len); $body = $txt->get_text(); } + else if ($part->ctype_secondary == 'enriched') { + $body = rcube_enriched::to_html($body); + } else { if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { $body = rcube_mime::unfold_flowed($body); @@ -761,7 +738,7 @@ function rcmail_compose_part_body($part, $isHtml = false) function rcmail_compose_body($attrib) { - global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY; + global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE, $MESSAGE_BODY; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -945,7 +922,8 @@ function rcmail_create_forward_body($body, $bodyIsHtml) if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); + $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); + $charset = $RCMAIL->output->get_charset(); if (!$bodyIsHtml) { $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; @@ -997,7 +975,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml) function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $COMPOSE; + global $MESSAGE, $OUTPUT, $COMPOSE; /** * add attachments @@ -1053,14 +1031,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) { global $RCMAIL, $COMPOSE, $compose_mode; - $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $attachment) { - $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; - } - - $cid_map = array(); - $messages = array(); - + $cid_map = $messages = array(); foreach ((array)$message->mime_parts as $pid => $part) { if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { @@ -1096,8 +1067,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) } } - if (($attachment = $loaded_attachments[rcmail_attachment_name($part) . $part->mimetype]) - || ($attachment = rcmail_save_attachment($message, $pid))) { + if ($attachment = rcmail_save_attachment($message, $pid)) { $COMPOSE['attachments'][$attachment['id']] = $attachment; if ($bodyIsHtml && ($part->content_id || $part->content_location)) { $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', @@ -1150,7 +1120,7 @@ function rcmail_write_forward_attachments() $names = array(); $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $attachment) { + foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1370,8 +1340,9 @@ function rcmail_compose_attachment_list($attrib) if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - $out = "\n"; + $out = "\n"; $jslist = array(); + $button = ''; if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { @@ -1380,27 +1351,38 @@ function rcmail_compose_attachment_list($attrib) 'alt' => rcube_label('delete') )); } - else + else if (rcube_utils::get_boolean($attrib['textbuttons'])) { $button = Q(rcube_label('delete')); + } foreach ($COMPOSE['attachments'] as $id => $a_prop) { if (empty($a_prop)) continue; - $out .= html::tag('li', array('id' => 'rcmfile'.$id, 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name'])), + $out .= html::tag('li', + array( + 'id' => 'rcmfile'.$id, + 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name']), + 'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)", + ), html::a(array( 'href' => "#delete", 'title' => rcube_label('delete'), 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id), - 'class' => 'delete'), - $button) . Q($a_prop['name'])); + 'class' => 'delete' + ), + $button + ) . Q($a_prop['name']) + ); - $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); + $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); } } if ($attrib['deleteicon']) $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; + else if (rcube_utils::get_boolean($attrib['textbuttons'])) + $COMPOSE['textbuttons'] = true; if ($attrib['cancelicon']) $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']); if ($attrib['loadingicon']) @@ -1427,7 +1409,7 @@ function rcmail_compose_attachment_form($attrib) $out = html::div($attrib, $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'name' => 'uploadform', 'method' => 'post', 'enctype' => 'multipart/form-data'), - html::div(null, rcmail_compose_attachment_field()) . + html::div(null, rcmail_compose_attachment_field(array('size' => $attrib['attachmentfieldsize']))) . html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . (get_boolean($attrib['buttons']) ? html::div('buttons', $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . @@ -1441,7 +1423,7 @@ function rcmail_compose_attachment_form($attrib) } -function rcmail_compose_attachment_field($attrib = array()) +function rcmail_compose_attachment_field($attrib) { $attrib['type'] = 'file'; $attrib['name'] = '_attachments[]'; @@ -1559,7 +1541,7 @@ function rcmail_editor_selector($attrib) $select->add(Q(rcube_label('plaintoggle')), 'plain'); return $select->show($useHtml ? 'html' : 'plain'); -/* + foreach ($choices as $value => $text) { $attrib['id'] = '_' . $value; $attrib['value'] = $value; @@ -1567,7 +1549,6 @@ function rcmail_editor_selector($attrib) } return $selector; -*/ } @@ -1661,7 +1642,7 @@ function rcmail_addressbook_list($attrib = array()) $class_name .= ' ' . $source['class_name']; $out .= sprintf($line_templ, - html_identifier($id,true), + html_identifier($id), $class_name, $source['id'], $js_id, (!empty($source['name']) ? $source['name'] : $id)); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index a7d9ca240..2938e91e1 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -89,12 +89,11 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { } $threading = (bool) $RCMAIL->storage->get_threading(); - $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); // set current mailbox and some other vars in client environment $OUTPUT->set_env('mailbox', $mbox_name); $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); - $OUTPUT->set_env('delimiter', $delimiter); + $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); @@ -120,48 +119,11 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { if (!$OUTPUT->ajax_call) $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', - 'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait'); + 'copy', 'move', 'quota'); - $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); - $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); - - $OUTPUT->set_pagetitle($pagetitle); + $OUTPUT->set_pagetitle(rcmail_localize_foldername($RCMAIL->storage->mod_folder($mbox_name))); } -// register UI objects -$OUTPUT->add_handlers(array( - 'mailboxlist' => 'rcmail_mailbox_list', - 'messages' => 'rcmail_message_list', - 'messagecountdisplay' => 'rcmail_messagecount_display', - 'quotadisplay' => 'rcmail_quota_display', - 'mailboxname' => 'rcmail_mailbox_name_display', - 'messageheaders' => 'rcmail_message_headers', - 'messagefullheaders' => 'rcmail_message_full_headers', - 'messagebody' => 'rcmail_message_body', - 'messagecontentframe' => 'rcmail_messagecontent_frame', - 'messageimportform' => 'rcmail_message_import_form', - 'searchfilter' => 'rcmail_search_filter', - 'searchform' => array($OUTPUT, 'search_form'), -)); - -// register action aliases -$RCMAIL->register_action_map(array( - 'refresh' => 'check_recent.inc', - 'preview' => 'show.inc', - 'print' => 'show.inc', - 'move' => 'move_del.inc', - 'delete' => 'move_del.inc', - 'send' => 'sendmail.inc', - 'expunge' => 'folders.inc', - 'purge' => 'folders.inc', - 'remove-attachment' => 'attachments.inc', - 'display-attachment' => 'attachments.inc', - 'upload' => 'attachments.inc', - 'group-expand' => 'autocomplete.inc', -)); - - - /** * Returns 'to' if current folder is configured Sent or Drafts * or their subfolders, otherwise returns 'from'. @@ -177,9 +139,7 @@ function rcmail_message_list_smart_column_name() $sent_mbox = $RCMAIL->config->get('sent_mbox'); $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); - if ((strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) - && strtoupper($mbox) != 'INBOX' - ) { + if (strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) { return 'to'; } @@ -260,7 +220,7 @@ function rcmail_message_list($attrib) if (!in_array('threads', $a_show_cols)) array_unshift($a_show_cols, 'threads'); - $_SESSION['skin_path'] = $CONFIG['skin_path']; + $skin_path = $_SESSION['skin_path'] = $CONFIG['skin_path']; // set client env $OUTPUT->add_gui_object('messagelist', $attrib['id']); @@ -272,13 +232,15 @@ function rcmail_message_list($attrib) $OUTPUT->include_script('list.js'); - $table = new html_table($attrib); - if (!$attrib['noheader']) { - foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) - $table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); - } + $thead = ''; + foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) + $thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); - return $table->show(); + return html::tag('table', + $attrib, + html::tag('thead', null, html::tag('tr', null, $thead)) . + html::tag('tbody', null, ''), + array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); } @@ -325,7 +287,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; // get name of smart From/To column in folder context - if (array_search('fromto', $a_show_cols) !== false) { + if (($f = array_search('fromto', $a_show_cols)) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -341,7 +303,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null } // loop through message headers - foreach ($a_headers as $header) { + foreach ($a_headers as $n => $header) { if (empty($header)) continue; @@ -415,6 +377,7 @@ function rcmail_message_list_head($attrib, $a_show_cols) global $RCMAIL; $skin_path = $_SESSION['skin_path']; + $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s")); // check to see if we have some settings for sorting $sort_col = $_SESSION['sort_col']; @@ -450,7 +413,7 @@ function rcmail_message_list_head($attrib, $a_show_cols) $cells = array(); // get name of smart From/To column in folder context - if (array_search('fromto', $a_show_cols) !== false) { + if (($f = array_search('fromto', $a_show_cols)) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -641,8 +604,6 @@ function rcmail_check_safe(&$message) $message->set_safe(true); } } - - $RCMAIL->plugins->exec_hook('message_check_safe', array('message' => $message)); break; case 2: // always @@ -742,10 +703,7 @@ function rcmail_print_body($part, $p = array()) + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); // convert html to text/plain - if ($data['plain'] && ($data['type'] == 'html' || $data['type'] == 'enriched')) { - if ($data['type'] == 'enriched') { - $data['body'] = rcube_enriched::to_html($data['body']); - } + if ($data['type'] == 'html' && $data['plain']) { $txt = new rcube_html2text($data['body'], false, true); $body = $txt->get_text(); $part->ctype_secondary = 'plain'; @@ -771,13 +729,8 @@ function rcmail_print_body($part, $p = array()) unset($data['body']); // plaintext postprocessing - if ($part->ctype_secondary == 'plain') { - if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { - $body = rcube_mime::unfold_flowed($body); - } - - $body = rcmail_plain_body($body); - } + if ($part->ctype_secondary == 'plain') + $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); // allow post-processing of the message body $data = $RCMAIL->plugins->exec_hook('message_part_after', @@ -791,16 +744,16 @@ function rcmail_print_body($part, $p = array()) * Handle links and citation marks in plain text message * * @param string Plain text string + * @param boolean Text uses format=flowed * * @return string Formatted HTML string */ -function rcmail_plain_body($body) +function rcmail_plain_body($body, $flowed=false) { global $RCMAIL; // make links and email-addresses clickable - $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); - $replacer = new rcmail_string_replacer($attribs); + $replacer = new rcmail_string_replacer; // search for patterns like links and e-mail addresses and replace with tokens $body = $replacer->replace($body); @@ -826,10 +779,48 @@ function rcmail_plain_body($body) str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; $last = $n; } + else if ($flowed) { + // previous line is flowed + if (isset($body[$last]) && $body[$n] + && $body[$last][strlen($body[$last])-1] == ' ') { + // merge lines + $body[$last] .= $body[$n]; + unset($body[$n]); + } + else { + $last = $n; + } + } } else { $q = 0; - if ($quote_level > 0) + if ($flowed) { + // sig separator - line is fixed + if ($body[$n] == '-- ') { + $last = $last_sig = $n; + } + else { + // remove space-stuffing + if ($body[$n][0] == ' ') + $body[$n] = substr($body[$n], 1); + + // previous line is flowed? + if (isset($body[$last]) && $body[$n] + && $last !== $last_sig + && $body[$last][strlen($body[$last])-1] == ' ' + ) { + $body[$last] .= $body[$n]; + unset($body[$n]); + } + else { + $last = $n; + } + } + if ($quote_level > 0) + $body[$last] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$last]; + } + else if ($quote_level > 0) $body[$n] = $replacer->get_replacement($replacer->add( str_repeat('</blockquote>', $quote_level))) . $body[$n]; } @@ -900,7 +891,7 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) */ function rcmail_message_headers($attrib, $headers=null) { - global $MESSAGE, $PRINT_MODE, $RCMAIL; + global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL; static $sa_attrib; // keep header table attrib @@ -1085,7 +1076,7 @@ function rcmail_message_body($attrib) $header_attrib[$regs[1]] = $value; if (!empty($MESSAGE->parts)) { - foreach ($MESSAGE->parts as $part) { + foreach ($MESSAGE->parts as $i => $part) { if ($part->type == 'headers') { $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); } @@ -1189,9 +1180,10 @@ function rcmail_message_body($attrib) $show_link = array( 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), 'onclick' => sprintf( - 'return %s.command(\'load-attachment\',\'%s\',this)', + 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', JS_OBJECT_NAME, - $attach_prop->mime_id) + $attach_prop->mime_id, + $mimetype) ); $out .= html::p('image-attachment', html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)), @@ -1377,7 +1369,7 @@ function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null /** - * parse link (a, link, area) attributes and set correct target + * parse link attributes and set correct target */ function rcmail_alter_html_link($matches) { @@ -1386,9 +1378,9 @@ function rcmail_alter_html_link($matches) // Support unicode/punycode in top-level domain part $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))'; - $tag = strtolower($matches[1]); + $tag = $matches[1]; $attrib = parse_attrib_string($matches[2]); - $end = '>'; + $end = '>'; // Remove non-printable characters in URL (#1487805) if ($attrib['href']) @@ -1415,11 +1407,6 @@ function rcmail_alter_html_link($matches) $attrib['target'] = '_blank'; } - // Better security by adding rel="noreferrer" (#1484686) - if (($tag == 'a' || $tag == 'area') && $attrib['href'] && $attrib['href'][0] != '#') { - $attrib['rel'] = 'noreferrer'; - } - // allowed attributes for a|link|area tags $allow = array('href','name','target','onclick','id','class','style','title', 'rel','type','media','alt','coords','nohref','hreflang','shape'); @@ -1443,8 +1430,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $c = count($a_parts); $j = 0; $out = ''; - $allvalues = array(); - $show_email = $RCMAIL->config->get('message_show_email'); + $allvalues = array(); if ($addicon && !isset($_SESSION['writeable_abook'])) { $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; @@ -1458,7 +1444,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $valid = check_email($mailto, false); // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>" - if (!$show_email && $valid && $name && $name != $mailto && strpos($name, '@')) { + if ($name && $valid && $name != $mailto && strpos($name, '@')) { $name = ''; } @@ -1476,21 +1462,13 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, } else if ($valid) { if ($linked) { - $attrs = array( - 'href' => 'mailto:' . $mailto, - 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), - 'class' => "rcmContactAddress", - ); - - if ($show_email && $name && $mailto) { - $content = Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto); - } - else { - $content = Q($name ? $name : $mailto); - $attrs['title'] = $mailto; - } - - $address = html::a($attrs, $content); + $address = html::a(array( + 'href' => 'mailto:'.$mailto, + 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), + 'title' => $mailto, + 'class' => "rcmContactAddress", + ), + Q($name ? $name : $mailto)); } else { $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), @@ -1617,6 +1595,45 @@ function rcmail_draftinfo_decode($str) } +function rcmail_message_part_controls($attrib) +{ + global $MESSAGE, $RCMAIL; + + $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC)); + if (!is_object($MESSAGE) || !is_array($MESSAGE->parts) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE->mime_parts[$part]) + return ''; + + $part = $MESSAGE->mime_parts[$part]; + $table = new html_table(array('cols' => 3)); + + $filename = rcmail_attachment_name($part); + + if (!empty($filename)) { + $table->add('title', Q(rcube_label('filename'))); + $table->add('header', Q($filename)); + $table->add('download-link', html::a(array('href' => './?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING'])), Q(rcube_label('download')))); + } + + $table->add('title', Q(rcube_label('filesize'))); + $table->add('header', Q($RCMAIL->message_part_size($part))); + + return $table->show($attrib); +} + + +function rcmail_message_part_frame($attrib) +{ + global $MESSAGE; + + $part = $MESSAGE->mime_parts[asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))]; + $ctype_primary = strtolower($part->ctype_primary); + + $attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary=='text' ? '_embed=' : '_preload='), $_SERVER['QUERY_STRING']); + + return html::iframe($attrib); +} + + /** * clear message composing settings */ @@ -1704,7 +1721,8 @@ function rcmail_send_mdn($message, &$smtp_error) $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); - if ($sent) { + if ($sent) + { $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); return true; } @@ -1784,15 +1802,19 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r // Try Return-Path if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { + $return_path = array_map('strtolower', (array) $return_path); + foreach ($identities as $idx => $ident) { // Return-Path header contains an email address, but on some mailing list // it can be e.g. <pear-dev-return-55250-local=domain.tld@lists.php.net> // where local@domain.tld is the address we're looking for (#1489241) - $ident1 = $ident['email_ascii']; + $ident1 = strtolower($ident['email_ascii']); $ident2 = str_replace('@', '=', $ident1); + $ident1 = '<' . $ident1 . '>'; + $ident2 = '-' . $ident2 . '@'; - foreach ((array)$return_path as $path) { - if (stripos($path, $ident1) !== false || stripos($path, $ident2)) { + foreach ($return_path as $path) { + if ($path == $ident1 || stripos($path, $ident2)) { $from_idx = $idx; break 2; } @@ -1800,13 +1822,27 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r } } - // See identity_select plugin for example usage of this hook - $plugin = rcmail::get_instance()->plugins->exec_hook('identity_select', - array('message' => $MESSAGE, 'identities' => $identities, 'selected' => $from_idx)); + // Fallback using Delivered-To + if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$delivered_to)) { + $from_idx = $idx; + break; + } + } + } - $selected = $plugin['selected']; + // Fallback using Envelope-To + if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$envelope_to)) { + $from_idx = $idx; + break; + } + } + } - return $identities[$selected !== null ? $selected : $default_identity]; + return $identities[$from_idx !== null ? $from_idx : $default_identity]; } // Fixes some content-type names @@ -1863,15 +1899,13 @@ function rcmail_search_filter($attrib) $attrib['onchange'] = JS_OBJECT_NAME.'.filter_mailbox(this.value)'; - // Content-Type values of messages with attachments - // the same as in app.js:add_message_row() - $ctypes = array('application/', 'multipart/m', 'multipart/signed', 'multipart/report'); - - // Build search string of "with attachment" filter - $attachment = str_repeat(' OR', count($ctypes)-1); - foreach ($ctypes as $type) { - $attachment .= ' HEADER Content-Type ' . rcube_imap_generic::escape($type); - } + /* + RFC3501 (6.4.4): 'ALL', 'RECENT', + 'ANSWERED', 'DELETED', 'FLAGGED', 'SEEN', + 'UNANSWERED', 'UNDELETED', 'UNFLAGGED', 'UNSEEN', + 'NEW', // = (RECENT UNSEEN) + 'OLD' // = NOT RECENT + */ $select_filter = new html_select($attrib); $select_filter->add(rcube_label('all'), 'ALL'); @@ -1882,7 +1916,6 @@ function rcmail_search_filter($attrib) $select_filter->add(rcube_label('deleted'), 'DELETED'); $select_filter->add(rcube_label('undeleted'), 'UNDELETED'); } - $select_filter->add(rcube_label('withattachment'), $attachment); $select_filter->add(rcube_label('priority').': '.rcube_label('highest'), 'HEADER X-PRIORITY 1'); $select_filter->add(rcube_label('priority').': '.rcube_label('high'), 'HEADER X-PRIORITY 2'); $select_filter->add(rcube_label('priority').': '.rcube_label('normal'), 'NOT HEADER X-PRIORITY 1 NOT HEADER X-PRIORITY 2 NOT HEADER X-PRIORITY 4 NOT HEADER X-PRIORITY 5'); @@ -1912,36 +1945,35 @@ function rcmail_message_error($uid=null) $RCMAIL->output->send('messageerror'); } -function rcmail_message_import_form($attrib = array()) -{ - global $OUTPUT; - - // set defaults - $attrib += array('id' => 'rcmImportform', 'buttons' => 'yes'); - - // Get filesize, enable upload progress bar - $max_filesize = rcube_upload_init(); - - $button = new html_inputfield(array('type' => 'button')); - $fileinput = new html_inputfield(array( - 'type' => 'file', - 'name' => '_file[]', - 'multiple' => 'multiple', - 'accept' => ".eml, .mbox, message/rfc822, text/*", - )); - - $out = html::div($attrib, - $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'method' => 'post', 'enctype' => 'multipart/form-data'), - html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => '')) . - html::div(null, $fileinput->show()) . - html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . - (get_boolean($attrib['buttons']) ? html::div('buttons', - $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . - $button->show(rcube_label('upload'), array('class' => 'button mainaction', 'onclick' => JS_OBJECT_NAME . ".command('import-messages', this.form)")) - ) : '') - ) - ); +// register UI objects +$OUTPUT->add_handlers(array( + 'mailboxlist' => 'rcmail_mailbox_list', + 'messages' => 'rcmail_message_list', + 'messagecountdisplay' => 'rcmail_messagecount_display', + 'quotadisplay' => 'rcmail_quota_display', + 'mailboxname' => 'rcmail_mailbox_name_display', + 'messageheaders' => 'rcmail_message_headers', + 'messagefullheaders' => 'rcmail_message_full_headers', + 'messagebody' => 'rcmail_message_body', + 'messagecontentframe' => 'rcmail_messagecontent_frame', + 'messagepartframe' => 'rcmail_message_part_frame', + 'messagepartcontrols' => 'rcmail_message_part_controls', + 'searchfilter' => 'rcmail_search_filter', + 'searchform' => array($OUTPUT, 'search_form'), +)); - $OUTPUT->add_gui_object('importform', $attrib['id'].'Frm'); - return $out; -} +// register action aliases +$RCMAIL->register_action_map(array( + 'refresh' => 'check_recent.inc', + 'preview' => 'show.inc', + 'print' => 'show.inc', + 'moveto' => 'move_del.inc', + 'delete' => 'move_del.inc', + 'send' => 'sendmail.inc', + 'expunge' => 'folders.inc', + 'purge' => 'folders.inc', + 'remove-attachment' => 'attachments.inc', + 'display-attachment' => 'attachments.inc', + 'upload' => 'attachments.inc', + 'group-expand' => 'autocomplete.inc', +)); diff --git a/program/steps/mail/func.inc.orig b/program/steps/mail/func.inc.orig new file mode 100644 index 000000000..5bae86c10 --- /dev/null +++ b/program/steps/mail/func.inc.orig @@ -0,0 +1,1964 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/mail/func.inc | + | | + | This file is part of the Roundcube Webmail client | + | 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. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Provide webmail functionality and GUI objects | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +// setup some global vars used by mail steps +$SENT_MBOX = $RCMAIL->config->get('sent_mbox'); +$DRAFTS_MBOX = $RCMAIL->config->get('drafts_mbox'); +$SEARCH_MODS_DEFAULT = array( + '*' => array('subject'=>1, 'from'=>1), + $SENT_MBOX => array('subject'=>1, 'to'=>1), + $DRAFTS_MBOX => array('subject'=>1, 'to'=>1) +); + +// always instantiate storage object (but not connect to server yet) +$RCMAIL->storage_init(); + +// set imap properties and session vars +if (strlen(trim($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC, true)))) + $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox)); +else if ($RCMAIL->storage) + $_SESSION['mbox'] = $RCMAIL->storage->get_folder(); + +if (!empty($_GET['_page'])) + $RCMAIL->storage->set_page(($_SESSION['page'] = intval($_GET['_page']))); + +// set default sort col/order to session +if (!isset($_SESSION['sort_col'])) + $_SESSION['sort_col'] = !empty($CONFIG['message_sort_col']) ? $CONFIG['message_sort_col'] : ''; +if (!isset($_SESSION['sort_order'])) + $_SESSION['sort_order'] = strtoupper($CONFIG['message_sort_order']) == 'ASC' ? 'ASC' : 'DESC'; + +// set threads mode +$a_threading = $RCMAIL->config->get('message_threading', array()); +if (isset($_GET['_threads'])) { + if ($_GET['_threads']) + $a_threading[$_SESSION['mbox']] = true; + else + unset($a_threading[$_SESSION['mbox']]); + $RCMAIL->user->save_prefs(array('message_threading' => $a_threading)); +} +$RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]); + +// set message set for search result +if (!empty($_REQUEST['_search']) && isset($_SESSION['search']) + && $_SESSION['search_request'] == $_REQUEST['_search'] +) { + $RCMAIL->storage->set_search_set($_SESSION['search']); + $OUTPUT->set_env('search_request', $_REQUEST['_search']); + $OUTPUT->set_env('search_text', $_SESSION['last_text_search']); +} + +// set main env variables, labels and page title +if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { + // connect to storage server and trigger error on failure + $RCMAIL->storage_connect(); + + $mbox_name = $RCMAIL->storage->get_folder(); + + if (empty($RCMAIL->action)) { + // initialize searching result if search_filter is used + if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { + $search_request = md5($mbox_name.$_SESSION['search_filter']); + + $RCMAIL->storage->search($mbox_name, $_SESSION['search_filter'], RCMAIL_CHARSET, rcmail_sort_column()); + $_SESSION['search'] = $RCMAIL->storage->get_search_set(); + $_SESSION['search_request'] = $search_request; + $OUTPUT->set_env('search_request', $search_request); + } + + $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); + $OUTPUT->set_env('search_mods', $search_mods); + } + + $threading = (bool) $RCMAIL->storage->get_threading(); + + // set current mailbox and some other vars in client environment + $OUTPUT->set_env('mailbox', $mbox_name); + $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); + $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); + $OUTPUT->set_env('threading', $threading); + $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); + $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); + if ($RCMAIL->storage->get_capability('QUOTA')) { + $OUTPUT->set_env('quota', true); + } + + foreach (array('delete_junk','flag_for_deletion','read_when_deleted','skip_deleted','display_next','message_extwin','compose_extwin','forward_attachment') as $prop) { + if ($CONFIG[$prop]) + $OUTPUT->set_env($prop, true); + } + + if ($CONFIG['trash_mbox']) + $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']); + if ($CONFIG['drafts_mbox']) + $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); + if ($CONFIG['junk_mbox']) + $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); + + if (!empty($_SESSION['browser_caps'])) + $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']); + + if (!$OUTPUT->ajax_call) + $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', + 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', + 'copy', 'move', 'quota'); + + $OUTPUT->set_pagetitle(rcmail_localize_foldername($RCMAIL->storage->mod_folder($mbox_name))); +} + +/** + * Returns 'to' if current folder is configured Sent or Drafts + * or their subfolders, otherwise returns 'from'. + * + * @return string Column name + */ +function rcmail_message_list_smart_column_name() +{ + global $RCMAIL; + + $delim = $RCMAIL->storage->get_hierarchy_delimiter(); + $mbox = $RCMAIL->storage->get_folder(); + $sent_mbox = $RCMAIL->config->get('sent_mbox'); + $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); + + if (strpos($mbox.$delim, $sent_mbox.$delim) === 0 || strpos($mbox.$delim, $drafts_mbox.$delim) === 0) { + return 'to'; + } + + return 'from'; +} + +/** + * Returns configured messages list sorting column name + * The name is context-sensitive, which means if sorting is set to 'fromto' + * it will return 'from' or 'to' according to current folder type. + * + * @return string Column name + */ +function rcmail_sort_column() +{ + global $RCMAIL; + + if (isset($_SESSION['sort_col'])) { + $column = $_SESSION['sort_col']; + } + else { + $column = $RCMAIL->config->get('message_sort_col'); + } + + // get name of smart From/To column in folder context + if ($column == 'fromto') { + $column = rcmail_message_list_smart_column_name(); + } + + return $column; +} + +/** + * Returns configured message list sorting order + * + * @return string Sorting order (ASC|DESC) + */ +function rcmail_sort_order() +{ + global $RCMAIL; + + if (isset($_SESSION['sort_order'])) { + return $_SESSION['sort_order']; + } + + return $RCMAIL->config->get('message_sort_order'); +} + +/** + * return the message list as HTML table + */ +function rcmail_message_list($attrib) +{ + global $CONFIG, $OUTPUT; + + // add some labels to client + $OUTPUT->add_label('from', 'to'); + + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcubemessagelist'; + + // define list of cols to be displayed based on parameter or config + if (empty($attrib['columns'])) { + $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); + $OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$CONFIG['dont_override'])); + } + else { + $a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns'])); + $attrib['columns'] = $a_show_cols; + } + + // save some variables for use in ajax list + $_SESSION['list_attrib'] = $attrib; + // make sure 'threads' and 'subject' columns are present + if (!in_array('subject', $a_show_cols)) + array_unshift($a_show_cols, 'subject'); + if (!in_array('threads', $a_show_cols)) + array_unshift($a_show_cols, 'threads'); + + $skin_path = $_SESSION['skin_path'] = $CONFIG['skin_path']; + + // set client env + $OUTPUT->add_gui_object('messagelist', $attrib['id']); + $OUTPUT->set_env('autoexpand_threads', intval($CONFIG['autoexpand_threads'])); + $OUTPUT->set_env('sort_col', $_SESSION['sort_col']); + $OUTPUT->set_env('sort_order', $_SESSION['sort_order']); + $OUTPUT->set_env('messages', array()); + $OUTPUT->set_env('coltypes', $a_show_cols); + + $OUTPUT->include_script('list.js'); + + $thead = ''; + foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) + $thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); + + return html::tag('table', + $attrib, + html::tag('thead', null, html::tag('tr', null, $thead)) . + html::tag('tbody', null, ''), + array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); +} + + +/** + * return javascript commands to add rows to the message list + */ +function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null) +{ + global $CONFIG, $RCMAIL, $OUTPUT; + + if (empty($a_show_cols)) { + if (!empty($_SESSION['list_attrib']['columns'])) + $a_show_cols = $_SESSION['list_attrib']['columns']; + else + $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); + } + else { + if (!is_array($a_show_cols)) + $a_show_cols = preg_split('/[\s,;]+/', strip_quotes($a_show_cols)); + $head_replace = true; + } + + $mbox = $RCMAIL->storage->get_folder(); + + // make sure 'threads' and 'subject' columns are present + if (!in_array('subject', $a_show_cols)) + array_unshift($a_show_cols, 'subject'); + if (!in_array('threads', $a_show_cols)) + array_unshift($a_show_cols, 'threads'); + + $_SESSION['list_attrib']['columns'] = $a_show_cols; + + // Make sure there are no duplicated columns (#1486999) + $a_show_cols = array_unique($a_show_cols); + + // Plugins may set header's list_cols/list_flags and other rcube_message_header variables + // and list columns + $plugin = $RCMAIL->plugins->exec_hook('messages_list', + array('messages' => $a_headers, 'cols' => $a_show_cols)); + + $a_show_cols = $plugin['cols']; + $a_headers = $plugin['messages']; + + $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; + + // get name of smart From/To column in folder context + if (($f = array_search('fromto', $a_show_cols)) !== false) { + $smart_col = rcmail_message_list_smart_column_name(); + } + + $OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col); + + if (empty($a_headers)) + return; + + // remove 'threads', 'attachment', 'flag', 'status' columns, we don't need them here + foreach (array('threads', 'attachment', 'flag', 'status', 'priority') as $col) { + if (($key = array_search($col, $a_show_cols)) !== FALSE) + unset($a_show_cols[$key]); + } + + // loop through message headers + foreach ($a_headers as $n => $header) { + if (empty($header)) + continue; + + $a_msg_cols = array(); + $a_msg_flags = array(); + + // format each col; similar as in rcmail_message_list() + foreach ($a_show_cols as $col) { + $col_name = $col == 'fromto' ? $smart_col : $col; + + if (in_array($col_name, array('from', 'to', 'cc', 'replyto'))) + $cont = rcmail_address_string($header->$col_name, 3, false, null, $header->charset); + else if ($col == 'subject') { + $cont = trim(rcube_mime::decode_header($header->$col, $header->charset)); + if (!$cont) $cont = rcube_label('nosubject'); + $cont = Q($cont); + } + else if ($col == 'size') + $cont = show_bytes($header->$col); + else if ($col == 'date') + $cont = format_date($header->date); + else + $cont = Q($header->$col); + + $a_msg_cols[$col] = $cont; + } + + $a_msg_flags = array_change_key_case(array_map('intval', (array) $header->flags)); + if ($header->depth) + $a_msg_flags['depth'] = $header->depth; + else if ($header->has_children) + $roots[] = $header->uid; + if ($header->parent_uid) + $a_msg_flags['parent_uid'] = $header->parent_uid; + if ($header->has_children) + $a_msg_flags['has_children'] = $header->has_children; + if ($header->unread_children) + $a_msg_flags['unread_children'] = $header->unread_children; + if ($header->others['list-post']) + $a_msg_flags['ml'] = 1; + if ($header->priority) + $a_msg_flags['prio'] = (int) $header->priority; + + $a_msg_flags['ctype'] = Q($header->ctype); + $a_msg_flags['mbox'] = $mbox; + + // merge with plugin result (Deprecated, use $header->flags) + if (!empty($header->list_flags) && is_array($header->list_flags)) + $a_msg_flags = array_merge($a_msg_flags, $header->list_flags); + if (!empty($header->list_cols) && is_array($header->list_cols)) + $a_msg_cols = array_merge($a_msg_cols, $header->list_cols); + + $OUTPUT->command('add_message_row', + $header->uid, + $a_msg_cols, + $a_msg_flags, + $insert_top); + } + + if ($RCMAIL->storage->get_threading()) { + $OUTPUT->command('init_threads', (array) $roots, $mbox); + } +} + + +/* + * Creates <THEAD> for message list table + */ +function rcmail_message_list_head($attrib, $a_show_cols) +{ + global $RCMAIL; + + $skin_path = $_SESSION['skin_path']; + $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s")); + + // check to see if we have some settings for sorting + $sort_col = $_SESSION['sort_col']; + $sort_order = $_SESSION['sort_order']; + + $dont_override = (array)$RCMAIL->config->get('dont_override'); + $disabled_sort = in_array('message_sort_col', $dont_override); + $disabled_order = in_array('message_sort_order', $dont_override); + + $RCMAIL->output->set_env('disabled_sort_col', $disabled_sort); + $RCMAIL->output->set_env('disabled_sort_order', $disabled_order); + + // define sortable columns + if ($disabled_sort) + $a_sort_cols = $sort_col && !$disabled_order ? array($sort_col) : array(); + else + $a_sort_cols = array('subject', 'date', 'from', 'to', 'fromto', 'size', 'cc'); + + if (!empty($attrib['optionsmenuicon'])) { + $onclick = 'return ' . JS_OBJECT_NAME . ".command('menu-open', 'messagelistmenu')"; + if ($attrib['optionsmenuicon'] === true || $attrib['optionsmenuicon'] == 'true') + $list_menu = html::div(array('onclick' => $onclick, 'class' => 'listmenu', + 'id' => 'listmenulink', 'title' => rcube_label('listoptions'))); + else + $list_menu = html::a(array('href' => '#', 'onclick' => $onclick), + html::img(array('src' => $skin_path . $attrib['optionsmenuicon'], + 'id' => 'listmenulink', 'title' => rcube_label('listoptions'))) + ); + } + else + $list_menu = ''; + + $cells = array(); + + // get name of smart From/To column in folder context + if (($f = array_search('fromto', $a_show_cols)) !== false) { + $smart_col = rcmail_message_list_smart_column_name(); + } + + foreach ($a_show_cols as $col) { + // get column name + switch ($col) { + case 'flag': + $col_name = '<span class="flagged"> </span>'; + break; + case 'attachment': + case 'priority': + case 'status': + $col_name = '<span class="' . $col .'"> </span>'; + break; + case 'threads': + $col_name = $list_menu; + break; + case 'fromto': + $col_name = Q(rcube_label($smart_col)); + break; + default: + $col_name = Q(rcube_label($col)); + } + + // make sort links + if (in_array($col, $a_sort_cols)) + $col_name = html::a(array('href'=>"./#sort", 'onclick' => 'return '.JS_OBJECT_NAME.".command('sort','".$col."',this)", 'title' => rcube_label('sortby')), $col_name); + else if ($col_name[0] != '<') + $col_name = '<span class="' . $col .'">' . $col_name . '</span>'; + + $sort_class = $col == $sort_col && !$disabled_order ? " sorted$sort_order" : ''; + $class_name = $col.$sort_class; + + // put it all together + $cells[] = array('className' => $class_name, 'id' => "rcm$col", 'html' => $col_name); + } + + return $cells; +} + + +/** + * return an HTML iframe for loading mail content + */ +function rcmail_messagecontent_frame($attrib) +{ + global $OUTPUT, $RCMAIL; + + if (empty($attrib['id'])) + $attrib['id'] = 'rcmailcontentwindow'; + + $attrib['name'] = $attrib['id']; + + if ($RCMAIL->config->get('preview_pane')) + $OUTPUT->set_env('contentframe', $attrib['id']); + $OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/resources/blank.gif'); + + return $OUTPUT->frame($attrib, true); +} + + +function rcmail_messagecount_display($attrib) +{ + global $RCMAIL; + + if (!$attrib['id']) + $attrib['id'] = 'rcmcountdisplay'; + + $RCMAIL->output->add_gui_object('countdisplay', $attrib['id']); + + $content = $RCMAIL->action != 'show' ? rcmail_get_messagecount_text() : rcube_label('loading'); + + return html::span($attrib, $content); +} + + +function rcmail_get_messagecount_text($count=NULL, $page=NULL) +{ + global $RCMAIL; + + if ($page === NULL) { + $page = $RCMAIL->storage->get_page(); + } + + $page_size = $RCMAIL->storage->get_pagesize(); + $start_msg = ($page-1) * $page_size + 1; + + if ($count!==NULL) + $max = $count; + else if ($RCMAIL->action) + $max = $RCMAIL->storage->count(NULL, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL'); + + if ($max==0) + $out = rcube_label('mailboxempty'); + else + $out = rcube_label(array('name' => $RCMAIL->storage->get_threading() ? 'threadsfromto' : 'messagesfromto', + 'vars' => array('from' => $start_msg, + 'to' => min($max, $start_msg + $page_size - 1), + 'count' => $max))); + + return Q($out); +} + + +function rcmail_mailbox_name_display($attrib) +{ + global $RCMAIL; + + if (!$attrib['id']) + $attrib['id'] = 'rcmmailboxname'; + + $RCMAIL->output->add_gui_object('mailboxname', $attrib['id']); + + return html::span($attrib, rcmail_get_mailbox_name_text()); +} + + +function rcmail_get_mailbox_name_text() +{ + global $RCMAIL; + return rcmail_localize_foldername($RCMAIL->storage->get_folder()); +} + + +function rcmail_send_unread_count($mbox_name, $force=false, $count=null, $mark='') +{ + global $RCMAIL; + + $old_unseen = rcmail_get_unseen_count($mbox_name); + + if ($count === null) + $unseen = $RCMAIL->storage->count($mbox_name, 'UNSEEN', $force); + else + $unseen = $count; + + if ($unseen != $old_unseen || ($mbox_name == 'INBOX')) + $RCMAIL->output->command('set_unread_count', $mbox_name, $unseen, + ($mbox_name == 'INBOX'), $unseen && $mark ? $mark : ''); + + rcmail_set_unseen_count($mbox_name, $unseen); + + return $unseen; +} + + +function rcmail_set_unseen_count($mbox_name, $count) +{ + // @TODO: this data is doubled (session and cache tables) if caching is enabled + + // Make sure we have an array here (#1487066) + if (!is_array($_SESSION['unseen_count'])) + $_SESSION['unseen_count'] = array(); + + $_SESSION['unseen_count'][$mbox_name] = $count; +} + + +function rcmail_get_unseen_count($mbox_name) +{ + if (is_array($_SESSION['unseen_count']) && array_key_exists($mbox_name, $_SESSION['unseen_count'])) + return $_SESSION['unseen_count'][$mbox_name]; + else + return null; +} + + +/** + * Sets message is_safe flag according to 'show_images' option value + * + * @param object rcube_message Message + */ +function rcmail_check_safe(&$message) +{ + global $RCMAIL; + + if (!$message->is_safe + && ($show_images = $RCMAIL->config->get('show_images')) + && $message->has_html_part() + ) { + switch ($show_images) { + case 1: // known senders only + // get default addressbook, like in addcontact.inc + $CONTACTS = $RCMAIL->get_address_book(-1, true); + + if ($CONTACTS) { + $result = $CONTACTS->search('email', $message->sender['mailto'], 1, false); + if ($result->count) { + $message->set_safe(true); + } + } + break; + + case 2: // always + $message->set_safe(true); + break; + } + } +} + + +/** + * Cleans up the given message HTML Body (for displaying) + * + * @param string HTML + * @param array Display parameters + * @param array CID map replaces (inline images) + * @return string Clean HTML + */ +function rcmail_wash_html($html, $p, $cid_replaces) +{ + global $REMOTE_OBJECTS; + + $p += array('safe' => false, 'inline_html' => true); + + // charset was converted to UTF-8 in rcube_storage::get_message_part(), + // change/add charset specification in HTML accordingly, + // washtml cannot work without that + $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />'; + + // remove old meta tag and add the new one, making sure + // that it is placed in the head (#1488093) + $html = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $html); + $html = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $html, -1, $rcount); + if (!$rcount) { + $html = '<head>' . $meta . '</head>' . $html; + } + + // clean HTML with washhtml by Frederic Motte + $wash_opts = array( + 'show_washed' => false, + 'allow_remote' => $p['safe'], + 'blocked_src' => "./program/resources/blocked.gif", + 'charset' => RCMAIL_CHARSET, + 'cid_map' => $cid_replaces, + 'html_elements' => array('body'), + ); + + if (!$p['inline_html']) { + $wash_opts['html_elements'] = array('html','head','title','body'); + } + if ($p['safe']) { + $wash_opts['html_elements'][] = 'link'; + $wash_opts['html_attribs'] = array('rel','type'); + } + + // overwrite washer options with options from plugins + if (isset($p['html_elements'])) + $wash_opts['html_elements'] = $p['html_elements']; + if (isset($p['html_attribs'])) + $wash_opts['html_attribs'] = $p['html_attribs']; + + // initialize HTML washer + $washer = new rcube_washtml($wash_opts); + + if (!$p['skip_washer_form_callback']) + $washer->add_callback('form', 'rcmail_washtml_callback'); + + // allow CSS styles, will be sanitized by rcmail_washtml_callback() + if (!$p['skip_washer_style_callback']) + $washer->add_callback('style', 'rcmail_washtml_callback'); + + // Remove non-UTF8 characters (#1487813) + $html = rc_utf8_clean($html); + + $html = $washer->wash($html); + $REMOTE_OBJECTS = $washer->extlinks; + + return $html; +} + + +/** + * Convert the given message part to proper HTML + * which can be displayed the message view + * + * @param object rcube_message_part Message part + * @param array Display parameters array + * @return string Formatted HTML string + */ +function rcmail_print_body($part, $p = array()) +{ + global $RCMAIL; + + // trigger plugin hook + $data = $RCMAIL->plugins->exec_hook('message_part_before', + array('type' => $part->ctype_secondary, 'body' => $part->body, 'id' => $part->mime_id) + + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); + + // convert html to text/plain + if ($data['type'] == 'html' && $data['plain']) { + $txt = new rcube_html2text($data['body'], false, true); + $body = $txt->get_text(); + $part->ctype_secondary = 'plain'; + } + // text/html + else if ($data['type'] == 'html') { + $body = rcmail_wash_html($data['body'], $data, $part->replaces); + $part->ctype_secondary = $data['type']; + } + // text/enriched + else if ($data['type'] == 'enriched') { + $body = rcube_enriched::to_html($data['body']); + $body = rcmail_wash_html($body, $data, $part->replaces); + $part->ctype_secondary = 'html'; + } + else { + // assert plaintext + $body = $part->body; + $part->ctype_secondary = $data['type'] = 'plain'; + } + + // free some memory (hopefully) + unset($data['body']); + + // plaintext postprocessing + if ($part->ctype_secondary == 'plain') + $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); + + // allow post-processing of the message body + $data = $RCMAIL->plugins->exec_hook('message_part_after', + array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $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 + * @param boolean Text uses format=flowed + * + * @return string Formatted HTML string + */ +function rcmail_plain_body($body, $flowed=false) +{ + global $RCMAIL; + + // make links and email-addresses clickable + $replacer = new rcmail_string_replacer; + + // search for patterns like links and e-mail addresses and replace with tokens + $body = $replacer->replace($body); + + // split body into single lines + $body = preg_split('/\r?\n/', $body); + $quote_level = 0; + $last = -1; + + // find/mark quoted lines... + for ($n=0, $cnt=count($body); $n < $cnt; $n++) { + if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) { + $q = substr_count($regs[0], '>'); + $body[$n] = substr($body[$n], strlen($regs[0])); + + if ($q > $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; + } + else if ($q < $quote_level) { + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; + } + else if ($flowed) { + // previous line is flowed + if (isset($body[$last]) && $body[$n] + && $body[$last][strlen($body[$last])-1] == ' ') { + // merge lines + $body[$last] .= $body[$n]; + unset($body[$n]); + } + else { + $last = $n; + } + } + } + else { + $q = 0; + if ($flowed) { + // sig separator - line is fixed + if ($body[$n] == '-- ') { + $last = $last_sig = $n; + } + else { + // remove space-stuffing + if ($body[$n][0] == ' ') + $body[$n] = substr($body[$n], 1); + + // previous line is flowed? + if (isset($body[$last]) && $body[$n] + && $last !== $last_sig + && $body[$last][strlen($body[$last])-1] == ' ' + ) { + $body[$last] .= $body[$n]; + unset($body[$n]); + } + else { + $last = $n; + } + } + if ($quote_level > 0) + $body[$last] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$last]; + } + else if ($quote_level > 0) + $body[$n] = $replacer->get_replacement($replacer->add( + str_repeat('</blockquote>', $quote_level))) . $body[$n]; + } + + $quote_level = $q; + } + + $body = join("\n", $body); + + // quote plain text (don't use Q() here, to display entities "as is") + $table = get_html_translation_table(HTML_SPECIALCHARS); + unset($table['?']); + $body = strtr($body, $table); + + // colorize signature (up to <sig_max_lines> lines) + $len = strlen($body); + $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); + while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { + if ($sp == 0 || $body[$sp-1] == "\n") { + // do not touch blocks with more that X lines + if (substr_count($body, "\n", $sp) < $sig_max_lines) + $body = substr($body, 0, max(0, $sp)) + .'<span class="sig">'.substr($body, $sp).'</span>'; + break; + } + } + + // insert url/mailto links and citation tags + $body = $replacer->resolve($body); + + return $body; +} + + +/** + * Callback function for washtml cleaning class + */ +function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) +{ + switch ($tagname) { + case 'form': + $out = html::div('form', $content); + break; + + case 'style': + // decode all escaped entities and reduce to ascii strings + $stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcmail_xss_entity_decode($content)); + + // now check for evil strings like expression, behavior or url() + if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) { + if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url(')) + $washtml->extlinks = true; + else + $out = html::tag('style', array('type' => 'text/css'), $content); + break; + } + + default: + $out = ''; + } + + return $out; +} + + +/** + * return table with message headers + */ +function rcmail_message_headers($attrib, $headers=null) + { + global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL; + static $sa_attrib; + + // keep header table attrib + if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) + $sa_attrib = $attrib; + else if (!is_array($attrib) && is_array($sa_attrib)) + $attrib = $sa_attrib; + + if (!isset($MESSAGE)) + return FALSE; + + // get associative array of headers object + if (!$headers) { + $headers_obj = $MESSAGE->headers; + $headers = get_object_vars($MESSAGE->headers); + } + else if (is_object($headers)) { + $headers_obj = $headers; + $headers = get_object_vars($headers_obj); + } + else { + $headers_obj = rcube_message_header::from_array($headers); + } + + // show these headers + $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto', + 'mail-reply-to', 'mail-followup-to', 'date', 'priority'); + $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array(); + $output_headers = array(); + + foreach ($standard_headers as $hkey) { + $ishtml = false; + + if ($headers[$hkey]) + $value = $headers[$hkey]; + else if ($headers['others'][$hkey]) + $value = $headers['others'][$hkey]; + else + continue; + + if (in_array($hkey, $exclude_headers)) + continue; + + $header_title = rcube_label(preg_replace('/(^mail-|-)/', '', $hkey)); + + if ($hkey == 'date') { + if ($PRINT_MODE) + $header_value = format_date($value, $RCMAIL->config->get('date_long', 'x')); + else + $header_value = format_date($value); + } + else if ($hkey == 'priority') { + if ($value) { + $header_value = html::span('prio' . $value, rcmail_localized_priority($value)); + } + else + continue; + } + else if ($hkey == 'replyto') { + if ($headers['replyto'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'mail-reply-to') { + if ($headers['mail-replyto'] != $headers['reply-to'] + && $headers['reply-to'] != $headers['from'] + ) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'sender') { + if ($headers['sender'] != $headers['from']) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else + continue; + } + else if ($hkey == 'mail-followup-to') { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) { + $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); + $ishtml = true; + } + else if ($hkey == 'subject' && empty($value)) + $header_value = rcube_label('nosubject'); + else + $header_value = trim(rcube_mime::decode_header($value, $headers['charset'])); + + $output_headers[$hkey] = array( + 'title' => $header_title, + 'value' => $header_value, + 'raw' => $value, + 'html' => $ishtml, + ); + } + + $plugin = $RCMAIL->plugins->exec_hook('message_headers_output', + array('output' => $output_headers, 'headers' => $headers_obj, 'exclude' => $exclude_headers)); + + // single header value is requested + if (!empty($attrib['valueof'])) + return Q($plugin['output'][$attrib['valueof']]['value'], ($attrib['valueof'] == 'subject' ? 'strict' : 'show')); + + // compose html table + $table = new html_table(array('cols' => 2)); + + foreach ($plugin['output'] as $hkey => $row) { + $table->add(array('class' => 'header-title'), Q($row['title'])); + $table->add(array('class' => 'header '.$hkey), $row['html'] ? $row['value'] : Q($row['value'], ($hkey == 'subject' ? 'strict' : 'show'))); + } + + return $table->show($attrib); +} + +/** + * Convert Priority header value into a localized string + */ +function rcmail_localized_priority($value) +{ + $labels_map = array( + '1' => 'highest', + '2' => 'high', + '3' => 'normal', + '4' => 'low', + '5' => 'lowest', + ); + + if ($value && $labels_map[$value]) + return rcube_label($labels_map[$value]); + + return ''; +} + +/** + * return block to show full message headers + */ +function rcmail_message_full_headers($attrib, $headers=NULL) +{ + 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)", 'title' => rcube_label('togglefullheaders')), ''); + + $OUTPUT->add_gui_object('all_headers_row', 'all-headers'); + $OUTPUT->add_gui_object('all_headers_box', 'headers-source'); + + return html::div($attrib, $html); +} + + +/** + * Handler for the 'messagebody' GUI object + * + * @param array Named parameters + * @return string HTML content showing the message body + */ +function rcmail_message_body($attrib) +{ + global $CONFIG, $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS; + + if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) + return ''; + + if (!$attrib['id']) + $attrib['id'] = 'rcmailMsgBody'; + + $safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']); + $out = ''; + + $header_attrib = array(); + foreach ($attrib as $attr => $value) + if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) + $header_attrib[$regs[1]] = $value; + + if (!empty($MESSAGE->parts)) { + foreach ($MESSAGE->parts as $i => $part) { + if ($part->type == 'headers') { + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); + } + else if ($part->type == 'content') { + // unsapported + if ($part->realtype) { + if ($part->realtype == 'multipart/encrypted') { + $out .= html::span('part-notice', rcube_label('encryptedmessage')); + } + continue; + } + else if (!$part->size) { + continue; + } + // Check if we have enough memory to handle the message in it + // #1487424: we need up to 10x more memory than the body + else if (!rcmail_mem_check($part->size * 10)) { + $out .= html::span('part-notice', rcube_label('messagetoobig'). ' ' + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id + .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), rcube_label('download'))); + continue; + } + + if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) + $part->ctype_parameters['charset'] = $MESSAGE->headers->charset; + + // fetch part if not available + if (!isset($part->body)) + $part->body = $MESSAGE->get_part_content($part->mime_id); + + // extract headers from message/rfc822 parts + if ($part->mimetype == 'message/rfc822') { + $msgpart = rcube_mime::parse_message($part->body); + if (!empty($msgpart->headers)) { + $part = $msgpart; + $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); + } + } + + // message is cached but not exists (#1485443), or other error + if ($part->body === false) { + rcmail_message_error($MESSAGE->uid); + } + + $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array( + 'part' => $part, 'prefix' => '')); + + $body = rcmail_print_body($part, array('safe' => $safe_mode, 'plain' => !$CONFIG['prefer_html'])); + + if ($part->ctype_secondary == 'html') { + $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); + $div_attr = array('class' => 'message-htmlpart'); + $style = array(); + + if (!empty($attrs)) { + foreach ($attrs as $a_idx => $a_val) + $style[] = $a_idx . ': ' . $a_val; + if (!empty($style)) + $div_attr['style'] = implode('; ', $style); + } + + $out .= html::div($div_attr, $plugin['prefix'] . $body); + } + else + $out .= html::div('message-part', $plugin['prefix'] . $body); + } + } + } + else { + // Check if we have enough memory to handle the message in it + // #1487424: we need up to 10x more memory than the body + if (!rcmail_mem_check(strlen($MESSAGE->body) * 10)) { + $out .= html::span('part-notice', rcube_label('messagetoobig'). ' ' + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0' + .'&_mbox='. urlencode($RCMAIL->storage->get_folder()), rcube_label('download'))); + } + else { + $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', array( + 'part' => $MESSAGE, 'prefix' => '')); + + $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(), + rcmail_plain_body(Q($MESSAGE->body, 'strict', false)))); + } + } + + // list images after mail body + if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) { + $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240); + $client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); + + foreach ($MESSAGE->attachments as $attach_prop) { + // skip inline images + if ($attach_prop->content_id && $attach_prop->disposition == 'inline') { + continue; + } + + // Content-Type: image/*... + if ($mimetype = rcmail_part_image_type($attach_prop)) { + // display thumbnails + if ($thumbnail_size) { + $show_link = array( + 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), + 'onclick' => sprintf( + 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', + JS_OBJECT_NAME, + $attach_prop->mime_id, + $mimetype) + ); + $out .= html::p('image-attachment', + html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)), + html::img(array( + 'class' => 'image-thumbnail', + 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true) . '&_thumb=1', + 'title' => $attach_prop->filename, + 'alt' => $attach_prop->filename, + 'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size), + )) + ) . + html::span('image-filename', Q($attach_prop->filename)) . + html::span('image-filesize', Q($RCMAIL->message_part_size($attach_prop))) . + html::span('attachment-links', + (in_array($mimetype, $client_mimetypes) ? html::a($show_link, rcube_label('showattachment')) . ' ' : '') . + html::a($show_link['href'] . '&_download=1', rcube_label('download')) + ) . + html::br(array('style' => 'clear:both')) + ); + } + else { + $out .= html::tag('fieldset', 'image-attachment', + html::tag('legend', 'image-filename', Q($attach_prop->filename)) . + html::p(array('align' => "center"), + html::img(array( + 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true), + 'title' => $attach_prop->filename, + 'alt' => $attach_prop->filename, + ))) + ); + } + } + } + } + + // tell client that there are blocked remote objects + if ($REMOTE_OBJECTS && !$safe_mode) + $OUTPUT->set_env('blockedobjects', true); + + return html::div($attrib, $out); +} + +function rcmail_part_image_type($part) +{ + $rcmail = rcmail::get_instance(); + + // Skip TIFF images if browser doesn't support this format... + $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']); + // until we can convert them to JPEG + $tiff_support = $tiff_support || $rcmail->config->get('im_convert_path'); + + // Content-type regexp + $mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i'; + + // Content-Type: image/*... + if (preg_match($mime_regex, $part->mimetype)) { + return rcmail_fix_mimetype($part->mimetype); + } + + // Many clients use application/octet-stream, we'll detect mimetype + // by checking filename extension + + // Supported image filename extensions to image type map + $types = array( + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'png' => 'image/png', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + ); + if ($tiff_support) { + $types['tif'] = 'image/tiff'; + $types['tiff'] = 'image/tiff'; + } + + if ($part->filename + && preg_match('/^application\/octet-stream$/i', $part->mimetype) + && preg_match('/\.([^.]+)$/i', $part->filename, $m) + && ($extension = strtolower($m[1])) + && isset($types[$extension]) + ) { + return $types[$extension]; + } +} + + +/** + * modify a HTML message that it can be displayed inside a HTML page + */ +function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false) +{ + $last_style_pos = 0; + $cont_id = $container_id.($body_id ? ' div.'.$body_id : ''); + + // find STYLE tags + while (($pos = stripos($body, '<style', $last_style_pos)) && ($pos2 = stripos($body, '</style>', $pos))) + { + $pos = strpos($body, '>', $pos) + 1; + $len = $pos2 - $pos; + + // replace all css definitions with #container [def] + $styles = substr($body, $pos, $len); + $styles = rcmail_mod_css_styles($styles, $cont_id, $allow_remote); + + $body = substr_replace($body, $styles, $pos, $len); + $last_style_pos = $pos2 + strlen($styles) - $len; + } + + // modify HTML links to open a new window if clicked + $GLOBALS['rcmail_html_container_id'] = $container_id; + $body = preg_replace_callback('/<(a|link|area)\s+([^>]+)>/Ui', 'rcmail_alter_html_link', $body); + unset($GLOBALS['rcmail_html_container_id']); + + $body = preg_replace(array( + // add comments arround html and other tags + '/(<!DOCTYPE[^>]*>)/i', + '/(<\?xml[^>]*>)/i', + '/(<\/?html[^>]*>)/i', + '/(<\/?head[^>]*>)/i', + '/(<title[^>]*>.*<\/title>)/Ui', + '/(<\/?meta[^>]*>)/i', + // quote <? of php and xml files that are specified as text/html + '/<\?/', + '/\?>/', + // replace <body> with <div> + '/<body([^>]*)>/i', + '/<\/body>/i', + ), + array( + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<!--\\1-->', + '<?', + '?>', + '<div class="'.$body_id.'"\\1>', + '</div>', + ), + $body); + + $attributes = array(); + + // Handle body attributes that doesn't play nicely with div elements + $regexp = '/<div class="' . preg_quote($body_id, '/') . '"([^>]*)/'; + if (preg_match($regexp, $body, $m)) { + $attrs = $m[0]; + // Get bgcolor, we'll set it as background-color of the message container + if ($m[1] && preg_match('/bgcolor=["\']*([a-z0-9#]+)["\']*/', $attrs, $mb)) { + $attributes['background-color'] = $mb[1]; + $attrs = preg_replace('/bgcolor=["\']*([a-z0-9#]+)["\']*/', '', $attrs); + } + // Get background, we'll set it as background-image of the message container + if ($m[1] && preg_match('/background=["\']*([^"\'>\s]+)["\']*/', $attrs, $mb)) { + $attributes['background-image'] = 'url('.$mb[1].')'; + $attrs = preg_replace('/background=["\']*([^"\'>\s]+)["\']*/', '', $attrs); + } + if (!empty($attributes)) { + $body = preg_replace($regexp, rtrim($attrs), $body, 1); + } + + // handle body styles related to background image + if ($attributes['background-image']) { + // get body style + if (preg_match('/#'.preg_quote($cont_id, '/').'\s+\{([^}]+)}/i', $body, $m)) { + // get background related style + if (preg_match_all('/(background-position|background-repeat)\s*:\s*([^;]+);/i', $m[1], $ma, PREG_SET_ORDER)) { + foreach ($ma as $style) + $attributes[$style[1]] = $style[2]; + } + } + } + } + // make sure there's 'rcmBody' div, we need it for proper css modification + // its name is hardcoded in rcmail_message_body() also + else { + $body = '<div class="' . $body_id . '">' . $body . '</div>'; + } + + return $body; +} + + +/** + * parse link attributes and set correct target + */ +function rcmail_alter_html_link($matches) +{ + global $RCMAIL; + + // Support unicode/punycode in top-level domain part + $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))'; + + $tag = $matches[1]; + $attrib = parse_attrib_string($matches[2]); + $end = '>'; + + // Remove non-printable characters in URL (#1487805) + if ($attrib['href']) + $attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']); + + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) { + $tempurl = 'tmp-' . md5($attrib['href']) . '.css'; + $_SESSION['modcssurls'][$tempurl] = $attrib['href']; + $attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id'])); + $end = ' />'; + } + else if (preg_match('/^mailto:'.$EMAIL_PATTERN.'(\?[^"\'>]+)?/i', $attrib['href'], $mailto)) { + $attrib['href'] = $mailto[0]; + $attrib['onclick'] = sprintf( + "return %s.command('compose','%s',this)", + JS_OBJECT_NAME, + JQ($mailto[1].$mailto[3])); + } + else if (empty($attrib['href']) && !$attrib['name']) { + $attrib['href'] = './#NOP'; + $attrib['onclick'] = 'return false'; + } + else if (!empty($attrib['href']) && $attrib['href'][0] != '#') { + $attrib['target'] = '_blank'; + } + + // allowed attributes for a|link|area tags + $allow = array('href','name','target','onclick','id','class','style','title', + 'rel','type','media','alt','coords','nohref','hreflang','shape'); + + return "<$tag" . html::attrib_string($attrib, $allow) . $end; +} + + +/** + * decode address string and re-format it as HTML links + */ +function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $default_charset=null, $title=null) +{ + global $RCMAIL, $PRINT_MODE, $CONFIG; + + $a_parts = rcube_mime::decode_address_list($input, null, true, $default_charset); + + if (!sizeof($a_parts)) + return $input; + + $c = count($a_parts); + $j = 0; + $out = ''; + $allvalues = array(); + + if ($addicon && !isset($_SESSION['writeable_abook'])) { + $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; + } + + foreach ($a_parts as $part) { + $j++; + $name = $part['name']; + $mailto = $part['mailto']; + $string = $part['string']; + + // IDNA ASCII to Unicode + if ($name == $mailto) + $name = rcube_idn_to_utf8($name); + if ($string == $mailto) + $string = rcube_idn_to_utf8($string); + $mailto = rcube_idn_to_utf8($mailto); + + if ($PRINT_MODE) { + $out .= ($out ? ', ' : '') . sprintf('%s <%s>', Q($name), $mailto); + // for printing we display all addresses + continue; + } + else if (check_email($part['mailto'], false)) { + if ($linked) { + $address = html::a(array( + 'href' => 'mailto:'.$mailto, + 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), + 'title' => $mailto, + 'class' => "rcmContactAddress", + ), + Q($name ? $name : $mailto)); + } + else { + $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), + Q($name ? $name : $mailto)); + } + + if ($addicon && $_SESSION['writeable_abook']) { + $address .= html::a(array( + 'href' => "#add", + 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, JQ($string)), + 'title' => rcube_label('addtoaddressbook'), + 'class' => 'rcmaddcontact', + ), + html::img(array( + 'src' => $CONFIG['skin_path'] . $addicon, + 'alt' => "Add contact", + ))); + } + } + else { + $address = ''; + if ($name) + $address .= Q($name); + if ($mailto) + $address .= (strlen($address) ? ' ' : '') . sprintf('<%s>', Q($mailto)); + } + + $address = html::span('adr', $address); + $allvalues[] = $address; + + if (!$moreadrs) + $out .= ($out ? ', ' : '') . $address; + + if ($max && $j == $max && $c > $j) { + if ($linked) { + $moreadrs = $c - $j; + } + else { + $out .= '...'; + break; + } + } + } + + if ($moreadrs) { + $out .= ' ' . html::a(array( + 'href' => '#more', + 'class' => 'morelink', + 'onclick' => sprintf("return %s.show_popup_dialog('%s','%s')", + JS_OBJECT_NAME, + JQ(join(', ', $allvalues)), + JQ($title)) + ), + Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))); + } + + return $out; +} + + +/** + * Wrap text to a given number of characters per line + * but respect the mail quotation of replies messages (>). + * Finally add another quotation level by prpending the lines + * with > + * + * @param string Text to wrap + * @param int The line width + * @return string The wrapped text + */ +function rcmail_wrap_and_quote($text, $length = 72) +{ + // Rebuild the message body with a maximum of $max chars, while keeping quoted message. + $max = max(75, $length + 8); + $lines = preg_split('/\r?\n/', trim($text)); + $out = ''; + + foreach ($lines as $line) { + // don't wrap already quoted lines + if ($line[0] == '>') + $line = '>' . rtrim($line); + else if (mb_strlen($line) > $max) { + $newline = ''; + foreach(explode("\n", rc_wordwrap($line, $length - 2)) as $l) { + if (strlen($l)) + $newline .= '> ' . $l . "\n"; + else + $newline .= ">\n"; + } + $line = rtrim($newline); + } + else + $line = '> ' . $line; + + // Append the line + $out .= $line . "\n"; + } + + return rtrim($out, "\n"); +} + + +function rcmail_draftinfo_encode($p) +{ + $parts = array(); + foreach ($p as $key => $val) + $parts[] = $key . '=' . ($key == 'folder' ? base64_encode($val) : $val); + + return join('; ', $parts); +} + + +function rcmail_draftinfo_decode($str) +{ + $info = array(); + foreach (preg_split('/;\s+/', $str) as $part) { + list($key, $val) = explode('=', $part, 2); + if ($key == 'folder') + $val = base64_decode($val); + $info[$key] = $val; + } + + return $info; +} + + +function rcmail_message_part_controls($attrib) +{ + global $MESSAGE, $RCMAIL; + + $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC)); + if (!is_object($MESSAGE) || !is_array($MESSAGE->parts) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE->mime_parts[$part]) + return ''; + + $part = $MESSAGE->mime_parts[$part]; + $table = new html_table(array('cols' => 3)); + + $filename = $part->filename; + if (empty($filename) && $attach_prop->mimetype == 'text/html') { + $filename = rcube_label('htmlmessage'); + } + + if (!empty($filename)) { + $table->add('title', Q(rcube_label('filename'))); + $table->add('header', Q($filename)); + $table->add('download-link', html::a(array('href' => './?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING'])), Q(rcube_label('download')))); + } + + $table->add('title', Q(rcube_label('filesize'))); + $table->add('header', Q($RCMAIL->message_part_size($part))); + + return $table->show($attrib); +} + + + +function rcmail_message_part_frame($attrib) +{ + global $MESSAGE; + + $part = $MESSAGE->mime_parts[asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))]; + $ctype_primary = strtolower($part->ctype_primary); + + $attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary=='text' ? '_embed=' : '_preload='), $_SERVER['QUERY_STRING']); + + return html::iframe($attrib); +} + + +/** + * clear message composing settings + */ +function rcmail_compose_cleanup($id) +{ + if (!isset($_SESSION['compose_data_'.$id])) + return; + + $rcmail = rcmail::get_instance(); + $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id)); + $rcmail->session->remove('compose_data_'.$id); +} + + +/** + * Send the MDN response + * + * @param mixed $message Original message object (rcube_message) or UID + * @param array $smtp_error SMTP error array (reference) + * + * @return boolean Send status + */ +function rcmail_send_mdn($message, &$smtp_error) +{ + global $RCMAIL; + + if (!is_object($message) || !is_a($message, 'rcube_message')) + $message = new rcube_message($message); + + if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && + ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))) + { + $identity = rcmail_identity_select($message); + $sender = format_email_recipient($identity['email'], $identity['name']); + $recipient = array_shift(rcube_mime::decode_address_list( + $message->headers->mdn_to, 1, true, $message->headers->charset)); + $mailto = $recipient['mailto']; + + $compose = new Mail_mime("\r\n"); + + $compose->setParam('text_encoding', 'quoted-printable'); + $compose->setParam('html_encoding', 'quoted-printable'); + $compose->setParam('head_encoding', 'quoted-printable'); + $compose->setParam('head_charset', RCMAIL_CHARSET); + $compose->setParam('html_charset', RCMAIL_CHARSET); + $compose->setParam('text_charset', RCMAIL_CHARSET); + + // compose headers array + $headers = array( + 'Date' => rcmail_user_date(), + 'From' => $sender, + 'To' => $message->headers->mdn_to, + 'Subject' => rcube_label('receiptread') . ': ' . $message->subject, + 'Message-ID' => rcmail_gen_message_id(), + 'X-Sender' => $identity['email'], + 'References' => trim($message->headers->references . ' ' . $message->headers->messageID), + ); + + if ($agent = $RCMAIL->config->get('useragent')) + $headers['User-Agent'] = $agent; + + $body = rcube_label("yourmessage") . "\r\n\r\n" . + "\t" . rcube_label("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" . + "\t" . rcube_label("subject") . ': ' . $message->subject . "\r\n" . + "\t" . rcube_label("sent") . ': ' . format_date($message->headers->date, $RCMAIL->config->get('date_long')) . "\r\n" . + "\r\n" . rcube_label("receiptnote") . "\r\n"; + + $ua = $RCMAIL->config->get('useragent', "Roundcube Webmail (Version ".RCMAIL_VERSION.")"); + $report = "Reporting-UA: $ua\r\n"; + + if ($message->headers->to) + $report .= "Original-Recipient: {$message->headers->to}\r\n"; + + $report .= "Final-Recipient: rfc822; {$identity['email']}\r\n" . + "Original-Message-ID: {$message->headers->messageID}\r\n" . + "Disposition: manual-action/MDN-sent-manually; displayed\r\n"; + + $compose->headers($headers); + $compose->setContentType('multipart/report', array('report-type'=> 'disposition-notification')); + $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, $smtp_error, $body_file); + + if ($sent) + { + $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); + return true; + } + } + + return false; +} + +/** + * Detect recipient identity from specified message + */ +function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'reply') +{ + $a_recipients = array(); + $a_names = array(); + + if ($identities === null) { + $identities = rcmail::get_instance()->user->list_identities(null, true); + } + + // extract all recipients of the reply-message + if (is_object($MESSAGE->headers) && in_array($compose_mode, array('reply', 'forward'))) { + $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); + foreach ($a_to as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + + if (!empty($MESSAGE->headers->cc)) { + $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); + foreach ($a_cc as $addr) { + if (!empty($addr['mailto'])) { + $a_recipients[] = format_email($addr['mailto']); + $a_names[] = $addr['name']; + } + } + } + } + + $from_idx = null; + $found_idx = null; + $default_identity = 0; // default identity is always first on the list + + // Select identity + foreach ($identities as $idx => $ident) { + // use From header + if (in_array($compose_mode, array('draft', 'edit'))) { + if ($MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + } + // reply to yourself + else if ($compose_mode == 'reply' && $MESSAGE->headers->from == $ident['ident']) { + $from_idx = $idx; + break; + } + // use replied message recipients + else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { + if ($found_idx === null) { + $found_idx = $idx; + } + // match identity name + if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { + $from_idx = $idx; + break; + } + } + } + + // If matching by name+address doesn't found any matches, get first found address (identity) + if ($from_idx === null) { + $from_idx = $found_idx; + } + + // Try Return-Path + if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { + foreach ($identities as $idx => $ident) { + if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { + $from_idx = $idx; + break; + } + } + } + + // Fallback using Delivered-To + if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$delivered_to)) { + $from_idx = $idx; + break; + } + } + } + + // Fallback using Envelope-To + if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { + foreach ($identities as $idx => $ident) { + if (in_array($ident['email_ascii'], (array)$envelope_to)) { + $from_idx = $idx; + break; + } + } + } + + return $identities[$from_idx !== null ? $from_idx : $default_identity]; +} + +// Fixes some content-type names +function rcmail_fix_mimetype($name) +{ + // Some versions of Outlook create garbage Content-Type: + // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608 + if (preg_match('/^application\/pdf.+/', $name)) + $name = 'application/pdf'; + + // treat image/pjpeg as image/jpeg + else if (preg_match('/^image\/p?jpe?g$/', $name)) + $name = 'image/jpeg'; + + return $name; +} + +<<<<<<< HEAD +// return attachment filename, handle empty filename case +function rcmail_attachment_name($attachment, $display = false) +{ + $filename = $attachment->filename; + + if ($filename === null || $filename === '') { + if ($attachment->mimetype == 'text/html') { + $filename = rcube_label('htmlmessage'); + } + else { + $ext = rcube_mime::get_mime_extensions($attachment->mimetype); + $ext = array_shift($ext); + $filename = rcube_label('messagepart') . ' ' . $attachment->mime_id; + if ($ext) { + $filename .= '.' . $ext; + } + } + } + + $filename = preg_replace('[\r\n]', '', $filename); + + // Display smart names for some known mimetypes + if ($display) { + if (preg_match('/application\/(pgp|pkcs7)-signature/i', $attachment->mimetype)) { + $filename = rcube_label('digitalsig'); + } + } + + return $filename; +} + +======= +>>>>>>> parent of be72fb3... Unified attachments filenames handling for message parts without a filename +function rcmail_search_filter($attrib) +{ + global $OUTPUT, $CONFIG; + + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmlistfilter'; + + $attrib['onchange'] = JS_OBJECT_NAME.'.filter_mailbox(this.value)'; + + /* + RFC3501 (6.4.4): 'ALL', 'RECENT', + 'ANSWERED', 'DELETED', 'FLAGGED', 'SEEN', + 'UNANSWERED', 'UNDELETED', 'UNFLAGGED', 'UNSEEN', + 'NEW', // = (RECENT UNSEEN) + 'OLD' // = NOT RECENT + */ + + $select_filter = new html_select($attrib); + $select_filter->add(rcube_label('all'), 'ALL'); + $select_filter->add(rcube_label('unread'), 'UNSEEN'); + $select_filter->add(rcube_label('flagged'), 'FLAGGED'); + $select_filter->add(rcube_label('unanswered'), 'UNANSWERED'); + if (!$CONFIG['skip_deleted']) { + $select_filter->add(rcube_label('deleted'), 'DELETED'); + $select_filter->add(rcube_label('undeleted'), 'UNDELETED'); + } + $select_filter->add(rcube_label('priority').': '.rcube_label('highest'), 'HEADER X-PRIORITY 1'); + $select_filter->add(rcube_label('priority').': '.rcube_label('high'), 'HEADER X-PRIORITY 2'); + $select_filter->add(rcube_label('priority').': '.rcube_label('normal'), 'NOT HEADER X-PRIORITY 1 NOT HEADER X-PRIORITY 2 NOT HEADER X-PRIORITY 4 NOT HEADER X-PRIORITY 5'); + $select_filter->add(rcube_label('priority').': '.rcube_label('low'), 'HEADER X-PRIORITY 4'); + $select_filter->add(rcube_label('priority').': '.rcube_label('lowest'), 'HEADER X-PRIORITY 5'); + + $out = $select_filter->show($_SESSION['search_filter']); + + $OUTPUT->add_gui_object('search_filter', $attrib['id']); + + return $out; +} + +function rcmail_message_error($uid=null) +{ + global $RCMAIL; + + // Set env variables for messageerror.html template + if ($RCMAIL->action == 'show') { + $mbox_name = $RCMAIL->storage->get_folder(); + $RCMAIL->output->set_env('mailbox', $mbox_name); + $RCMAIL->output->set_env('uid', null); + } + // display error message + $RCMAIL->output->show_message('messageopenerror', 'error'); + // ... display message error page + $RCMAIL->output->send('messageerror'); +} + +// register UI objects +$OUTPUT->add_handlers(array( + 'mailboxlist' => 'rcmail_mailbox_list', + 'messages' => 'rcmail_message_list', + 'messagecountdisplay' => 'rcmail_messagecount_display', + 'quotadisplay' => 'rcmail_quota_display', + 'mailboxname' => 'rcmail_mailbox_name_display', + 'messageheaders' => 'rcmail_message_headers', + 'messagefullheaders' => 'rcmail_message_full_headers', + 'messagebody' => 'rcmail_message_body', + 'messagecontentframe' => 'rcmail_messagecontent_frame', + 'messagepartframe' => 'rcmail_message_part_frame', + 'messagepartcontrols' => 'rcmail_message_part_controls', + 'searchfilter' => 'rcmail_search_filter', + 'searchform' => array($OUTPUT, 'search_form'), +)); + +// register action aliases +$RCMAIL->register_action_map(array( + 'refresh' => 'check_recent.inc', + 'preview' => 'show.inc', + 'print' => 'show.inc', + 'moveto' => 'move_del.inc', + 'delete' => 'move_del.inc', + 'send' => 'sendmail.inc', + 'expunge' => 'folders.inc', + 'purge' => 'folders.inc', + 'remove-attachment' => 'attachments.inc', + 'display-attachment' => 'attachments.inc', + 'upload' => 'attachments.inc', + 'group-expand' => 'autocomplete.inc', +)); diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index e0c4e2911..372757720 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -38,34 +38,19 @@ ob_end_clean(); // similar code as in program/steps/mail/show.inc if (!empty($_GET['_uid'])) { - $uid = get_input_value('_uid', RCUBE_INPUT_GET); $RCMAIL->config->set('prefer_html', true); - $MESSAGE = new rcube_message($uid); + $MESSAGE = new rcube_message(get_input_value('_uid', RCUBE_INPUT_GET)); } // check connection status check_storage_status(); -$part_id = get_input_value('_part', RCUBE_INPUT_GPC); - // show part page if (!empty($_GET['_frame'])) { - if ($part_id && ($part = $MESSAGE->mime_parts[$part_id])) { - $filename = rcmail_attachment_name($part); - $OUTPUT->set_pagetitle($filename); + if (($part_id = get_input_value('_part', RCUBE_INPUT_GPC)) && ($part = $MESSAGE->mime_parts[$part_id])) { + $OUTPUT->set_pagetitle(rcmail_attachment_name($part)); } - // register UI objects - $OUTPUT->add_handlers(array( - 'messagepartframe' => 'rcmail_message_part_frame', - 'messagepartcontrols' => 'rcmail_message_part_controls', - )); - - $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); - $OUTPUT->set_env('uid', $uid); - $OUTPUT->set_env('part', $part_id); - $OUTPUT->set_env('filename', $filename); - $OUTPUT->send('messagepart'); exit; } @@ -107,8 +92,9 @@ else if ($_GET['_thumb']) { exit; } -else if (strlen($part_id)) { - if ($part = $MESSAGE->mime_parts[$part_id]) { +else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) { + + if ($part = $MESSAGE->mime_parts[$pid]) { $mimetype = rcmail_fix_mimetype($part->mimetype); // allow post-processing of the message body @@ -134,7 +120,7 @@ else if (strlen($part_id)) { $valid = $file_extension && in_array($file_extension, (array)$extensions) || !empty($_REQUEST['_mimeclass']); // 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension - if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) { + if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || $mimetype == 'text/plain') { if ($part->body) // part body is already loaded $body = $part->body; else if ($part->size && $part->size < 1024*1024) // load the entire part if it's small enough @@ -189,8 +175,8 @@ else if (strlen($part_id)) { rcube_label(array( 'name' => 'attachmentvalidationerror', 'vars' => array( - 'expected' => $mimetype . ($file_extension ? " (.$file_extension)" : ''), - 'detected' => $real_mimetype . ($extensions[0] ? " (.$extensions[0])" : ''), + 'expected' => $mimetype . ($file_extension ? "(.$file_extension)" : ''), + 'detected' => $real_mimetype . ($extensions[0] ? "(.$extensions[0])" : ''), ) )) . html::p(array('class' => 'rcmail-inline-buttons'), @@ -233,6 +219,7 @@ else if (strlen($part_id)) { header("Content-Transfer-Encoding: binary"); } + // deliver part content if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($plugin['download'])) { // Check if we have enough memory to handle the message in it @@ -357,8 +344,7 @@ else if (strlen($part_id)) { header("Content-Length: $size"); } - // 8th argument disables re-formatting of text/* parts (#1489267) - $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, true, null, false, 0, false); + $sent = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, true); } } @@ -392,9 +378,7 @@ else { header('HTTP/1.1 404 Not Found'); exit; -/** - * Handles nicely storage connection errors - */ + function check_storage_status() { $error = rcmail::get_instance()->storage->get_error_code(); @@ -426,49 +410,3 @@ function check_storage_status() exit; } } - -/** - * Attachment properties table - */ -function rcmail_message_part_controls($attrib) -{ - global $MESSAGE, $RCMAIL; - - $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC)); - if (!is_object($MESSAGE) || !is_array($MESSAGE->parts) - || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE->mime_parts[$part] - ) { - return ''; - } - - $part = $MESSAGE->mime_parts[$part]; - $table = new html_table(array('cols' => 2)); - - $table->add('title', Q(rcube_label('namex')).':'); - $table->add('header', Q(rcmail_attachment_name($part))); - - $table->add('title', Q(rcube_label('type')).':'); - $table->add('header', Q($part->mimetype)); - - $table->add('title', Q(rcube_label('size')).':'); - $table->add('header', Q($RCMAIL->message_part_size($part))); - - return $table->show($attrib); -} - -/** - * Attachment preview frame - */ -function rcmail_message_part_frame($attrib) -{ - global $MESSAGE, $RCMAIL; - - $part = $MESSAGE->mime_parts[asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))]; - $ctype_primary = strtolower($part->ctype_primary); - - $attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary=='text' ? '_embed=' : '_preload='), $_SERVER['QUERY_STRING']); - - $RCMAIL->output->add_gui_object('messagepartframe', $attrib['id']); - - return html::iframe($attrib); -} diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index a2380131a..b8c3ee021 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -97,6 +97,7 @@ $OUTPUT->set_env('threading', $threading); $OUTPUT->set_env('current_page', $count ? $RCMAIL->storage->get_page() : 1); $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); +$OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text()); // add message rows rcmail_js_message_list($a_headers, FALSE, $cols); diff --git a/program/steps/mail/list_contacts.inc b/program/steps/mail/list_contacts.inc index dab146431..479c21422 100644 --- a/program/steps/mail/list_contacts.inc +++ b/program/steps/mail/list_contacts.inc @@ -73,11 +73,8 @@ else { $CONTACTS->set_pagesize($page_size); $CONTACTS->set_page($list_page); - if ($group_id = get_input_value('_gid', RCUBE_INPUT_GPC)) { - $CONTACTS->set_group($group_id); - } // list groups of this source (on page one) - else if ($CONTACTS->groups && $CONTACTS->list_page == 1) { + if ($CONTACTS->groups && $CONTACTS->list_page == 1) { foreach ($CONTACTS->list_groups() as $group) { $CONTACTS->reset(); $CONTACTS->set_group($group['ID']); @@ -92,19 +89,6 @@ else { 'contactgroup' => html::span(array('title' => $email), Q($group['name']))), 'group'); } } - // make virtual groups clickable to list their members - else if ($group_prop['virtual']) { - $row_id = 'G'.$group['ID']; - $OUTPUT->command('add_contact_row', $row_id, array( - 'contactgroup' => html::a(array( - 'href' => '#list', - 'rel' => $row['ID'], - 'title' => rcube_label('listgroup'), - 'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)", JS_OBJECT_NAME, $source, $group['ID']), - ), Q($group['name']) . ' ' . html::span('action', '»'))), - 'group', - array('ID' => $group['ID'], 'name' => $group['name'], 'virtual' => true)); - } // show group with count else if (($result = $CONTACTS->count()) && $result->count) { $row_id = 'E'.$group['ID']; @@ -113,12 +97,10 @@ else { 'contactgroup' => Q($group['name'] . ' (' . intval($result->count) . ')')), 'group'); } } - - $CONTACTS->reset(); - $CONTACTS->set_group(0); } // get contacts for this user + $CONTACTS->set_group(0); $result = $CONTACTS->list_records($afields); } } @@ -136,13 +118,10 @@ else if (!empty($result) && $result->count > 0) { foreach ($emails as $i => $email) { $row_id = $row['ID'].$i; $jsresult[$row_id] = format_email_recipient($email, $name); - $classname = $row['_type'] == 'group' ? 'group' : 'person'; - $keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact'; - $OUTPUT->command('add_contact_row', $row_id, array( - $keyname => html::span(array('title' => $email), Q($name ? $name : $email) . + 'contact' => html::span(array('title' => $email), Q($name ? $name : $email) . ($name && count($emails) > 1 ? ' ' . html::span('email', Q($email)) : '') - )), $classname); + )), 'person'); } } } diff --git a/program/steps/mail/move_del.inc b/program/steps/mail/move_del.inc index f15cd2460..37157b71f 100644 --- a/program/steps/mail/move_del.inc +++ b/program/steps/mail/move_del.inc @@ -29,11 +29,10 @@ $old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); $old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize()); // move messages -if ($RCMAIL->action == 'move' && !empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) { - $count = sizeof(explode(',', ($uids = get_input_value('_uid', RCUBE_INPUT_POST)))); +if ($RCMAIL->action=='moveto' && !empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) { + $count = sizeof(explode(',', ($uids = get_input_value('_uid', RCUBE_INPUT_POST)))); $target = get_input_value('_target_mbox', RCUBE_INPUT_POST, true); - $mbox = get_input_value('_mbox', RCUBE_INPUT_POST, true); - $trash = $RCMAIL->config->get('trash_mbox'); + $mbox = get_input_value('_mbox', RCUBE_INPUT_POST, true); $moved = $RCMAIL->storage->move_message($uids, $target, $mbox); @@ -41,7 +40,7 @@ if ($RCMAIL->action == 'move' && !empty($_POST['_uid']) && strlen($_POST['_targe // send error message if ($_POST['_from'] != 'show') $OUTPUT->command('list_mailbox'); - rcmail_display_server_error('errormoving', null, $target == $trash ? 'delete' : ''); + rcmail_display_server_error('errormoving'); $OUTPUT->send(); exit; } @@ -126,7 +125,7 @@ else rcmail_set_unseen_count($mbox, $unseen_count); } - if ($RCMAIL->action == 'move' && strlen($target)) { + if ($RCMAIL->action == 'moveto' && strlen($target)) { rcmail_send_unread_count($target, true); } diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index 779fb87cd..c1c257127 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -123,7 +123,7 @@ function rcmail_fix_emoticon_paths($mime_message) // sanitize image name so resulting attachment doesn't leave images dir $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name); - $img_file = INSTALL_PATH . '/' . $searchstr . $image_name; + $img_file = '/usr/share/tinymce/www/plugins/emotions/img/' . $image_name; if (! in_array($image_name, $included_images)) { // add the image to the MIME message @@ -391,6 +391,10 @@ if (!empty($mailcc)) { if (!empty($mailbcc)) { $headers['Bcc'] = $mailbcc; } +if (!empty($identity_arr['bcc']) && stripos($headers['Bcc'], $identity_arr['bcc']) === false) { + $headers['Bcc'] = ($headers['Bcc'] ? $headers['Bcc'].', ' : '') . $identity_arr['bcc']; + $RECIPIENT_COUNT ++; +} if (($max_recipients = (int) $RCMAIL->config->get('max_recipients')) > 0) { if ($RECIPIENT_COUNT > $max_recipients) { @@ -408,6 +412,9 @@ if (!empty($identity_arr['organization'])) { if (!empty($_POST['_replyto'])) { $headers['Reply-To'] = rcmail_email_input_format(get_input_value('_replyto', RCUBE_INPUT_POST, TRUE, $message_charset)); } +else if (!empty($identity_arr['reply-to'])) { + $headers['Reply-To'] = rcmail_email_input_format($identity_arr['reply-to'], false, true); +} if (!empty($headers['Reply-To'])) { $headers['Mail-Reply-To'] = $headers['Reply-To']; } @@ -823,24 +830,15 @@ if ($savedraft) { // start the auto-save timer again $OUTPUT->command('auto_save_start'); + + $OUTPUT->send('iframe'); } else { - $folders = array(); - - if ($COMPOSE['mode'] == 'reply' || $COMPOSE['mode'] == 'forward') - $folders[] = $COMPOSE['mailbox']; - rcmail_compose_cleanup($COMPOSE_ID); if ($store_folder && !$saved) - $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'), $folders); - else { - if ($store_folder) { - $folders[] = $store_target; - } - - $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'), $folders); - } + $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent')); + else + $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'), $store_target); + $OUTPUT->send('iframe'); } - -$OUTPUT->send('iframe'); diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 59f4d55e1..c1726bbdf 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -19,7 +19,7 @@ +-----------------------------------------------------------------------+ */ -$PRINT_MODE = $RCMAIL->action == 'print' ? TRUE : FALSE; +$PRINT_MODE = $RCMAIL->action=='print' ? TRUE : FALSE; // Read browser capabilities and store them in session if ($caps = get_input_value('_caps', RCUBE_INPUT_GET)) { @@ -31,21 +31,8 @@ if ($caps = get_input_value('_caps', RCUBE_INPUT_GET)) { $_SESSION['browser_caps'] = $browser_caps; } -$uid = get_input_value('_uid', RCUBE_INPUT_GET); -$mbox_name = $RCMAIL->storage->get_folder(); - // similar code as in program/steps/mail/get.inc -if ($uid) { - // set message format (need to be done before rcube_message construction) - if (!empty($_GET['_format'])) { - $prefer_html = $_GET['_format'] == 'html'; - $RCMAIL->config->set('prefer_html', $prefer_html); - $_SESSION['msg_formats'][$mbox_name.':'.$uid] = $prefer_html; - } - else if (isset($_SESSION['msg_formats'][$mbox_name.':'.$uid])) { - $RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$uid]); - } - +if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { $MESSAGE = new rcube_message($uid); // if message not found (wrong UID)... @@ -53,6 +40,7 @@ if ($uid) { rcmail_message_error($uid); } + $mbox_name = $RCMAIL->storage->get_folder(); // show images? rcmail_check_safe($MESSAGE); @@ -116,12 +104,7 @@ if ($uid) { if (!$OUTPUT->ajax_call) $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', - 'movingmessage', 'deletingmessage', 'markingmessage', 'replyall', 'replylist'); - - $prefer_html = $RCMAIL->config->get('prefer_html'); - if ($MESSAGE->has_html_part()) { - $OUTPUT->set_env('optional_format', $prefer_html ? 'text' : 'html'); - } + 'movingmessage', 'deletingmessage', 'markingmessage'); // check for unset disposition notification if ($MESSAGE->headers->mdn_to @@ -164,7 +147,6 @@ function rcmail_message_attachments($attrib) global $PRINT_MODE, $MESSAGE, $RCMAIL; $out = $ol = ''; - $attachments = array(); if (sizeof($MESSAGE->attachments)) { foreach ($MESSAGE->attachments as $attach_prop) { @@ -175,31 +157,30 @@ function rcmail_message_attachments($attrib) $ol .= html::tag('li', null, Q(sprintf("%s (%s)", $filename, $size))); } else { - if (mb_strlen($filename) > 50) { + if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) { $title = $filename; - $filename = abbreviate_string($filename, 50); + $filename = abbreviate_string($filename, $attrib['maxlength']); } else { $title = ''; } - $mimetype = rcmail_fix_mimetype($attach_prop->mimetype); - $class = rcmail_filetype2classname($mimetype, $filename); - $id = 'attach' . $attach_prop->mime_id; - $link = html::a(array( + $ol .= html::tag('li', rcmail_filetype2classname($attach_prop->mimetype, $filename), + html::a(array( 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), - 'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)', - JS_OBJECT_NAME, $attach_prop->mime_id), - 'title' => Q($title), - ), Q($filename)); - $ol .= html::tag('li', array('class' => $class, 'id' => $id), $link); - - $attachments[$attach_prop->mime_id] = $mimetype; + 'onclick' => sprintf( + 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', + JS_OBJECT_NAME, + $attach_prop->mime_id, + rcmail_fix_mimetype($attach_prop->mimetype)), + 'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)', + 'title' => Q($title), + ), + Q($filename))); } } $out = html::tag('ul', $attrib, $ol, html::$common_attrib); - $RCMAIL->output->set_env('attachments', $attachments); } return $out; @@ -228,11 +209,11 @@ function rcmail_remote_objects_msg() function rcmail_message_buttons() { - global $RCMAIL; + global $MESSAGE, $RCMAIL, $CONFIG; $mbox = $RCMAIL->storage->get_folder(); $delim = $RCMAIL->storage->get_hierarchy_delimiter(); - $dbox = $RCMAIL->config->get('drafts_mbox'); + $dbox = $CONFIG['drafts_mbox']; // the message is not a draft if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { @@ -309,9 +290,9 @@ $OUTPUT->add_handlers(array( )); -if ($RCMAIL->action == 'print' && $OUTPUT->template_exists('messageprint')) +if ($RCMAIL->action=='print' && $OUTPUT->template_exists('messageprint')) $OUTPUT->send('messageprint', false); -else if ($RCMAIL->action == 'preview' && $OUTPUT->template_exists('messagepreview')) +else if ($RCMAIL->action=='preview' && $OUTPUT->template_exists('messagepreview')) $OUTPUT->send('messagepreview', false); else $OUTPUT->send('message', false); diff --git a/program/steps/mail/show.inc.orig b/program/steps/mail/show.inc.orig new file mode 100644 index 000000000..5ca8f66d4 --- /dev/null +++ b/program/steps/mail/show.inc.orig @@ -0,0 +1,315 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/mail/show.inc | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2009, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Display a mail message similar as a usual mail application does | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +$PRINT_MODE = $RCMAIL->action=='print' ? TRUE : FALSE; + +// Read browser capabilities and store them in session +if ($caps = get_input_value('_caps', RCUBE_INPUT_GET)) { + $browser_caps = array(); + foreach (explode(',', $caps) as $cap) { + $cap = explode('=', $cap); + $browser_caps[$cap[0]] = $cap[1]; + } + $_SESSION['browser_caps'] = $browser_caps; +} + +// similar code as in program/steps/mail/get.inc +if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { + $MESSAGE = new rcube_message($uid); + + // if message not found (wrong UID)... + if (empty($MESSAGE->headers)) { + rcmail_message_error($uid); + } + + $mbox_name = $RCMAIL->storage->get_folder(); + + // show images? + rcmail_check_safe($MESSAGE); + + // set message charset as default + if (!empty($MESSAGE->headers->charset)) + $RCMAIL->storage->set_charset($MESSAGE->headers->charset); + + $OUTPUT->set_pagetitle(abbreviate_string($MESSAGE->subject, 128, '...', true)); + + // give message uid to the client + $OUTPUT->set_env('uid', $MESSAGE->uid); + // set environement + $OUTPUT->set_env('safemode', $MESSAGE->is_safe); + $OUTPUT->set_env('sender', $MESSAGE->sender['string']); + $OUTPUT->set_env('permaurl', rcmail_url('show', array('_uid' => $MESSAGE->uid, '_mbox' => $mbox_name))); + $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); + $OUTPUT->set_env('mailbox', $mbox_name); + $OUTPUT->set_env('compose_extwin', $RCMAIL->config->get('compose_extwin',false)); + + // mimetypes supported by the browser (default settings) + $mimetypes = (array)$RCMAIL->config->get('client_mimetypes'); + + // Remove unsupported types, which makes that attachment which cannot be + // displayed in a browser will be downloaded directly without displaying an overlay page + if (empty($_SESSION['browser_caps']['pdf']) && ($key = array_search('application/pdf', $mimetypes)) !== false) { + unset($mimetypes[$key]); + } + if (empty($_SESSION['browser_caps']['flash']) && ($key = array_search('application/x-shockwave-flash', $mimetypes)) !== false) { + unset($mimetypes[$key]); + } + if (empty($_SESSION['browser_caps']['tif']) && ($key = array_search('image/tiff', $mimetypes)) !== false) { + // we can convert tiff to jpeg + if (!$RCMAIL->config->get('im_convert_path')) { + unset($mimetypes[$key]); + } + } + + $OUTPUT->set_env('mimetypes', $mimetypes); + + if ($CONFIG['drafts_mbox']) + $OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']); + if ($CONFIG['trash_mbox']) + $OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']); + if ($CONFIG['junk_mbox']) + $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); + if ($CONFIG['delete_junk']) + $OUTPUT->set_env('delete_junk', true); + if ($CONFIG['flag_for_deletion']) + $OUTPUT->set_env('flag_for_deletion', true); + if ($CONFIG['read_when_deleted']) + $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 ($MESSAGE->headers->others['list-post']) + $OUTPUT->set_env('list_post', true); + if ($CONFIG['forward_attachment']) + $OUTPUT->set_env('forward_attachment', true); + + if (!$OUTPUT->ajax_call) + $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', + 'movingmessage', 'deletingmessage', 'markingmessage'); + + // check for unset disposition notification + if ($MESSAGE->headers->mdn_to + && empty($MESSAGE->headers->flags['MDNSENT']) + && empty($MESSAGE->headers->flags['SEEN']) + && ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*')) + && $mbox_name != $CONFIG['drafts_mbox'] + && $mbox_name != $CONFIG['sent_mbox'] + ) { + $mdn_cfg = intval($CONFIG['mdn_requests']); + + if ($mdn_cfg == 1 || (($mdn_cfg == 3 || $mdn_cfg == 4) && rcmail_contact_exists($MESSAGE->sender['mailto']))) { + // Send MDN + if (rcmail_send_mdn($MESSAGE, $smtp_error)) + $OUTPUT->show_message('receiptsent', 'confirmation'); + else if ($smtp_error) + $OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']); + else + $OUTPUT->show_message('errorsendingreceipt', 'error'); + } + else if ($mdn_cfg != 2 && $mdn_cfg != 4) { + // Ask user + $OUTPUT->add_label('mdnrequest'); + $OUTPUT->set_env('mdn_request', true); + } + } + + if (empty($MESSAGE->headers->flags['SEEN']) + && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0)) + ) { + $RCMAIL->plugins->exec_hook('message_read', array('uid' => $MESSAGE->uid, + 'mailbox' => $mbox_name, 'message' => $MESSAGE)); + } +} + + + +function rcmail_message_attachments($attrib) +{ + global $PRINT_MODE, $MESSAGE, $RCMAIL; + + $out = $ol = ''; + + if (sizeof($MESSAGE->attachments)) { + foreach ($MESSAGE->attachments as $attach_prop) { +<<<<<<< HEAD + $filename = rcmail_attachment_name($attach_prop, true); +======= + $filename = $attach_prop->filename; + if (empty($filename) && $attach_prop->mimetype == 'text/html') { + $filename = rcube_label('htmlmessage'); + } +>>>>>>> parent of be72fb3... Unified attachments filenames handling for message parts without a filename + + if ($PRINT_MODE) { + $size = $RCMAIL->message_part_size($attach_prop); + $ol .= html::tag('li', null, Q(sprintf("%s (%s)", $filename, $size))); + } + else { + if (mb_strlen($filename) > 50) { + $filename = abbreviate_string($filename, 50); + $title = $filename; + } + else { + $title = ''; + } + + $ol .= html::tag('li', rcmail_filetype2classname($attach_prop->mimetype, $filename), + html::a(array( + 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), + 'onclick' => sprintf( + 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', + JS_OBJECT_NAME, + $attach_prop->mime_id, + rcmail_fix_mimetype($attach_prop->mimetype)), + 'title' => Q($title), + ), + Q($filename))); + } + } + + $out = html::tag('ul', $attrib, $ol, html::$common_attrib); + } + + return $out; +} + +function rcmail_remote_objects_msg() +{ + global $MESSAGE, $RCMAIL; + + $attrib['id'] = 'remote-objects-message'; + $attrib['class'] = 'notice'; + $attrib['style'] = 'display: none'; + + $msg = Q(rcube_label('blockedimages')) . ' '; + $msg .= html::a(array('href' => "#loadimages", 'onclick' => JS_OBJECT_NAME.".command('load-images')"), Q(rcube_label('showimages'))); + + // add link to save sender in addressbook and reload message + if ($MESSAGE->sender['mailto'] && $RCMAIL->config->get('show_images') == 1) { + $msg .= ' ' . html::a(array('href' => "#alwaysload", 'onclick' => JS_OBJECT_NAME.".command('always-load')", 'style' => "white-space:nowrap"), + Q(rcube_label(array('name' => 'alwaysshow', 'vars' => array('sender' => $MESSAGE->sender['mailto']))))); + } + + $RCMAIL->output->add_gui_object('remoteobjectsmsg', $attrib['id']); + return html::div($attrib, $msg); +} + +function rcmail_message_buttons() +{ + global $MESSAGE, $RCMAIL, $CONFIG; + + $mbox = $RCMAIL->storage->get_folder(); + $delim = $RCMAIL->storage->get_hierarchy_delimiter(); + $dbox = $CONFIG['drafts_mbox']; + + // the message is not a draft + if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { + return ''; + } + + $attrib['id'] = 'message-buttons'; + $attrib['class'] = 'notice'; + + $msg = Q(rcube_label('isdraft')) . ' '; + $msg .= html::a(array('href' => "#edit", 'onclick' => JS_OBJECT_NAME.".command('edit')"), Q(rcube_label('edit'))); + + return html::div($attrib, $msg); +} + +function rcmail_message_objects($attrib) +{ + global $RCMAIL, $MESSAGE; + + if (!$attrib['id']) + $attrib['id'] = 'message-objects'; + + $content = array( + rcmail_message_buttons(), + rcmail_remote_objects_msg(), + ); + + $plugin = $RCMAIL->plugins->exec_hook('message_objects', + array('content' => $content, 'message' => $MESSAGE)); + + $content = implode("\n", $plugin['content']); + + return html::div($attrib, $content); +} + +function rcmail_contact_exists($email) +{ + global $RCMAIL; + + if ($email) { + // @TODO: search in all address books? + $CONTACTS = $RCMAIL->get_address_book(-1, true); + $existing = $CONTACTS->search('email', $email, true, false); + if ($existing->count) + return true; + } + + return false; +} + +function rcmail_message_contactphoto($attrib) +{ + global $RCMAIL, $MESSAGE; + + $placeholder = $attrib['placeholder'] ? $RCMAIL->config->get('skin_path') . $attrib['placeholder'] : null; + if ($MESSAGE->sender) + $photo_img = $RCMAIL->url(array('_task' => 'addressbook', '_action' => 'photo', '_email' => $MESSAGE->sender['mailto'], '_alt' => $placeholder)); + else + $photo_img = $placeholder ? $placeholder : 'program/resources/blank.gif'; + + return html::img(array('src' => $photo_img) + $attrib); +} + + +$OUTPUT->add_handlers(array( + 'messageattachments' => 'rcmail_message_attachments', + 'mailboxname' => 'rcmail_mailbox_name_display', + 'messageobjects' => 'rcmail_message_objects', + 'contactphoto' => 'rcmail_message_contactphoto', +)); + + +if ($RCMAIL->action=='print' && $OUTPUT->template_exists('messageprint')) + $OUTPUT->send('messageprint', false); +else if ($RCMAIL->action=='preview' && $OUTPUT->template_exists('messagepreview')) + $OUTPUT->send('messagepreview', false); +else + $OUTPUT->send('message', false); + + +// mark message as read +if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN']) && + ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) +{ + if ($RCMAIL->storage->set_flag($MESSAGE->uid, 'SEEN')) { + if ($count = rcmail_get_unseen_count($mbox_name)) { + rcmail_set_unseen_count($mbox_name, $count - 1); + } + } +} + +exit; + diff --git a/program/steps/settings/about.inc b/program/steps/settings/about.inc index 0fdefddda..9b13402f1 100644 --- a/program/steps/settings/about.inc +++ b/program/steps/settings/about.inc @@ -40,28 +40,17 @@ function rcmail_plugins_list($attrib) $attrib['id'] = 'rcmpluginlist'; $plugins = array_filter((array) $RCMAIL->config->get('plugins')); - $plugin_info = array(); + $plugins = array_flip($plugins); - foreach ($plugins as $name) { - if ($info = $RCMAIL->plugins->get_info($name)) - $plugin_info[$name] = $info; + foreach ($plugins as $name => $plugin) { + rcube_plugin_data($name, $plugins); } - // load info from required plugins, too - foreach ($plugin_info as $name => $info) { - if (is_array($info['required']) && !empty($info['required'])) { - foreach ($info['required'] as $req_name) { - if (!isset($plugin_info[$req_name]) && ($req_info = $RCMAIL->plugins->get_info($req_name))) - $plugin_info[$req_name] = $req_info; - } - } - } - - if (empty($plugin_info)) { + if (empty($plugins)) { return ''; } - ksort($plugin_info, SORT_LOCALE_STRING); + ksort($plugins, SORT_LOCALE_STRING); $table = new html_table($attrib); @@ -71,8 +60,8 @@ function rcmail_plugins_list($attrib) $table->add_header('license', rcube_label('license')); $table->add_header('source', rcube_label('source')); - foreach ($plugin_info as $name => $data) { - $uri = $data['src_uri'] ? $data['src_uri'] : $data['uri']; + foreach ($plugins as $name => $data) { + $uri = $data['srcuri'] ? $data['srcuri'] : $data['uri']; if ($uri && stripos($uri, 'http') !== 0) { $uri = 'http://' . $uri; } @@ -89,6 +78,48 @@ function rcmail_plugins_list($attrib) return $table->show(); } +function rcube_plugin_data($name, &$plugins = array()) +{ + // XPaths of plugin metadata elements + $metadata = array( + 'name' => 'string(//rc:package/rc:name)', + 'version' => 'string(//rc:package/rc:version/rc:release)', + 'license' => 'string(//rc:package/rc:license)', + 'license_uri' => 'string(//rc:package/rc:license/@uri)', + 'srcuri' => 'string(//rc:package/rc:srcuri)', + 'uri' => 'string(//rc:package/rc:uri)', + ); + + $package = INSTALL_PATH . "/plugins/$name/package.xml"; + if (file_exists($package) && ($file = file_get_contents($package))) { + $doc = new DOMDocument(); + $doc->loadXML($file); + $xpath = new DOMXPath($doc); + $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); + $data = array(); + + foreach ($metadata as $key => $path) { + $data[$key] = $xpath->evaluate($path); + } + + $plugins[$name] = $data; + + // dependent required plugins (can be used, but not included in config) + $deps = $xpath->evaluate('//rc:package/rc:dependencies/rc:required/rc:package/rc:name'); + $cnt = $deps->length; + + for ($i=0; $i<$cnt; $i++) { + $dn = $deps->item($i)->nodeValue; + if (!array_key_exists($dn, $plugins)) { + rcube_plugin_data($dn, $plugins); + } + } + } + else { + unset($plugins[$name]); + } +} + $OUTPUT->set_pagetitle(rcube_label('about')); diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index f19e2177b..fdb38e602 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -264,12 +264,9 @@ function rcmail_folder_form($attrib) $content = rcmail_get_form_part($tab, $attrib); } - if ($content && sizeof($form) > 1) { + if ($content) { $out .= html::tag('fieldset', null, html::tag('legend', null, Q($tab['name'])) . $content) ."\n"; } - else { - $out .= $content ."\n"; - } } $out .= "\n$form_end"; diff --git a/program/steps/settings/edit_prefs.inc b/program/steps/settings/edit_prefs.inc index 468e4994d..971ed60b6 100644 --- a/program/steps/settings/edit_prefs.inc +++ b/program/steps/settings/edit_prefs.inc @@ -40,7 +40,7 @@ function rcmail_user_prefs_form($attrib) $out = $form_start; - foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $block) { + foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $idx => $block) { if (!empty($block['options'])) { $table = new html_table(array('cols' => 2)); diff --git a/program/steps/settings/edit_response.inc b/program/steps/settings/edit_response.inc new file mode 100644 index 000000000..49856775a --- /dev/null +++ b/program/steps/settings/edit_response.inc @@ -0,0 +1,107 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/settings/edit_response.inc | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Show edit form for a canned response record or to add a new one | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +$responses = $RCMAIL->get_compose_responses(); + +// edit-response +if (($key = get_input_value('_key', RCUBE_INPUT_GPC))) { + foreach ($responses as $i => $response) { + if ($response['key'] == $key) { + $RESPONSE_RECORD = $response; + $RESPONSE_RECORD['index'] = $i; + break; + } + } +} + +// save response +if ($RCMAIL->action == 'save-response' && isset($_POST['_name']) && !$RESPONSE_RECORD['static']) { + $name = trim(get_input_value('_name', RCUBE_INPUT_POST)); + $text = trim(get_input_value('_text', RCUBE_INPUT_POST)); + + if (!empty($name) && !empty($text)) { + $dupes = 0; + foreach ($responses as $i => $resp) { + if ($RESPONSE_RECORD && $RESPONSE_RECORD['index'] === $i) + continue; + if (strcasecmp($name, preg_replace('/\s\(\d+\)$/', '', $resp['name'])) == 0) + $dupes++; + } + if ($dupes) { // require a unique name + $name .= ' (' . ++$dupes . ')'; + } + + $response = array('name' => $name, 'text' => $text, 'format' => 'text', 'key' => substr(md5($name), 0, 16)); + if ($RESPONSE_RECORD && $responses[$RESPONSE_RECORD['index']]) { + $responses[$RESPONSE_RECORD['index']] = $response; + } + else { + $responses[] = $response; + } + + $responses = array_filter($responses, function($item){ return empty($item['static']); }); + if ($RCMAIL->user->save_prefs(array('compose_responses' => array_values($responses)))) { + $RCMAIL->output->show_message('successfullysaved', 'confirmation'); + $RCMAIL->output->command('parent.update_response_row', $response, $key); + $RCMAIL->overwrite_action('edit-response'); + $RESPONSE_RECORD = $response; + } + } + else { + $RCMAIL->output->show_message('formincomplete', 'error'); + } +} + + +function rcube_response_form($attrib) +{ + global $RCMAIL, $OUTPUT, $RESPONSE_RECORD; + + // Set form tags and hidden fields + $disabled = !empty($RESPONSE_RECORD['static']); + $key = $RESPONSE_RECORD['key']; + list($form_start, $form_end) = get_form_tags($attrib, 'save-response', $key, array('name' => '_key', 'value' => $key)); + unset($attrib['form'], $attrib['id']); + + // return the complete edit form as table + $out = "$form_start\n"; + + $table = new html_table(array('cols' => 2)); + $label = rcube_label('responsename'); + + $table->add('title', html::label('ffname', Q(rcube_label('responsename')))); + $table->add(null, rcube_output::get_edit_field('name', $RESPONSE_RECORD['name'], array('id' => 'ffname', 'size' => $attrib['size'], 'disabled' => $disabled), 'text')); + + $table->add('title', html::label('fftext', Q(rcube_label('responsetext')))); + $table->add(null, rcube_output::get_edit_field('text', $RESPONSE_RECORD['text'], array('id' => 'fftext', 'size' => $attrib['textareacols'], 'rows' => $attrib['textarearows'], 'disabled' => $disabled), 'textarea')); + + $out .= $table->show($attrib); + $out .= $form_end; + + return $out; +} + +$OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static'])); +$OUTPUT->add_handler('responseform', 'rcube_response_form'); +$OUTPUT->set_pagetitle(rcube_label(($RCMAIL->action=='add-response' ? 'savenewresponse' : 'editresponse'))); + +$OUTPUT->send('responseedit'); + diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 64af18d62..778d93c03 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -232,16 +232,16 @@ function rcube_subscription_form($attrib) // add any necessary "virtual" parent folders if ($parent_folder && !isset($seen[$parent_folder])) { 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], 'UTF7-IMAP'); - $list_folders[] = array( + $ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i)); + if ($ancestor_folder && !$seen[$ancestor_folder]++) { + $ancestor_name = rcube_charset_convert($foldersplit[$i-1], 'UTF7-IMAP'); + $list_folders[] = array( 'id' => $ancestor_folder, 'name' => $ancestor_name, 'level' => $i-1, 'virtual' => true, ); - } + } } } @@ -283,6 +283,7 @@ function rcube_subscription_form($attrib) $noselect = false; $classes = array($i%2 ? 'even' : 'odd'); + $folder_js = Q($folder['id']); $folder_utf8 = rcube_charset_convert($folder['id'], 'UTF7-IMAP'); $display_folder = str_repeat(' ', $folder['level']) . Q($protected ? rcmail_localize_foldername($folder['id']) : $folder['name']); @@ -291,8 +292,7 @@ function rcube_subscription_form($attrib) $classes[] = 'virtual'; } - // Check \Noselect flag (of existing folder) - if (!$protected && in_array($folder['id'], $a_unsubscribed)) { + if (!$protected) { $attrs = $STORAGE->folder_attributes($folder['id']); $noselect = in_array('\\Noselect', $attrs); } @@ -394,7 +394,7 @@ function rcmail_rename_folder($oldname, $newname) $a_threaded = (array) $RCMAIL->config->get('message_threading', array()); $oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/'; - foreach (array_keys($a_threaded) as $key) { + foreach ($a_threaded as $key => $val) { if ($key == $oldname) { unset($a_threaded[$key]); $a_threaded[$newname] = true; diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index fdc07be9e..981d4e406 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -19,1176 +19,915 @@ +-----------------------------------------------------------------------+ */ -if (!$OUTPUT->ajax_call) { - $OUTPUT->set_pagetitle(rcube_label('preferences')); -} +if (!$OUTPUT->ajax_call) + $OUTPUT->set_pagetitle(rcube_label('preferences')); + // similar function as /steps/settings/identities.inc::rcmail_identity_frame() function rcmail_preferences_frame($attrib) { - global $OUTPUT; + global $OUTPUT; - if (!$attrib['id']) { - $attrib['id'] = 'rcmprefsframe'; - } + if (!$attrib['id']) + $attrib['id'] = 'rcmprefsframe'; - return $OUTPUT->frame($attrib, true); + return $OUTPUT->frame($attrib, true); } function rcmail_sections_list($attrib) { - global $RCMAIL; + global $RCMAIL; - // add id to message list table if not specified - if (!strlen($attrib['id'])) { - $attrib['id'] = 'rcmsectionslist'; - } + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmsectionslist'; - list($list, $cols) = rcmail_user_prefs(); + list($list, $cols) = rcmail_user_prefs(); - // create XHTML table - $out = rcube_table_output($attrib, $list, $cols, 'id'); + // create XHTML table + $out = rcube_table_output($attrib, $list, $cols, 'id'); - // set client env - $RCMAIL->output->add_gui_object('sectionslist', $attrib['id']); - $RCMAIL->output->include_script('list.js'); + // set client env + $RCMAIL->output->add_gui_object('sectionslist', $attrib['id']); + $RCMAIL->output->include_script('list.js'); - return $out; + return $out; } function rcmail_identities_list($attrib) { - global $OUTPUT, $RCMAIL; + global $OUTPUT, $RCMAIL; - // add id to message list table if not specified - if (!strlen($attrib['id'])) { - $attrib['id'] = 'rcmIdentitiesList'; - } + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmIdentitiesList'; - // get identities list and define 'mail' column - $list = $RCMAIL->user->list_identities(); - foreach ($list as $idx => $row) { - $list[$idx]['mail'] = trim($row['name'] . ' <' . rcube_idn_to_utf8($row['email']) .'>'); - } + // get identities list and define 'mail' column + $list = $RCMAIL->user->list_identities(); + foreach ($list as $idx => $row) + $list[$idx]['mail'] = trim($row['name'] . ' <' . rcube_idn_to_utf8($row['email']) .'>'); - // get all identites from DB and define list of cols to be displayed - $plugin = $RCMAIL->plugins->exec_hook('identities_list', array( - 'list' => $list, - 'cols' => array('mail') - )); + // get all identites from DB and define list of cols to be displayed + $plugin = $RCMAIL->plugins->exec_hook('identities_list', array( + 'list' => $list, + 'cols' => array('mail'))); - // @TODO: use <UL> instead of <TABLE> for identities list - // create XHTML table - $out = rcube_table_output($attrib, $plugin['list'], $plugin['cols'], 'identity_id'); + // @TODO: use <UL> instead of <TABLE> for identities list + // create XHTML table + $out = rcube_table_output($attrib, $plugin['list'], $plugin['cols'], 'identity_id'); - // set client env - $OUTPUT->add_gui_object('identitieslist', $attrib['id']); + // set client env + $OUTPUT->add_gui_object('identitieslist', $attrib['id']); - return $out; + return $out; } // similar function as in /steps/addressbook/edit.inc function get_form_tags($attrib, $action, $id = null, $hidden = null) { - global $EDIT_FORM, $RCMAIL; - - $form_start = $form_end = ''; - - if (empty($EDIT_FORM)) { - $request_key = $action . (isset($id) ? '.'.$id : ''); - $form_start = $RCMAIL->output->request_form(array( - 'name' => 'form', - 'method' => 'post', - 'task' => $RCMAIL->task, - 'action' => $action, - 'request' => $request_key, - 'noclose' => true - ) + $attrib); - - if (is_array($hidden)) { - $hiddenfields = new html_hiddenfield($hidden); - $form_start .= $hiddenfields->show(); - } + global $EDIT_FORM, $RCMAIL; + + $form_start = $form_end = ''; + + if (empty($EDIT_FORM)) { + $request_key = $action . (isset($id) ? '.'.$id : ''); + $form_start = $RCMAIL->output->request_form(array( + 'name' => 'form', + 'method' => 'post', + 'task' => $RCMAIL->task, + 'action' => $action, + 'request' => $request_key, + 'noclose' => true + ) + $attrib); + + if (is_array($hidden)) { + $hiddenfields = new html_hiddenfield($hidden); + $form_start .= $hiddenfields->show(); + } - $form_end = !strlen($attrib['form']) ? '</form>' : ''; + $form_end = !strlen($attrib['form']) ? '</form>' : ''; - $EDIT_FORM = !empty($attrib['form']) ? $attrib['form'] : 'form'; - $RCMAIL->output->add_gui_object('editform', $EDIT_FORM); - } + $EDIT_FORM = !empty($attrib['form']) ? $attrib['form'] : 'form'; + $RCMAIL->output->add_gui_object('editform', $EDIT_FORM); + } - return array($form_start, $form_end); + return array($form_start, $form_end); } -function rcmail_user_prefs($current = null) +function rcmail_user_prefs($current=null) { - global $RCMAIL; + global $RCMAIL; + + $sections['general'] = array('id' => 'general', 'section' => rcube_label('uisettings')); + $sections['mailbox'] = array('id' => 'mailbox', 'section' => rcube_label('mailboxview')); + $sections['mailview'] = array('id' => 'mailview','section' => rcube_label('messagesdisplaying')); + $sections['compose'] = array('id' => 'compose', 'section' => rcube_label('messagescomposition')); + $sections['addressbook'] = array('id' => 'addressbook','section' => rcube_label('addressbook')); + $sections['folders'] = array('id' => 'folders', 'section' => rcube_label('specialfolders')); + $sections['server'] = array('id' => 'server', 'section' => rcube_label('serversettings')); + + // hook + define list cols + $plugin = $RCMAIL->plugins->exec_hook('preferences_sections_list', + array('list' => $sections, 'cols' => array('section'))); - $sections['general'] = array('id' => 'general', 'section' => rcube_label('uisettings')); - $sections['mailbox'] = array('id' => 'mailbox', 'section' => rcube_label('mailboxview')); - $sections['mailview'] = array('id' => 'mailview','section' => rcube_label('messagesdisplaying')); - $sections['compose'] = array('id' => 'compose', 'section' => rcube_label('messagescomposition')); - $sections['addressbook'] = array('id' => 'addressbook','section' => rcube_label('addressbook')); - $sections['folders'] = array('id' => 'folders', 'section' => rcube_label('specialfolders')); - $sections['server'] = array('id' => 'server', 'section' => rcube_label('serversettings')); + $sections = $plugin['list']; - // hook + define list cols - $plugin = $RCMAIL->plugins->exec_hook('preferences_sections_list', - array('list' => $sections, 'cols' => array('section'))); + $config = $RCMAIL->config->all(); + $no_override = array_flip($RCMAIL->config->get('dont_override', array())); + + foreach ($sections as $idx => $sect) { + + if ($current && $sect['id'] != $current) + continue; + + $blocks = array(); - $sections = $plugin['list']; - $config = $RCMAIL->config->all(); - $no_override = array_flip((array)$RCMAIL->config->get('dont_override')); + switch ($sect['id']) { + // general + case 'general': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + ); + + // language selection + if (!isset($no_override['language'])) { + $a_lang = $RCMAIL->list_languages(); + asort($a_lang); + + $field_id = 'rcmfd_lang'; + $select_lang = new html_select(array('name' => '_language', 'id' => $field_id)); + $select_lang->add(array_values($a_lang), array_keys($a_lang)); + + $blocks['main']['options']['language'] = array( + 'title' => html::label($field_id, Q(rcube_label('language'))), + 'content' => $select_lang->show($RCMAIL->user->language), + ); + } - foreach ($sections as $idx => $sect) { - if ($current && $sect['id'] != $current) { - continue; + // timezone selection + if (!isset($no_override['timezone'])) { + $field_id = 'rcmfd_timezone'; + $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id)); + $select_timezone->add(rcube_label('autodetect'), 'auto'); + + $zones = array(); + foreach (DateTimeZone::listIdentifiers() as $i => $tzs) { + try { + $tz = new DateTimeZone($tzs); + $date = new DateTime('2012-12-21', $tz); + $offset = $date->format('Z') + 45000; + $sortkey = sprintf('%06d.%s', $offset, $tzs); + $zones[$sortkey] = array($tzs, $date->format('P')); } + catch (Exception $e) {} + } + + ksort($zones); + foreach ($zones as $zone) { + list($tzs, $offset) = $zone; + $select_timezone->add('(GMT ' . $offset . ') ' . strtr($tzs, '_', ' '), $tzs); + } + + $blocks['main']['options']['timezone'] = array( + 'title' => html::label($field_id, Q(rcube_label('timezone'))), + 'content' => $select_timezone->show((string)$config['timezone']), + ); + } + + // date/time formatting + if (!isset($no_override['time_format'])) { + $reftime = mktime(7,30,0); + $field_id = 'rcmfd_time_format'; + $select_time = new html_select(array('name' => '_time_format', 'id' => $field_id)); + foreach ((array)$RCMAIL->config->get('time_formats', array('G:i', 'H:i', 'g:i a', 'h:i A')) as $choice) + $select_time->add(date($choice, $reftime), $choice); + + $blocks['main']['options']['time_format'] = array( + 'title' => html::label($field_id, Q(rcube_label('timeformat'))), + 'content' => $select_time->show($RCMAIL->config->get('time_format')), + ); + } + + if (!isset($no_override['date_format'])) { + $refdate = mktime(12,30,0,7,24); + $field_id = 'rcmfd_date_format'; + $select_date = new html_select(array('name' => '_date_format', 'id' => $field_id)); + foreach ((array)$RCMAIL->config->get('date_formats', array('Y-m-d','d-m-Y','Y/m/d','m/d/Y','d/m/Y','d.m.Y','j.n.Y')) as $choice) + $select_date->add(date($choice, $refdate), $choice); + + $blocks['main']['options']['date_format'] = array( + 'title' => html::label($field_id, Q(rcube_label('dateformat'))), + 'content' => $select_date->show($config['date_format']), + ); + } + + // MM: Show checkbox for toggling 'pretty dates' + if (!isset($no_override['prettydate'])) { + $field_id = 'rcmfd_prettydate'; + $input_prettydate = new html_checkbox(array('name' => '_pretty_date', 'id' => $field_id, 'value' => 1)); - $blocks = array(); - - switch ($sect['id']) { - - // general - case 'general': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - 'skin' => array('name' => Q(rcube_label('skin'))), - 'browser' => array('name' => Q(rcube_label('browseroptions'))), - ); - - // language selection - if (!isset($no_override['language'])) { - if (!$current) { - continue 2; - } - - $a_lang = $RCMAIL->list_languages(); - asort($a_lang); - - $field_id = 'rcmfd_lang'; - $select = new html_select(array('name' => '_language', 'id' => $field_id)); - $select->add(array_values($a_lang), array_keys($a_lang)); - - $blocks['main']['options']['language'] = array( - 'title' => html::label($field_id, Q(rcube_label('language'))), - 'content' => $select->show($RCMAIL->user->language), - ); - } - - // timezone selection - if (!isset($no_override['timezone'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_timezone'; - $select = new html_select(array('name' => '_timezone', 'id' => $field_id)); - $select->add(rcube_label('autodetect'), 'auto'); - - $zones = array(); - foreach (DateTimeZone::listIdentifiers() as $i => $tzs) { - try { - $tz = new DateTimeZone($tzs); - $date = new DateTime('2012-12-21', $tz); - $offset = $date->format('Z') + 45000; - $sortkey = sprintf('%06d.%s', $offset, $tzs); - $zones[$sortkey] = array($tzs, $date->format('P')); - } - catch (Exception $e) {} - } - - ksort($zones); - - foreach ($zones as $zone) { - list($tzs, $offset) = $zone; - $select->add('(GMT ' . $offset . ') ' . strtr($tzs, '_', ' '), $tzs); - } - - $blocks['main']['options']['timezone'] = array( - 'title' => html::label($field_id, Q(rcube_label('timezone'))), - 'content' => $select->show((string)$config['timezone']), - ); - } - - // date/time formatting - if (!isset($no_override['time_format'])) { - if (!$current) { - continue 2; - } - - $reftime = mktime(7,30,0); - $defaults = array('G:i', 'H:i', 'g:i a', 'h:i A'); - $formats = (array)$RCMAIL->config->get('time_formats', $defaults); - $field_id = 'rcmfd_time_format'; - $select = new html_select(array('name' => '_time_format', 'id' => $field_id)); - - foreach ($formats as $choice) { - $select->add(date($choice, $reftime), $choice); - } - - $blocks['main']['options']['time_format'] = array( - 'title' => html::label($field_id, Q(rcube_label('timeformat'))), - 'content' => $select->show($RCMAIL->config->get('time_format')), - ); - } - - if (!isset($no_override['date_format'])) { - if (!$current) { - continue 2; - } - - $refdate = mktime(12,30,0,7,24); - $defaults = array('Y-m-d','d-m-Y','Y/m/d','m/d/Y','d/m/Y','d.m.Y','j.n.Y'); - $formats = (array)$RCMAIL->config->get('date_formats', $defaults); - $field_id = 'rcmfd_date_format'; - $select = new html_select(array('name' => '_date_format', 'id' => $field_id)); - - foreach ($formats as $choice) { - $select->add(date($choice, $refdate), $choice); - } - - $blocks['main']['options']['date_format'] = array( - 'title' => html::label($field_id, Q(rcube_label('dateformat'))), - 'content' => $select->show($config['date_format']), - ); - } - - // Show checkbox for toggling 'pretty dates' - if (!isset($no_override['prettydate'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_prettydate'; - $input = new html_checkbox(array('name' => '_pretty_date', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['prettydate'] = array( - 'title' => html::label($field_id, Q(rcube_label('prettydate'))), - 'content' => $input->show($config['prettydate']?1:0), - ); - } - - if (!isset($no_override['refresh_interval'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_refresh_interval'; - $select = new html_select(array('name' => '_refresh_interval', 'id' => $field_id)); - - $select->add(rcube_label('never'), 0); - foreach (array(1, 3, 5, 10, 15, 30, 60) as $min) { - if (!$config['min_refresh_interval'] || $config['min_refresh_interval'] <= $min * 60) { - $label = rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))); - $select->add($label, $min); - } - } - - $blocks['main']['options']['refresh_interval'] = array( - 'title' => html::label($field_id, Q(rcube_label('refreshinterval'))), - 'content' => $select->show($config['refresh_interval']/60), - ); - } - - // show drop-down for available skins - if (!isset($no_override['skin'])) { - if (!$current) { - continue 2; - } - - $skins = rcmail_get_skins(); - - if (count($skins) > 1) { - $field_id = 'rcmfd_skin'; - $input = new html_radiobutton(array('name'=>'_skin')); - - foreach ($skins as $skin) { - $thumbnail = "./skins/$skin/thumbnail.png"; - if (!is_file($thumbnail)) - $thumbnail = './program/resources/blank.gif'; - - $skinname = ucfirst($skin); - $author_link = $license_link = ''; - $meta = @json_decode(@file_get_contents("./skins/$skin/meta.json"), true); - - if (is_array($meta) && $meta['name']) { - $skinname = $meta['name']; - $author_link = $meta['url'] ? html::a(array('href' => $meta['url'], 'target' => '_blank'), Q($meta['author'])) : Q($meta['author']); - $license_link = $meta['license-url'] ? html::a(array('href' => $meta['license-url'], 'target' => '_blank'), Q($meta['license'])) : Q($meta['license']); - } - - $blocks['skin']['options'][$skin]['content'] = html::label(array('class' => 'skinselection'), - html::span('skinitem', $input->show($config['skin'], array('value' => $skin, 'id' => $field_id.$skin))) . - html::span('skinitem', html::img(array('src' => $thumbnail, 'class' => 'skinthumbnail', 'alt' => $skin, 'width' => 64, 'height' => 64))) . - html::span('skinitem', html::span('skinname', Q($skinname)) . html::br() . - html::span('skinauthor', $author_link ? 'by ' . $author_link : '') . html::br() . - html::span('skinlicense', $license_link ? rcube_label('license').': ' . $license_link : '')) - ); - } - } - } - - // standard_windows option decides if new windows should be - // opened as popups or standard windows (which can be handled by browsers as tabs) - if (!isset($no_override['standard_windows'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_standard_windows'; - $checkbox = new html_checkbox(array('name' => '_standard_windows', 'id' => $field_id, 'value' => 1)); - - $blocks['browser']['options']['standard_windows'] = array( - 'title' => html::label($field_id, Q(rcube_label('standardwindows'))), - 'content' => $checkbox->show($config['standard_windows']?1:0), - ); - } - - if ($current) { - $product_name = $RCMAIL->config->get('product_name', 'Roundcube Webmail'); - $RCMAIL->output->add_script(sprintf("%s.check_protocol_handler('%s', '#mailtoprotohandler');", - JS_OBJECT_NAME, JQ($product_name)), 'foot'); - } - - $blocks['browser']['options']['mailtoprotohandler'] = array( - 'content' => html::a(array( - 'href' => '#', - 'id' => 'mailtoprotohandler'), Q(rcube_label('mailtoprotohandler'))), - ); - - break; - - // Mailbox view (mail screen) - case 'mailbox': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - 'new_message' => array('name' => Q(rcube_label('newmessage'))), - ); - - // show config parameter for preview pane - if (!isset($no_override['preview_pane'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_preview'; - $input = new html_checkbox(array('name' => '_preview_pane', 'id' => $field_id, 'value' => 1, - 'onchange' => "$('#rcmfd_preview_pane_mark_read').prop('disabled', !this.checked)")); - - $blocks['main']['options']['preview_pane'] = array( - 'title' => html::label($field_id, Q(rcube_label('previewpane'))), - 'content' => $input->show($config['preview_pane']?1:0), - ); - } - - // show config parameter for preview pane auto mark as read delay - if (!isset($no_override['preview_pane_mark_read'])) { - if (!$current) { - continue 2; - } - - // apply default if config option is not set at all - $config['preview_pane_mark_read'] = $RCMAIL->config->get('preview_pane_mark_read', 0); - - $field_id = 'rcmfd_preview_pane_mark_read'; - $select = new html_select(array('name' => '_preview_pane_mark_read', 'id' => $field_id, - 'disabled' => $config['preview_pane']?0:1)); - - $select->add(rcube_label('never'), '-1'); - $select->add(rcube_label('immediately'), 0); - - foreach (array(5, 10, 20, 30) as $sec) { - $label = rcube_label(array('name' => 'afternseconds', 'vars' => array('n' => $sec))); - $select->add($label, $sec); - } - - $blocks['main']['options']['preview_pane_mark_read'] = array( - 'title' => html::label($field_id, Q(rcube_label('previewpanemarkread'))), - 'content' => $select->show(intval($config['preview_pane_mark_read'])), - ); - } - - if (!isset($no_override['mdn_requests'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_mdn_requests'; - $select = new html_select(array('name' => '_mdn_requests', 'id' => $field_id)); - $select->add(rcube_label('askuser'), 0); - $select->add(rcube_label('autosend'), 1); - $select->add(rcube_label('autosendknown'), 3); - $select->add(rcube_label('autosendknownignore'), 4); - $select->add(rcube_label('ignore'), 2); - - $blocks['main']['options']['mdn_requests'] = array( - 'title' => html::label($field_id, Q(rcube_label('mdnrequests'))), - 'content' => $select->show($config['mdn_requests']), - ); - } - - if (!isset($no_override['autoexpand_threads'])) { - if (!$current) { - continue 2; - } - - $storage = $RCMAIL->get_storage(); - $supported = $storage->get_capability('THREAD'); - - if ($supported) { - $field_id = 'rcmfd_autoexpand_threads'; - $select = new html_select(array('name' => '_autoexpand_threads', 'id' => $field_id)); - $select->add(rcube_label('never'), 0); - $select->add(rcube_label('do_expand'), 1); - $select->add(rcube_label('expand_only_unread'), 2); - - $blocks['main']['options']['autoexpand_threads'] = array( - 'title' => html::label($field_id, Q(rcube_label('autoexpand_threads'))), - 'content' => $select->show($config['autoexpand_threads']), - ); - } - } - - // show page size selection - if (!isset($no_override['mail_pagesize'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_mail_pagesize'; - $input = new html_inputfield(array('name' => '_mail_pagesize', 'id' => $field_id, 'size' => 5)); - $size = intval($config['mail_pagesize'] ? $config['mail_pagesize'] : $config['pagesize']); - - $blocks['main']['options']['pagesize'] = array( - 'title' => html::label($field_id, Q(rcube_label('pagesize'))), - 'content' => $input->show($size ? $size : 50), - ); - } - - if (!isset($no_override['check_all_folders'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_check_all_folders'; - $input = new html_checkbox(array('name' => '_check_all_folders', 'id' => $field_id, 'value' => 1)); - - $blocks['new_message']['options']['check_all_folders'] = array( - 'title' => html::label($field_id, Q(rcube_label('checkallfolders'))), - 'content' => $input->show($config['check_all_folders']?1:0), - ); - } - break; - - // Message viewing - case 'mailview': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - ); - - // show checkbox to open message view in new window - if (!isset($no_override['message_extwin'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_message_extwin'; - $input = new html_checkbox(array('name' => '_message_extwin', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['message_extwin'] = array( - 'title' => html::label($field_id, Q(rcube_label('showinextwin'))), - 'content' => $input->show($config['message_extwin']?1:0), - ); - } - - // show checkbox to show email instead of name - if (!isset($no_override['message_show_email'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_message_show_email'; - $input = new html_checkbox(array('name' => '_message_show_email', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['message_show_email'] = array( - 'title' => html::label($field_id, Q(rcube_label('showemail'))), - 'content' => $input->show($config['message_show_email']?1:0), - ); - } - - // show checkbox for HTML/plaintext messages - if (!isset($no_override['prefer_html'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_htmlmsg'; - $input = new html_checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1, - 'onchange' => "$('#rcmfd_show_images').prop('disabled', !this.checked).val(0)")); - - $blocks['main']['options']['prefer_html'] = array( - 'title' => html::label($field_id, Q(rcube_label('preferhtml'))), - 'content' => $input->show($config['prefer_html']?1:0), - ); - } - - if (!isset($no_override['default_charset'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_default_charset'; - - $blocks['main']['options']['default_charset'] = array( - 'title' => html::label($field_id, Q(rcube_label('defaultcharset'))), - 'content' => $RCMAIL->output->charset_selector(array( - 'id' => $field_id, 'name' => '_default_charset', 'selected' => $config['default_charset'] - ))); - } - - if (!isset($no_override['show_images'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_show_images'; - $input = new html_select(array('name' => '_show_images', 'id' => $field_id, - 'disabled' => !$config['prefer_html'])); - - $input->add(rcube_label('never'), 0); - $input->add(rcube_label('fromknownsenders'), 1); - $input->add(rcube_label('always'), 2); - - $blocks['main']['options']['show_images'] = array( - 'title' => html::label($field_id, Q(rcube_label('showremoteimages'))), - 'content' => $input->show($config['prefer_html'] ? $config['show_images'] : 0), - ); - } - - if (!isset($no_override['inline_images'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_inline_images'; - $input = new html_checkbox(array('name' => '_inline_images', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['inline_images'] = array( - 'title' => html::label($field_id, Q(rcube_label('showinlineimages'))), - 'content' => $input->show($config['inline_images']?1:0), - ); - } - - // "display after delete" checkbox - if (!isset($no_override['display_next'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_displaynext'; - $input = new html_checkbox(array('name' => '_display_next', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['display_next'] = array( - 'title' => html::label($field_id, Q(rcube_label('displaynext'))), - 'content' => $input->show($config['display_next']?1:0), - ); - } - break; - - // Mail composition - case 'compose': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - 'sig' => array('name' => Q(rcube_label('signatureoptions'))), - 'spellcheck' => array('name' => Q(rcube_label('spellcheckoptions'))), - ); - - // show checkbox to compose messages in a new window - if (!isset($no_override['compose_extwin'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfdcompose_extwin'; - $input = new html_checkbox(array('name' => '_compose_extwin', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['compose_extwin'] = array( - 'title' => html::label($field_id, Q(rcube_label('composeextwin'))), - 'content' => $input->show($config['compose_extwin']?1:0), - ); - } - - if (!isset($no_override['htmleditor'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_htmleditor'; - $select = new html_select(array('name' => '_htmleditor', 'id' => $field_id)); - - $select->add(rcube_label('never'), 0); - $select->add(rcube_label('always'), 1); - $select->add(rcube_label('htmlonreply'), 2); - $select->add(rcube_label('htmlonreplyandforward'), 3); - - $blocks['main']['options']['htmleditor'] = array( - 'title' => html::label($field_id, Q(rcube_label('htmleditor'))), - 'content' => $select->show(intval($config['htmleditor'])), - ); - } - - if (!isset($no_override['draft_autosave'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_autosave'; - $select = new html_select(array('name' => '_draft_autosave', 'id' => $field_id, 'disabled' => empty($config['drafts_mbox']))); - - $select->add(rcube_label('never'), 0); - foreach (array(1, 3, 5, 10) as $i => $min) { - $label = rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))); - $select->add($label, $min*60); - } - - $blocks['main']['options']['draft_autosave'] = array( - 'title' => html::label($field_id, Q(rcube_label('autosavedraft'))), - 'content' => $select->show($config['draft_autosave']), - ); - } - - if (!isset($no_override['mime_param_folding'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_param_folding'; - $select = new html_select(array('name' => '_mime_param_folding', 'id' => $field_id)); - - $select->add(rcube_label('2231folding'), 0); - $select->add(rcube_label('miscfolding'), 1); - $select->add(rcube_label('2047folding'), 2); - - $blocks['main']['options']['mime_param_folding'] = array( - 'advanced' => true, - 'title' => html::label($field_id, Q(rcube_label('mimeparamfolding'))), - 'content' => $select->show($config['mime_param_folding']), - ); - } - - if (!isset($no_override['force_7bit'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_force_7bit'; - $input = new html_checkbox(array('name' => '_force_7bit', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['force_7bit'] = array( - 'advanced' => true, - 'title' => html::label($field_id, Q(rcube_label('force7bit'))), - 'content' => $input->show($config['force_7bit']?1:0), - ); - } - - if (!isset($no_override['mdn_default'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_mdn_default'; - $input = new html_checkbox(array('name' => '_mdn_default', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['mdn_default'] = array( - 'title' => html::label($field_id, Q(rcube_label('reqmdn'))), - 'content' => $input->show($config['mdn_default']?1:0), - ); - } - - if (!isset($no_override['dsn_default'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_dsn_default'; - $input = new html_checkbox(array('name' => '_dsn_default', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['dsn_default'] = array( - 'title' => html::label($field_id, Q(rcube_label('reqdsn'))), - 'content' => $input->show($config['dsn_default']?1:0), - ); - } - - if (!isset($no_override['reply_same_folder'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_reply_same_folder'; - $input = new html_checkbox(array('name' => '_reply_same_folder', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['reply_same_folder'] = array( - 'title' => html::label($field_id, Q(rcube_label('replysamefolder'))), - 'content' => $input->show($config['reply_same_folder']?1:0), - ); - } - - if (!isset($no_override['reply_mode'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_reply_mode'; - $select = new html_select(array('name' => '_reply_mode', 'id' => $field_id)); - - $select->add(rcube_label('replyempty'), -1); - $select->add(rcube_label('replybottomposting'), 0); - $select->add(rcube_label('replytopposting'), 1); - - $blocks['main']['options']['reply_mode'] = array( - 'title' => html::label($field_id, Q(rcube_label('whenreplying'))), - 'content' => $select->show(intval($config['reply_mode'])), - ); - } - - if (!isset($no_override['spellcheck_before_send']) && $config['enable_spellcheck']) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_spellcheck_before_send'; - $input = new html_checkbox(array('name' => '_spellcheck_before_send', 'id' => $field_id, 'value' => 1)); - - $blocks['spellcheck']['options']['spellcheck_before_send'] = array( - 'title' => html::label($field_id, Q(rcube_label('spellcheckbeforesend'))), - 'content' => $input->show($config['spellcheck_before_send']?1:0), - ); - } - - if ($config['enable_spellcheck']) { - if (!$current) { - continue 2; - } - - foreach (array('syms', 'nums', 'caps') as $key) { - $key = 'spellcheck_ignore_'.$key; - if (!isset($no_override[$key])) { - $input = new html_checkbox(array('name' => '_'.$key, 'id' => 'rcmfd_'.$key, 'value' => 1)); - - $blocks['spellcheck']['options'][$key] = array( - 'title' => html::label($field_id, Q(rcube_label(str_replace('_', '', $key)))), - 'content' => $input->show($config[$key]?1:0), - ); - } - } - } - - if (!isset($no_override['show_sig'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_show_sig'; - $select = new html_select(array('name' => '_show_sig', 'id' => $field_id)); - - $select->add(rcube_label('never'), 0); - $select->add(rcube_label('always'), 1); - $select->add(rcube_label('newmessageonly'), 2); - $select->add(rcube_label('replyandforwardonly'), 3); - - $blocks['sig']['options']['show_sig'] = array( - 'title' => html::label($field_id, Q(rcube_label('autoaddsignature'))), - 'content' => $select->show($RCMAIL->config->get('show_sig', 1)), - ); - } - - if (!isset($no_override['strip_existing_sig'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_strip_existing_sig'; - $input = new html_checkbox(array('name' => '_strip_existing_sig', 'id' => $field_id, 'value' => 1)); - - $blocks['sig']['options']['strip_existing_sig'] = array( - 'title' => html::label($field_id, Q(rcube_label('replyremovesignature'))), - 'content' => $input->show($config['strip_existing_sig']?1:0), - ); - } - - if (!isset($no_override['forward_attachment'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_forward_attachment'; - $select = new html_select(array('name' => '_forward_attachment', 'id' => $field_id)); - - $select->add(rcube_label('inline'), 0); - $select->add(rcube_label('asattachment'), 1); - - $blocks['main']['options']['forward_attachment'] = array( - 'title' => html::label($field_id, Q(rcube_label('forwardmode'))), - 'content' => $select->show(intval($config['forward_attachment'])), - ); - } - - if (!isset($no_override['default_font'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_default_font'; - $fonts = rcube_fontdefs(); - $selected = $config['default_font']; - - $select = '<select name="_default_font" id="'.$field_id.'">'; - $select .= '<option value=""' . (!$selected ? ' selected="selected"' : '') . '>---</option>'; - foreach ($fonts as $fname => $font) { - $select .= '<option value="'.$fname.'"' - . ($fname == $selected ? ' selected="selected"' : '') - . ' style=\'font-family: ' . $font . '\'>' - . Q($fname) . '</option>'; - } - $select .= '</select>'; - - $blocks['main']['options']['default_font'] = array( - 'title' => html::label($field_id, Q(rcube_label('defaultfont'))), - 'content' => $select - ); - } - break; - - // Addressbook config - case 'addressbook': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - ); - - if (!isset($no_override['default_addressbook']) - && (!$current || ($books = $RCMAIL->get_address_sources(true, true))) - ) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_default_addressbook'; - $select = new html_select(array('name' => '_default_addressbook', 'id' => $field_id)); - - foreach ($books as $book) { - $select->add(html_entity_decode($book['name'], ENT_COMPAT, 'UTF-8'), $book['id']); - } - - $blocks['main']['options']['default_addressbook'] = array( - 'title' => html::label($field_id, Q(rcube_label('defaultabook'))), - 'content' => $select->show($config['default_addressbook']), - ); - } - - // show addressbook listing mode selection - if (!isset($no_override['addressbook_name_listing'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_addressbook_name_listing'; - $select = new html_select(array('name' => '_addressbook_name_listing', 'id' => $field_id)); - - $select->add(rcube_label('name'), 0); - $select->add(rcube_label('firstname') . ' ' . rcube_label('surname'), 1); - $select->add(rcube_label('surname') . ' ' . rcube_label('firstname'), 2); - $select->add(rcube_label('surname') . ', ' . rcube_label('firstname'), 3); - - $blocks['main']['options']['list_name_listing'] = array( - 'title' => html::label($field_id, Q(rcube_label('listnamedisplay'))), - 'content' => $select->show($config['addressbook_name_listing']), - ); - } - - // show addressbook sort column - if (!isset($no_override['addressbook_sort_col'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_addressbook_sort_col'; - $select = new html_select(array('name' => '_addressbook_sort_col', 'id' => $field_id)); - - $select->add(rcube_label('name'), 'name'); - $select->add(rcube_label('firstname'), 'firstname'); - $select->add(rcube_label('surname'), 'surname'); - - $blocks['main']['options']['sort_col'] = array( - 'title' => html::label($field_id, Q(rcube_label('listsorting'))), - 'content' => $select->show($config['addressbook_sort_col']), - ); - } - - // show addressbook page size selection - if (!isset($no_override['addressbook_pagesize'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_addressbook_pagesize'; - $input = new html_inputfield(array('name' => '_addressbook_pagesize', 'id' => $field_id, 'size' => 5)); - $size = intval($config['addressbook_pagesize'] ? $config['addressbook_pagesize'] : $config['pagesize']); - - $blocks['main']['options']['pagesize'] = array( - 'title' => html::label($field_id, Q(rcube_label('pagesize'))), - 'content' => $input->show($size ? $size : 50), - ); - } - - if (!isset($no_override['autocomplete_single'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_autocomplete_single'; - $checkbox = new html_checkbox(array('name' => '_autocomplete_single', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['autocomplete_single'] = array( - 'title' => html::label($field_id, Q(rcube_label('autocompletesingle'))), - 'content' => $checkbox->show($config['autocomplete_single']?1:0), - ); - } - break; - - // Special IMAP folders - case 'folders': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - ); - - if (!isset($no_override['show_real_foldernames'])) { - if (!$current) { - continue 2; - } - - $field_id = 'show_real_foldernames'; - $input = new html_checkbox(array('name' => '_show_real_foldernames', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['show_real_foldernames'] = array( - 'title' => html::label($field_id, Q(rcube_label('show_real_foldernames'))), - 'content' => $input->show($config['show_real_foldernames']?1:0), - ); - } - - // Configure special folders - if (!isset($no_override['default_folders']) && $current) { - $select = rcmail_mailbox_select(array( - 'noselection' => '---', - 'realnames' => true, - 'maxlength' => 30, - 'folder_filter' => 'mail', - 'folder_rights' => 'w', - )); - } - - // #1486114, #1488279, #1489219 - $onchange = "if ($(this).val() == 'INBOX') $(this).val('')"; - - if (!isset($no_override['drafts_mbox'])) { - if (!$current) { - continue 2; - } - - $blocks['main']['options']['drafts_mbox'] = array( - 'title' => Q(rcube_label('drafts')), - 'content' => $select->show($config['drafts_mbox'], array('name' => "_drafts_mbox", 'onchange' => $onchange)), - ); - } - - if (!isset($no_override['sent_mbox'])) { - if (!$current) { - continue 2; - } - - $blocks['main']['options']['sent_mbox'] = array( - 'title' => Q(rcube_label('sent')), - 'content' => $select->show($config['sent_mbox'], array('name' => "_sent_mbox", 'onchange' => '')), - ); - } - - if (!isset($no_override['junk_mbox'])) { - if (!$current) { - continue 2; - } - - $blocks['main']['options']['junk_mbox'] = array( - 'title' => Q(rcube_label('junk')), - 'content' => $select->show($config['junk_mbox'], array('name' => "_junk_mbox", 'onchange' => $onchange)), - ); - } - - if (!isset($no_override['trash_mbox'])) { - if (!$current) { - continue 2; - } - - $blocks['main']['options']['trash_mbox'] = array( - 'title' => Q(rcube_label('trash')), - 'content' => $select->show($config['trash_mbox'], array('name' => "_trash_mbox", 'onchange' => $onchange)), - ); - } - break; - - // Server settings - case 'server': - $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - 'maintenance' => array('name' => Q(rcube_label('maintenance'))), - ); - - if (!isset($no_override['read_when_deleted'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_read_deleted'; - $input = new html_checkbox(array('name' => '_read_when_deleted', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['read_when_deleted'] = array( - 'title' => html::label($field_id, Q(rcube_label('readwhendeleted'))), - 'content' => $input->show($config['read_when_deleted']?1:0), - ); - } - - if (!isset($no_override['flag_for_deletion'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_flag_for_deletion'; - $input = new html_checkbox(array('name' => '_flag_for_deletion', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['flag_for_deletion'] = array( - 'title' => html::label($field_id, Q(rcube_label('flagfordeletion'))), - 'content' => $input->show($config['flag_for_deletion']?1:0), - ); - } - - // don't show deleted messages - if (!isset($no_override['skip_deleted'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_skip_deleted'; - $input = new html_checkbox(array('name' => '_skip_deleted', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['skip_deleted'] = array( - 'title' => html::label($field_id, Q(rcube_label('skipdeleted'))), - 'content' => $input->show($config['skip_deleted']?1:0), - ); - } - - if (!isset($no_override['delete_always'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_delete_always'; - $input = new html_checkbox(array('name' => '_delete_always', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['delete_always'] = array( - 'title' => html::label($field_id, Q(rcube_label('deletealways'))), - 'content' => $input->show($config['delete_always']?1:0), - ); - } - - if (!isset($no_override['delete_junk'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_delete_junk'; - $input = new html_checkbox(array('name' => '_delete_junk', 'id' => $field_id, 'value' => 1)); - - $blocks['main']['options']['delete_junk'] = array( - 'title' => html::label($field_id, Q(rcube_label('deletejunk'))), - 'content' => $input->show($config['delete_junk']?1:0), - ); - } - - // Trash purging on logout - if (!isset($no_override['logout_purge'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_logout_purge'; - $input = new html_checkbox(array('name' => '_logout_purge', 'id' => $field_id, 'value' => 1)); - - $blocks['maintenance']['options']['logout_purge'] = array( - 'title' => html::label($field_id, Q(rcube_label('logoutclear'))), - 'content' => $input->show($config['logout_purge']?1:0), - ); - } - - // INBOX compacting on logout - if (!isset($no_override['logout_expunge'])) { - if (!$current) { - continue 2; - } - - $field_id = 'rcmfd_logout_expunge'; - $input = new html_checkbox(array('name' => '_logout_expunge', 'id' => $field_id, 'value' => 1)); - - $blocks['maintenance']['options']['logout_expunge'] = array( - 'title' => html::label($field_id, Q(rcube_label('logoutcompact'))), - 'content' => $input->show($config['logout_expunge']?1:0), - ); - } + $blocks['main']['options']['prettydate'] = array( + 'title' => html::label($field_id, Q(rcube_label('prettydate'))), + 'content' => $input_prettydate->show($config['prettydate']?1:0), + ); + } + + if (!isset($no_override['refresh_interval'])) { + $field_id = 'rcmfd_refresh_interval'; + $select_refresh_interval = new html_select(array('name' => '_refresh_interval', 'id' => $field_id)); + + $select_refresh_interval->add(rcube_label('never'), 0); + foreach (array(1, 3, 5, 10, 15, 30, 60) as $min) { + if (!$config['min_refresh_interval'] || $config['min_refresh_interval'] <= $min * 60) { + $label = rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))); + $select_refresh_interval->add($label, $min); } + } - $found = false; - $data = $RCMAIL->plugins->exec_hook('preferences_list', - array('section' => $sect['id'], 'blocks' => $blocks, 'current' => $current)); + $blocks['main']['options']['refresh_interval'] = array( + 'title' => html::label($field_id, Q(rcube_label('refreshinterval'))), + 'content' => $select_refresh_interval->show($config['refresh_interval']/60), + ); + } - // create output - foreach ($data['blocks'] as $block) { - if (!empty($block['content']) || !empty($block['options'])) { - $found = true; - break; - } + // show drop-down for available skins + if (!isset($no_override['skin'])) { + $skins = rcmail_get_skins(); + + if (count($skins) > 1) { + $field_id = 'rcmfd_skin'; + $input_skin = new html_radiobutton(array('name'=>'_skin')); + + $blocks['skin'] = array('name' => Q(rcube_label('skin')),); + + foreach($skins as $skin) { + $thumbnail = "./skins/$skin/thumbnail.png"; + if (!is_file($thumbnail)) + $thumbnail = './program/resources/blank.gif'; + + $skinname = ucfirst($skin); + $author_link = $license_link = ''; + $meta = @json_decode(@file_get_contents("./skins/$skin/meta.json"), true); + if (is_array($meta) && $meta['name']) { + $skinname = $meta['name']; + $author_link = $meta['url'] ? html::a(array('href' => $meta['url'], 'target' => '_blank'), Q($meta['author'])) : Q($meta['author']); + $license_link = $meta['license-url'] ? html::a(array('href' => $meta['license-url'], 'target' => '_blank'), Q($meta['license'])) : Q($meta['license']); + } + + $blocks['skin']['options'][$skin]['content'] = html::label(array('class' => 'skinselection'), + html::span('skinitem', $input_skin->show($config['skin'], array('value' => $skin, 'id' => $field_id.$skin))) . + html::span('skinitem', html::img(array('src' => $thumbnail, 'class' => 'skinthumbnail', 'alt' => $skin, 'width' => 64, 'height' => 64))) . + html::span('skinitem', html::span('skinname', Q($skinname)) . html::br() . + html::span('skinauthor', $author_link ? 'by ' . $author_link : '') . html::br() . + html::span('skinlicense', $license_link ? rcube_label('license').': ' . $license_link : '')) + ); } + } + } - if (!$found) - unset($sections[$idx]); - else - $sections[$idx]['blocks'] = $data['blocks']; + $product_name = $RCMAIL->config->get('product_name', 'Roundcube Webmail'); + $RCMAIL->output->add_script(sprintf("%s.check_protocol_handler('%s', '#mailtoprotohandler');", + JS_OBJECT_NAME, JQ($product_name)), 'foot'); + + $blocks['browser'] = array( + 'name' => Q(rcube_label('browseroptions')), + 'options' => array('mailtoprotohandler' => array( + 'content' => html::a(array( + 'href' => '#', + 'id' => 'mailtoprotohandler'), Q(rcube_label('mailtoprotohandler'))), + )), + ); + + break; + + // Mailbox view (mail screen) + case 'mailbox': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'new_message' => array('name' => Q(rcube_label('newmessage'))), + ); + + // show config parameter for preview pane + if (!isset($no_override['preview_pane'])) { + $field_id = 'rcmfd_preview'; + $input_preview = new html_checkbox(array('name' => '_preview_pane', 'id' => $field_id, 'value' => 1, + 'onchange' => "$('#rcmfd_preview_pane_mark_read').prop('disabled', !this.checked)")); + + $blocks['main']['options']['preview_pane'] = array( + 'title' => html::label($field_id, Q(rcube_label('previewpane'))), + 'content' => $input_preview->show($config['preview_pane']?1:0), + ); } - return array($sections, $plugin['cols']); -} + // show config parameter for preview pane auto mark as read delay + if (!isset($no_override['preview_pane_mark_read'])) { + // apply default if config option is not set at all + $config['preview_pane_mark_read'] = $RCMAIL->config->get('preview_pane_mark_read', 0); + $field_id = 'rcmfd_preview_pane_mark_read'; + $select_delay = new html_select(array('name' => '_preview_pane_mark_read', 'id' => $field_id, + 'disabled' => $config['preview_pane']?0:1)); -function rcmail_get_skins() -{ - $path = RCUBE_INSTALL_PATH . 'skins'; - $skins = array(); - $dir = opendir($path); + $select_delay->add(rcube_label('never'), '-1'); + $select_delay->add(rcube_label('immediately'), 0); + foreach(array(5, 10, 20, 30) as $sec) + $select_delay->add(rcube_label(array('name' => 'afternseconds', 'vars' => array('n' => $sec))), $sec); + + $blocks['main']['options']['preview_pane_mark_read'] = array( + 'title' => html::label($field_id, Q(rcube_label('previewpanemarkread'))), + 'content' => $select_delay->show(intval($config['preview_pane_mark_read'])), + ); + } + + if (!isset($no_override['mdn_requests'])) { + $field_id = 'rcmfd_mdn_requests'; + $select_mdn_requests = new html_select(array('name' => '_mdn_requests', 'id' => $field_id)); + $select_mdn_requests->add(rcube_label('askuser'), 0); + $select_mdn_requests->add(rcube_label('autosend'), 1); + $select_mdn_requests->add(rcube_label('autosendknown'), 3); + $select_mdn_requests->add(rcube_label('autosendknownignore'), 4); + $select_mdn_requests->add(rcube_label('ignore'), 2); + + $blocks['main']['options']['mdn_requests'] = array( + 'title' => html::label($field_id, Q(rcube_label('mdnrequests'))), + 'content' => $select_mdn_requests->show($config['mdn_requests']), + ); + } + + $storage = $RCMAIL->get_storage(); + $threading_supported = $storage->get_capability('THREAD'); + + if (!isset($no_override['autoexpand_threads']) && $threading_supported) { + $field_id = 'rcmfd_autoexpand_threads'; + $select_autoexpand_threads = new html_select(array('name' => '_autoexpand_threads', 'id' => $field_id)); + $select_autoexpand_threads->add(rcube_label('never'), 0); + $select_autoexpand_threads->add(rcube_label('do_expand'), 1); + $select_autoexpand_threads->add(rcube_label('expand_only_unread'), 2); + + $blocks['main']['options']['autoexpand_threads'] = array( + 'title' => html::label($field_id, Q(rcube_label('autoexpand_threads'))), + 'content' => $select_autoexpand_threads->show($config['autoexpand_threads']), + ); + } + + // show page size selection + if (!isset($no_override['mail_pagesize'])) { + $field_id = 'rcmfd_mail_pagesize'; + $input_pagesize = new html_inputfield(array('name' => '_mail_pagesize', 'id' => $field_id, 'size' => 5)); + + $size = intval($config['mail_pagesize'] ? $config['mail_pagesize'] : $config['pagesize']); + + $blocks['main']['options']['pagesize'] = array( + 'title' => html::label($field_id, Q(rcube_label('pagesize'))), + 'content' => $input_pagesize->show($size ? $size : 50), + ); + } + if (!isset($no_override['check_all_folders'])) { + $field_id = 'rcmfd_check_all_folders'; + $input_check_all = new html_checkbox(array('name' => '_check_all_folders', 'id' => $field_id, 'value' => 1)); + + $blocks['new_message']['options']['check_all_folders'] = array( + 'title' => html::label($field_id, Q(rcube_label('checkallfolders'))), + 'content' => $input_check_all->show($config['check_all_folders']?1:0), + ); + } + + break; + + // Message viewing + case 'mailview': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + ); + + // show checkbox to open message view in new window + if (!isset($no_override['message_extwin'])) { + $field_id = 'rcmfd_message_extwin'; + $input_msgextwin = new html_checkbox(array('name' => '_message_extwin', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['message_extwin'] = array( + 'title' => html::label($field_id, Q(rcube_label('showinextwin'))), + 'content' => $input_msgextwin->show($config['message_extwin']?1:0), + ); + } + + // show checkbox for HTML/plaintext messages + if (!isset($no_override['prefer_html'])) { + $field_id = 'rcmfd_htmlmsg'; + $input_preferhtml = new html_checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1, + 'onchange' => "$('#rcmfd_show_images').prop('disabled', !this.checked).val(0)")); + + $blocks['main']['options']['prefer_html'] = array( + 'title' => html::label($field_id, Q(rcube_label('preferhtml'))), + 'content' => $input_preferhtml->show($config['prefer_html']?1:0), + ); + } + + if (!isset($no_override['default_charset'])) { + $field_id = 'rcmfd_default_charset'; + + $blocks['main']['options']['default_charset'] = array( + 'title' => html::label($field_id, Q(rcube_label('defaultcharset'))), + 'content' => $RCMAIL->output->charset_selector(array( + 'name' => '_default_charset', 'selected' => $config['default_charset'] + )) + ); + } + + if (!isset($no_override['show_images'])) { + $field_id = 'rcmfd_show_images'; + $input_show_images = new html_select(array('name' => '_show_images', 'id' => $field_id, + 'disabled' => !$config['prefer_html'])); + $input_show_images->add(rcube_label('never'), 0); + $input_show_images->add(rcube_label('fromknownsenders'), 1); + $input_show_images->add(rcube_label('always'), 2); + + $blocks['main']['options']['show_images'] = array( + 'title' => html::label($field_id, Q(rcube_label('showremoteimages'))), + 'content' => $input_show_images->show($config['prefer_html'] ? $config['show_images'] : 0), + ); + } + + if (!isset($no_override['inline_images'])) { + $field_id = 'rcmfd_inline_images'; + $input_inline_images = new html_checkbox(array('name' => '_inline_images', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['inline_images'] = array( + 'title' => html::label($field_id, Q(rcube_label('showinlineimages'))), + 'content' => $input_inline_images->show($config['inline_images']?1:0), + ); + } + + // "display after delete" checkbox + if (!isset($no_override['display_next'])) { + $field_id = 'rcmfd_displaynext'; + $input_displaynext = new html_checkbox(array('name' => '_display_next', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['display_next'] = array( + 'title' => html::label($field_id, Q(rcube_label('displaynext'))), + 'content' => $input_displaynext->show($config['display_next']?1:0), + ); + } + + break; + + // Mail composition + case 'compose': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'sig' => array('name' => Q(rcube_label('signatureoptions'))), + 'spellcheck' => array('name' => Q(rcube_label('spellcheckoptions'))), + ); + + // show checkbox to compose messages in a new window + if (!isset($no_override['compose_extwin'])) { + $field_id = 'rcmfdcompose_extwin'; + $input_compextwin = new html_checkbox(array('name' => '_compose_extwin', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['compose_extwin'] = array( + 'title' => html::label($field_id, Q(rcube_label('composeextwin'))), + 'content' => $input_compextwin->show($config['compose_extwin']?1:0), + ); + } + + if (!isset($no_override['htmleditor'])) { + $field_id = 'rcmfd_htmleditor'; + $select_htmleditor = new html_select(array('name' => '_htmleditor', 'id' => $field_id)); + $select_htmleditor->add(rcube_label('never'), 0); + $select_htmleditor->add(rcube_label('always'), 1); + $select_htmleditor->add(rcube_label('htmlonreply'), 2); + $select_htmleditor->add(rcube_label('htmlonreplyandforward'), 3); + + $blocks['main']['options']['htmleditor'] = array( + 'title' => html::label($field_id, Q(rcube_label('htmleditor'))), + 'content' => $select_htmleditor->show(intval($config['htmleditor'])), + ); + } + + if (!isset($no_override['draft_autosave'])) { + $field_id = 'rcmfd_autosave'; + $select_autosave = new html_select(array('name' => '_draft_autosave', 'id' => $field_id, 'disabled' => empty($config['drafts_mbox']))); + $select_autosave->add(rcube_label('never'), 0); + foreach (array(1, 3, 5, 10) as $i => $min) + $select_autosave->add(rcube_label(array('name' => 'everynminutes', 'vars' => array('n' => $min))), $min*60); + + $blocks['main']['options']['draft_autosave'] = array( + 'title' => html::label($field_id, Q(rcube_label('autosavedraft'))), + 'content' => $select_autosave->show($config['draft_autosave']), + ); + } + + if (!isset($no_override['mime_param_folding'])) { + $field_id = 'rcmfd_param_folding'; + $select_param_folding = new html_select(array('name' => '_mime_param_folding', 'id' => $field_id)); + $select_param_folding->add(rcube_label('2231folding'), 0); + $select_param_folding->add(rcube_label('miscfolding'), 1); + $select_param_folding->add(rcube_label('2047folding'), 2); + + $blocks['main']['options']['mime_param_folding'] = array( + 'advanced' => true, + 'title' => html::label($field_id, Q(rcube_label('mimeparamfolding'))), + 'content' => $select_param_folding->show($config['mime_param_folding']), + ); + } + + if (!isset($no_override['force_7bit'])) { + $field_id = 'rcmfd_force_7bit'; + $input_7bit = new html_checkbox(array('name' => '_force_7bit', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['force_7bit'] = array( + 'title' => html::label($field_id, Q(rcube_label('force7bit'))), + 'content' => $input_7bit->show($config['force_7bit']?1:0), + ); + } + + if (!isset($no_override['mdn_default'])) { + $field_id = 'rcmfd_mdn_default'; + $input_mdn = new html_checkbox(array('name' => '_mdn_default', 'id' => $field_id, 'value' => 1)); - if (!$dir) { - return false; + $blocks['main']['options']['mdn_default'] = array( + 'title' => html::label($field_id, Q(rcube_label('reqmdn'))), + 'content' => $input_mdn->show($config['mdn_default']?1:0), + ); } - while (($file = readdir($dir)) !== false) { - $filename = $path.'/'.$file; - if (!preg_match('/^\./', $file) && is_dir($filename) && is_readable($filename)) { - $skins[] = $file; + if (!isset($no_override['dsn_default'])) { + $field_id = 'rcmfd_dsn_default'; + $input_dsn = new html_checkbox(array('name' => '_dsn_default', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['dsn_default'] = array( + 'title' => html::label($field_id, Q(rcube_label('reqdsn'))), + 'content' => $input_dsn->show($config['dsn_default']?1:0), + ); + } + + if (!isset($no_override['reply_same_folder'])) { + $field_id = 'rcmfd_reply_same_folder'; + $input_reply_same_folder = new html_checkbox(array('name' => '_reply_same_folder', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['reply_same_folder'] = array( + 'title' => html::label($field_id, Q(rcube_label('replysamefolder'))), + 'content' => $input_reply_same_folder->show($config['reply_same_folder']?1:0), + ); + } + + if (!isset($no_override['reply_mode'])) { + $field_id = 'rcmfd_reply_mode'; + $select_replymode = new html_select(array('name' => '_reply_mode', 'id' => $field_id)); + $select_replymode->add(rcube_label('replyempty'), -1); + $select_replymode->add(rcube_label('replybottomposting'), 0); + $select_replymode->add(rcube_label('replytopposting'), 1); + + $blocks['main']['options']['reply_mode'] = array( + 'title' => html::label($field_id, Q(rcube_label('whenreplying'))), + 'content' => $select_replymode->show(intval($config['reply_mode'])), + ); + } + + if (!isset($no_override['spellcheck_before_send']) && $config['enable_spellcheck']) { + $field_id = 'rcmfd_spellcheck_before_send'; + $input_spellcheck = new html_checkbox(array('name' => '_spellcheck_before_send', 'id' => $field_id, 'value' => 1)); + + $blocks['spellcheck']['options']['spellcheck_before_send'] = array( + 'title' => html::label($field_id, Q(rcube_label('spellcheckbeforesend'))), + 'content' => $input_spellcheck->show($config['spellcheck_before_send']?1:0), + ); + } + + if ($config['enable_spellcheck']) { + foreach (array('syms', 'nums', 'caps') as $key) { + $key = 'spellcheck_ignore_'.$key; + if (!isset($no_override[$key])) { + $input_spellcheck = new html_checkbox(array('name' => '_'.$key, 'id' => 'rcmfd_'.$key, 'value' => 1)); + + $blocks['spellcheck']['options'][$key] = array( + 'title' => html::label($field_id, Q(rcube_label(str_replace('_', '', $key)))), + 'content' => $input_spellcheck->show($config[$key]?1:0), + ); } + } + } + + if (!isset($no_override['show_sig'])) { + $field_id = 'rcmfd_show_sig'; + $select_show_sig = new html_select(array('name' => '_show_sig', 'id' => $field_id)); + $select_show_sig->add(rcube_label('never'), 0); + $select_show_sig->add(rcube_label('always'), 1); + $select_show_sig->add(rcube_label('newmessageonly'), 2); + $select_show_sig->add(rcube_label('replyandforwardonly'), 3); + + $blocks['sig']['options']['show_sig'] = array( + 'title' => html::label($field_id, Q(rcube_label('autoaddsignature'))), + 'content' => $select_show_sig->show($RCMAIL->config->get('show_sig', 1)), + ); + } + + if (!isset($no_override['strip_existing_sig'])) { + $field_id = 'rcmfd_strip_existing_sig'; + $input_stripexistingsig = new html_checkbox(array('name' => '_strip_existing_sig', 'id' => $field_id, 'value' => 1)); + + $blocks['sig']['options']['strip_existing_sig'] = array( + 'title' => html::label($field_id, Q(rcube_label('replyremovesignature'))), + 'content' => $input_stripexistingsig->show($config['strip_existing_sig']?1:0), + ); + } + + if (!isset($no_override['forward_attachment'])) { + $field_id = 'rcmfd_forward_attachment'; + $select = new html_select(array('name' => '_forward_attachment', 'id' => $field_id)); + $select->add(rcube_label('inline'), 0); + $select->add(rcube_label('asattachment'), 1); + + $blocks['main']['options']['forward_attachment'] = array( + 'title' => html::label($field_id, Q(rcube_label('forwardmode'))), + 'content' => $select->show(intval($config['forward_attachment'])), + ); + } + + if (!isset($no_override['default_font'])) { + $field_id = 'rcmfd_default_font'; + $fonts = rcube_fontdefs(); + $selected = $config['default_font']; + + $select = '<select name="_default_font" id="'.$field_id.'">'; + $select .= '<option value=""' . (!$selected ? ' selected="selected"' : '') . '>---</option>'; + foreach ($fonts as $fname => $font) + $select .= '<option value="'.$fname.'"' + . ($fname == $selected ? ' selected="selected"' : '') + . ' style=\'font-family: ' . $font . '\'>' + . Q($fname) . '</option>'; + $select .= '</select>'; + + $blocks['main']['options']['default_font'] = array( + 'title' => html::label($field_id, Q(rcube_label('defaultfont'))), + 'content' => $select + ); + } + + break; + + + // Addressbook config + case 'addressbook': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + ); + + if (!isset($no_override['default_addressbook']) + && ($books = $RCMAIL->get_address_sources(true, true)) + ) { + $field_id = 'rcmfd_default_addressbook'; + $select_abook = new html_select(array('name' => '_default_addressbook', 'id' => $field_id)); + + foreach ($books as $book) { + $select_abook->add(html_entity_decode($book['name'], ENT_COMPAT, 'UTF-8'), $book['id']); + } + + $blocks['main']['options']['default_addressbook'] = array( + 'title' => html::label($field_id, Q(rcube_label('defaultabook'))), + 'content' => $select_abook->show($config['default_addressbook']), + ); + } + + // show addressbook listing mode selection + if (!isset($no_override['addressbook_name_listing'])) { + $field_id = 'rcmfd_addressbook_name_listing'; + $select_listing = new html_select(array('name' => '_addressbook_name_listing', 'id' => $field_id)); + $select_listing->add(rcube_label('name'), 0); + $select_listing->add(rcube_label('firstname') . ' ' . rcube_label('surname'), 1); + $select_listing->add(rcube_label('surname') . ' ' . rcube_label('firstname'), 2); + $select_listing->add(rcube_label('surname') . ', ' . rcube_label('firstname'), 3); + + $blocks['main']['options']['list_name_listing'] = array( + 'title' => html::label($field_id, Q(rcube_label('listnamedisplay'))), + 'content' => $select_listing->show($config['addressbook_name_listing']), + ); } - closedir($dir); + // show addressbook sort column + if (!isset($no_override['addressbook_sort_col'])) { + $field_id = 'rcmfd_addressbook_sort_col'; + $select_sort = new html_select(array('name' => '_addressbook_sort_col', 'id' => $field_id)); + $select_sort->add(rcube_label('name'), 'name'); + $select_sort->add(rcube_label('firstname'), 'firstname'); + $select_sort->add(rcube_label('surname'), 'surname'); + + $blocks['main']['options']['sort_col'] = array( + 'title' => html::label($field_id, Q(rcube_label('listsorting'))), + 'content' => $select_sort->show($config['addressbook_sort_col']), + ); + } + + // show addressbook page size selection + if (!isset($no_override['addressbook_pagesize'])) { + $field_id = 'rcmfd_addressbook_pagesize'; + $input_pagesize = new html_inputfield(array('name' => '_addressbook_pagesize', 'id' => $field_id, 'size' => 5)); + + $size = intval($config['addressbook_pagesize'] ? $config['addressbook_pagesize'] : $config['pagesize']); + + $blocks['main']['options']['pagesize'] = array( + 'title' => html::label($field_id, Q(rcube_label('pagesize'))), + 'content' => $input_pagesize->show($size ? $size : 50), + ); + } + + if (!isset($no_override['autocomplete_single'])) { + $field_id = 'rcmfd_autocomplete_single'; + $checkbox = new html_checkbox(array('name' => '_autocomplete_single', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['autocomplete_single'] = array( + 'title' => html::label($field_id, Q(rcube_label('autocompletesingle'))), + 'content' => $checkbox->show($config['autocomplete_single']?1:0), + ); + } + + break; + + // Special IMAP folders + case 'folders': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + ); + + // Configure special folders + if (!isset($no_override['default_folders'])) { + // load folders list only when needed + if ($current) { + $select = rcmail_mailbox_select(array( + 'noselection' => '---', + 'realnames' => true, + 'maxlength' => 30, + 'folder_filter' => 'mail', + 'folder_rights' => 'w', + // #1486114, #1488279 + 'onchange' => "if ($(this).val() == 'INBOX') $(this).val('')", + )); + } + else // dummy select + $select = new html_select(); + + if (!isset($no_override['drafts_mbox'])) + $blocks['main']['options']['drafts_mbox'] = array( + 'title' => Q(rcube_label('drafts')), + 'content' => $select->show($config['drafts_mbox'], array('name' => "_drafts_mbox")), + ); + + if (!isset($no_override['sent_mbox'])) + $blocks['main']['options']['sent_mbox'] = array( + 'title' => Q(rcube_label('sent')), + 'content' => $select->show($config['sent_mbox'], array('name' => "_sent_mbox")), + ); + + if (!isset($no_override['junk_mbox'])) + $blocks['main']['options']['junk_mbox'] = array( + 'title' => Q(rcube_label('junk')), + 'content' => $select->show($config['junk_mbox'], array('name' => "_junk_mbox")), + ); + + if (!isset($no_override['trash_mbox'])) + $blocks['main']['options']['trash_mbox'] = array( + 'title' => Q(rcube_label('trash')), + 'content' => $select->show($config['trash_mbox'], array('name' => "_trash_mbox")), + ); + } + + break; + + // Server settings + case 'server': + + $blocks = array( + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'maintenance' => array('name' => Q(rcube_label('maintenance'))), + ); + + if (!isset($no_override['read_when_deleted'])) { + $field_id = 'rcmfd_read_deleted'; + $input_readdeleted = new html_checkbox(array('name' => '_read_when_deleted', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['read_when_deleted'] = array( + 'title' => html::label($field_id, Q(rcube_label('readwhendeleted'))), + 'content' => $input_readdeleted->show($config['read_when_deleted']?1:0), + ); + } + + if (!isset($no_override['flag_for_deletion'])) { + $field_id = 'rcmfd_flag_for_deletion'; + $input_flagfordeletion = new html_checkbox(array('name' => '_flag_for_deletion', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['flag_for_deletion'] = array( + 'title' => html::label($field_id, Q(rcube_label('flagfordeletion'))), + 'content' => $input_flagfordeletion->show($config['flag_for_deletion']?1:0), + ); + } + + // don't show deleted messages + if (!isset($no_override['skip_deleted'])) { + $field_id = 'rcmfd_skip_deleted'; + $input_purge = new html_checkbox(array('name' => '_skip_deleted', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['skip_deleted'] = array( + 'title' => html::label($field_id, Q(rcube_label('skipdeleted'))), + 'content' => $input_purge->show($config['skip_deleted']?1:0), + ); + } + + if (!isset($no_override['delete_always'])) { + $field_id = 'rcmfd_delete_always'; + $input_delete_always = new html_checkbox(array('name' => '_delete_always', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['delete_always'] = array( + 'title' => html::label($field_id, Q(rcube_label('deletealways'))), + 'content' => $input_delete_always->show($config['delete_always']?1:0), + ); + } + + if (!isset($no_override['delete_junk'])) { + $field_id = 'rcmfd_delete_junk'; + $input_delete_junk = new html_checkbox(array('name' => '_delete_junk', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['delete_junk'] = array( + 'title' => html::label($field_id, Q(rcube_label('deletejunk'))), + 'content' => $input_delete_junk->show($config['delete_junk']?1:0), + ); + } + + // Trash purging on logout + if (!isset($no_override['logout_purge'])) { + $field_id = 'rcmfd_logout_purge'; + $input_purge = new html_checkbox(array('name' => '_logout_purge', 'id' => $field_id, 'value' => 1)); + + $blocks['maintenance']['options']['logout_purge'] = array( + 'title' => html::label($field_id, Q(rcube_label('logoutclear'))), + 'content' => $input_purge->show($config['logout_purge']?1:0), + ); + } + + // INBOX compacting on logout + if (!isset($no_override['logout_expunge'])) { + $field_id = 'rcmfd_logout_expunge'; + $input_expunge = new html_checkbox(array('name' => '_logout_expunge', 'id' => $field_id, 'value' => 1)); + + $blocks['maintenance']['options']['logout_expunge'] = array( + 'title' => html::label($field_id, Q(rcube_label('logoutcompact'))), + 'content' => $input_expunge->show($config['logout_expunge']?1:0), + ); + } + + break; + } + + $data = $RCMAIL->plugins->exec_hook('preferences_list', array('section' => $sect['id'], 'blocks' => $blocks)); + $found = false; + + // create output + foreach ($data['blocks'] as $block) { + if (!empty($block['content']) || !empty($block['options'])) { + $found = true; + break; + } + } + + if (!$found) + unset($sections[$idx]); + else + $sections[$idx]['blocks'] = $data['blocks']; + } + + return array($sections, $plugin['cols']); +} + + +function rcmail_get_skins() +{ + $path = 'skins'; + $skins = array(); + + $dir = opendir($path); + + if (!$dir) + return false; + + while (($file = readdir($dir)) !== false) + { + $filename = $path.'/'.$file; + if (!preg_match('/^\./', $file) && is_dir($filename) && is_readable($filename)) + $skins[] = $file; + } + + closedir($dir); - return $skins; + return $skins; } @@ -1238,9 +977,9 @@ function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class // register UI objects $OUTPUT->add_handlers(array( - 'prefsframe' => 'rcmail_preferences_frame', - 'sectionslist' => 'rcmail_sections_list', - 'identitieslist' => 'rcmail_identities_list', + 'prefsframe' => 'rcmail_preferences_frame', + 'sectionslist' => 'rcmail_sections_list', + 'identitieslist' => 'rcmail_identities_list', )); // register action aliases diff --git a/program/steps/settings/responses.inc b/program/steps/settings/responses.inc new file mode 100644 index 000000000..cfc4148c3 --- /dev/null +++ b/program/steps/settings/responses.inc @@ -0,0 +1,128 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/settings/responses.inc | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Manage and save canned response texts | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + + +if (!empty($_POST['_insert'])) { + $name = trim(get_input_value('_name', RCUBE_INPUT_POST)); + $text = trim(get_input_value('_text', RCUBE_INPUT_POST)); + + if (!empty($name) && !empty($text)) { + $dupes = 0; + $responses = $RCMAIL->get_compose_responses(false, true); + foreach ($responses as $resp) { + if (strcasecmp($name, preg_replace('/\s\(\d+\)$/', '', $resp['name'])) == 0) + $dupes++; + } + if ($dupes) { // require a unique name + $name .= ' (' . ++$dupes . ')'; + } + + $response = array('name' => $name, 'text' => $text, 'format' => 'text', 'key' => substr(md5($name), 0, 16)); + $responses[] = $response; + + if ($RCMAIL->user->save_prefs(array('compose_responses' => $responses))) { + $RCMAIL->output->command('add_response_item', $response); + $RCMAIL->output->command('display_message', rcube_label('successfullysaved'), 'confirmation'); + } + else { + $RCMAIL->output->command('display_message', rcube_label('errorsaving'), 'error'); + } + } + + // send response + $RCMAIL->output->send(); +} + + +if ($RCMAIL->action == 'delete-response') { + if ($key = get_input_value('_key', RCUBE_INPUT_GPC)) { + $responses = $RCMAIL->get_compose_responses(false, true); + foreach ($responses as $i => $response) { + if (empty($response['key'])) + $response['key'] = substr(md5($response['name']), 0, 16); + if ($response['key'] == $key) { + unset($responses[$i]); + $deleted = $RCMAIL->user->save_prefs(array('compose_responses' => $responses)); + break; + } + } + } + + if ($deleted) { + $RCMAIL->output->command('display_message', rcube_label('deletedsuccessfully'), 'confirmation'); + $RCMAIL->output->command('remove_response', $key); + } + + if ($RCMAIL->output->ajax_call) { + $RCMAIL->output->send(); + } +} + + +$OUTPUT->set_pagetitle(rcube_label('responses')); +$OUTPUT->include_script('list.js'); + + +/** + * + */ +function rcmail_responses_list($attrib) +{ + global $RCMAIL, $OUTPUT; + + $attrib += array('id' => 'rcmresponseslist', 'tagname' => 'table', 'cols' => 1); + + $plugin = $RCMAIL->plugins->exec_hook('responses_list', array( + 'list' => $RCMAIL->get_compose_responses(true), + 'cols' => array('name') + )); + + $out = rcube_table_output($attrib, $plugin['list'], $plugin['cols'], 'key'); + + // set client env + $OUTPUT->add_gui_object('responseslist', $attrib['id']); + $OUTPUT->set_env('readonly_responses', array_values(array_map(function($rec){ return $rec['key']; }, + array_filter($plugin['list'], function($item){ return !empty($item['static']); })))); + + return $out; +} + + +// similar function as /steps/addressbook/func.inc::rcmail_contact_frame() +function rcmail_response_frame($attrib) +{ + global $OUTPUT; + + if (!$attrib['id']) { + $attrib['id'] = 'rcmResponseFrame'; + } + + $OUTPUT->set_env('contentframe', $attrib['id']); + return $OUTPUT->frame($attrib, true); +} + +$OUTPUT->add_handlers(array( + 'responseframe' => 'rcmail_response_frame', + 'responseslist' => 'rcmail_responses_list', +)); +$OUTPUT->add_label('deleteresponseconfirm'); + +$OUTPUT->send('responses'); diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index 3e8b1d17e..945005d39 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -34,7 +34,6 @@ switch ($CURR_SECTION) 'time_format' => isset($_POST['_time_format']) ? get_input_value('_time_format', RCUBE_INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'), 'prettydate' => isset($_POST['_pretty_date']) ? TRUE : FALSE, 'refresh_interval' => isset($_POST['_refresh_interval']) ? intval($_POST['_refresh_interval'])*60 : $CONFIG['refresh_interval'], - 'standard_windows' => isset($_POST['_standard_windows']) ? TRUE : FALSE, 'skin' => isset($_POST['_skin']) ? get_input_value('_skin', RCUBE_INPUT_POST) : $CONFIG['skin'], ); @@ -61,7 +60,6 @@ switch ($CURR_SECTION) case 'mailview': $a_user_prefs = array( 'message_extwin' => intval($_POST['_message_extwin']), - 'message_show_email' => isset($_POST['_message_show_email']) ? TRUE : FALSE, 'prefer_html' => isset($_POST['_prefer_html']) ? TRUE : FALSE, 'inline_images' => isset($_POST['_inline_images']) ? TRUE : FALSE, 'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0, @@ -120,8 +118,6 @@ switch ($CURR_SECTION) case 'folders': $a_user_prefs = array( - 'show_real_foldernames' => - isset($_POST['_show_real_foldernames']) ? TRUE : FALSE, 'drafts_mbox' => get_input_value('_drafts_mbox', RCUBE_INPUT_POST, true), 'sent_mbox' => get_input_value('_sent_mbox', RCUBE_INPUT_POST, true), 'junk_mbox' => get_input_value('_junk_mbox', RCUBE_INPUT_POST, true), diff --git a/program/steps/utils/save_pref.inc b/program/steps/utils/save_pref.inc index 7def8733d..7c30be71b 100644 --- a/program/steps/utils/save_pref.inc +++ b/program/steps/utils/save_pref.inc @@ -5,7 +5,7 @@ | program/steps/utils/save_pref.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -19,16 +19,26 @@ +-----------------------------------------------------------------------+ */ -$name = get_input_value('_name', RCUBE_INPUT_POST); -$value = get_input_value('_value', RCUBE_INPUT_POST); +$name = get_input_value('_name', RCUBE_INPUT_POST); +$value = get_input_value('_value', RCUBE_INPUT_POST); +$sessname = get_input_value('_session', RCUBE_INPUT_POST); + +// Whitelisted preferences and session variables, others +// can be added by plugins $whitelist = array( 'preview_pane', 'list_cols', 'collapsed_folders', 'collapsed_abooks', ); +$whitelist_sess = array( + 'list_attrib/columns', +); + +$whitelist = array_merge($whitelist, $RCMAIL->plugins->allowed_prefs); +$whitelist_sess = array_merge($whitelist_sess, $RCMAIL->plugins->allowed_session_prefs); -if (!in_array($name, array_merge($whitelist, $RCMAIL->plugins->allowed_prefs))) { +if (!in_array($name, $whitelist) || ($sessname && !in_array($sessname, $whitelist_sess))) { raise_error(array('code' => 500, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => sprintf("Hack attempt detected (user: %s)", $RCMAIL->get_user_name())), @@ -42,7 +52,7 @@ if (!in_array($name, array_merge($whitelist, $RCMAIL->plugins->allowed_prefs))) $RCMAIL->user->save_prefs(array($name => $value)); // update also session if requested -if ($sessname = get_input_value('_session', RCUBE_INPUT_POST)) { +if ($sessname) { // Support multidimensional arrays... $vars = explode('/', $sessname); @@ -57,5 +67,3 @@ if ($sessname = get_input_value('_session', RCUBE_INPUT_POST)) { $OUTPUT->reset(); $OUTPUT->send(); - - diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index 1c68e8328..a0dd35d27 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -42,13 +42,6 @@ else { $result = $spellchecker->get_xml(); } -if ($err = $spellchecker->error()) { - rcube::raise_error(array('code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Spell check engine error: " . trim($err)), - true, false); -} - // set response length header("Content-Length: " . strlen($result)); diff --git a/program/steps/utils/spell_html.inc b/program/steps/utils/spell_html.inc index 96b41e230..861e4ba48 100644 --- a/program/steps/utils/spell_html.inc +++ b/program/steps/utils/spell_html.inc @@ -46,11 +46,6 @@ else if ($request['method'] == 'learnWord') { } if ($error = $spellchecker->error()) { - rcube::raise_error(array('code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => sprintf("Spell check engine error: " . $error)), - true, false); - echo '{"error":{"errstr":"' . addslashes($error) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}'; exit; } |