From 76507f7c63a660742e76889ad6e3919f3dde3bb0 Mon Sep 17 00:00:00 2001 From: Vincent Bernat <bernat@luffy.cx> Date: Fri, 23 Dec 2011 22:03:08 +0100 Subject: [PATCH] Imported Upstream version 0.7 --- CHANGELOG | 166 +- INSTALL | 2 +- INSTALL.orig | 233 +++ SQL/mssql.initial.sql | 177 +- SQL/mssql.upgrade.sql | 134 ++ SQL/mysql.initial.sql | 105 +- SQL/mysql.update.sql | 68 + SQL/postgres.initial.sql | 107 +- SQL/postgres.update.sql | 69 + SQL/sqlite.initial.sql | 103 +- SQL/sqlite.update.sql | 69 + bin/indexcontacts.sh | 6 +- bin/installto.sh | 6 +- bin/jsshrink.sh | 13 +- config/db.inc.php.dist | 18 +- config/main.inc.php.dist | 76 +- index.php | 17 +- installer/rcube_install.php | 43 +- installer/test.php | 20 +- plugins/acl/acl.js | 5 +- plugins/acl/acl.php | 17 +- plugins/acl/skins/default/acl.css | 6 + plugins/archive/archive.js | 4 +- plugins/archive/archive.php | 2 +- plugins/archive/localization/fr_FR.inc | 2 +- plugins/archive/package.xml | 14 +- plugins/enigma/README | 2 +- .../{config.inc.php => config.inc.php.dist} | 0 plugins/enigma/lib/enigma_ui.php | 3 - .../http_authentication.php | 2 +- plugins/managesieve/Changelog | 32 + plugins/managesieve/config.inc.php.dist | 14 + plugins/managesieve/lib/rcube_sieve.php | 106 +- .../managesieve/lib/rcube_sieve_script.php | 706 +++++-- plugins/managesieve/localization/de_CH.inc | 93 +- plugins/managesieve/localization/de_DE.inc | 97 +- plugins/managesieve/localization/en_US.inc | 71 +- plugins/managesieve/localization/es_ES.inc | 28 +- plugins/managesieve/localization/lv_LV.inc | 92 + plugins/managesieve/localization/pl_PL.inc | 71 +- plugins/managesieve/localization/pt_BR.inc | 2 +- plugins/managesieve/managesieve.js | 816 +++++--- plugins/managesieve/managesieve.php | 1243 +++++++++--- plugins/managesieve/package.xml | 100 + .../managesieve/skins/default/images/add.png | Bin 0 -> 280 bytes .../managesieve/skins/default/images/del.png | Bin 0 -> 247 bytes .../skins/default/images/down_small.gif | Bin 0 -> 106 bytes .../skins/default/images/filter.png | Bin 0 -> 547 bytes .../skins/default/images/up_small.gif | Bin 0 -> 106 bytes .../managesieve/skins/default/managesieve.css | 278 +-- .../skins/default/managesieve_mail.css | 63 + .../skins/default/managesieve_toolbar.png | Bin 12093 -> 0 bytes .../skins/default/templates/filteredit.html | 7 +- .../skins/default/templates/managesieve.html | 73 +- plugins/managesieve/tests/parser.phpt | 90 +- plugins/managesieve/tests/parser_body.phpt | 49 + .../managesieve/tests/parser_imapflags.phpt | 28 + plugins/managesieve/tests/parser_include.phpt | 30 + plugins/managesieve/tests/parser_kep14.phpt | 19 + plugins/managesieve/tests/parser_prefix.phpt | 25 + .../managesieve/tests/parser_relational.phpt | 25 + .../managesieve/tests/parser_vacation.phpt | 39 + .../managesieve/tests/parser_variables.phpt | 39 + .../managesieve/tests/parset_subaddress.phpt | 38 + .../new_user_dialog/localization/bg_BG.inc | 7 + plugins/newmail_notifier/config.inc.php.dist | 3 + .../newmail_notifier/localization/de_CH.inc | 13 + .../newmail_notifier/localization/de_DE.inc | 13 + .../newmail_notifier/localization/en_US.inc | 9 +- .../newmail_notifier/localization/lv_LV.inc | 13 + .../newmail_notifier/localization/pl_PL.inc | 9 +- .../newmail_notifier/localization/pt_BR.inc | 13 + .../newmail_notifier/localization/ru_RU.inc | 21 + plugins/newmail_notifier/mail.png | Bin 0 -> 1408 bytes plugins/newmail_notifier/newmail_notifier.js | 60 +- plugins/newmail_notifier/newmail_notifier.php | 78 +- plugins/password/config.inc.php.dist | 4 + plugins/password/drivers/ldap.php | 1 + plugins/password/drivers/ldap_simple.php | 1 + plugins/password/drivers/sql.php | 46 +- plugins/password/package.xml | 36 +- plugins/password/password.php | 6 +- plugins/userinfo/localization/fr_FR.inc | 9 + plugins/userinfo/localization/ro_RO.inc | 9 + program/include/clisetup.php | 4 +- program/include/iniset.php | 4 +- program/include/main.inc | 285 +-- program/include/rcmail.php | 102 +- program/include/rcmail.php.orig | 1716 +++++++++++++++++ program/include/rcube_addressbook.php | 30 +- program/include/rcube_browser.php | 26 +- program/include/rcube_cache.php | 61 +- program/include/rcube_config.php | 34 +- program/include/rcube_contacts.php | 121 +- program/include/rcube_html_page.php | 2 +- program/include/rcube_imap.php | 1559 +++++++-------- program/include/rcube_imap_cache.php | 1212 ++++++++++++ program/include/rcube_imap_generic.php | 722 ++++--- program/include/rcube_json_output.php | 2 +- program/include/rcube_ldap.php | 927 ++++++--- program/include/rcube_mdb2.php | 72 +- program/include/rcube_message.php | 23 +- program/include/rcube_mime_struct.php | 88 +- program/include/rcube_plugin.php | 9 +- program/include/rcube_plugin_api.php | 13 +- program/include/rcube_result_set.php | 5 +- program/include/rcube_session.php | 31 +- program/include/rcube_shared.inc | 71 +- program/include/rcube_smtp.php | 14 +- program/include/rcube_spellchecker.php | 240 ++- program/include/rcube_string_replacer.php | 4 +- program/include/rcube_template.php | 26 +- program/include/rcube_user.php | 134 +- program/include/rcube_vcard.php | 2 +- program/js/app.js | 418 ++-- program/js/app.js.src | 855 +++++--- program/js/common.js | 39 +- program/js/common.js.src | 119 +- program/js/editor.js | 23 +- program/js/googiespell.js | 69 +- program/js/googiespell.js.src | 247 ++- program/js/list.js | 74 +- program/js/list.js.src | 28 +- program/lib/html2text.php | 96 +- program/lib/washtml.php | 61 +- program/localization/ar_SA/labels.inc | 26 +- program/localization/ar_SA/messages.inc | 15 +- program/localization/bg_BG/labels.inc | 55 +- program/localization/bg_BG/messages.inc | 35 +- program/localization/ca_ES/labels.inc | 2 +- program/localization/ca_ES/messages.inc | 2 +- program/localization/cs_CZ/labels.inc | 33 +- program/localization/cs_CZ/messages.inc | 29 +- program/localization/cy_GB/labels.inc | 20 +- program/localization/cy_GB/messages.inc | 11 +- program/localization/da_DK/labels.inc | 125 +- program/localization/da_DK/messages.inc | 26 +- program/localization/de_CH/labels.inc | 10 +- program/localization/de_CH/messages.inc | 5 +- program/localization/de_DE/labels.inc | 51 +- program/localization/de_DE/messages.inc | 14 +- program/localization/en_GB/labels.inc | 9 +- program/localization/en_GB/messages.inc | 3 +- program/localization/en_US/labels.inc | 36 +- program/localization/en_US/messages.inc | 15 +- program/localization/es_ES/labels.inc | 32 +- program/localization/es_ES/messages.inc | 20 +- program/localization/et_EE/messages.inc | 4 +- program/localization/fr_FR/labels.inc | 30 +- program/localization/fr_FR/messages.inc | 21 +- program/localization/gl_ES/labels.inc | 142 +- program/localization/gl_ES/messages.inc | 189 +- program/localization/he_IL/labels.inc | 22 +- program/localization/he_IL/messages.inc | 13 +- program/localization/hr_HR/messages.inc | 4 +- program/localization/hu_HU/labels.inc | 47 +- program/localization/hu_HU/messages.inc | 48 +- program/localization/id_ID/messages.inc | 4 +- program/localization/it_IT/labels.inc | 27 +- program/localization/it_IT/messages.inc | 15 +- program/localization/ja_JP/labels.inc | 15 +- program/localization/ja_JP/messages.inc | 6 +- program/localization/ka_GE/labels.inc | 126 +- program/localization/ka_GE/messages.inc | 21 +- program/localization/lt_LT/labels.inc | 29 +- program/localization/lt_LT/messages.inc | 15 +- program/localization/lv_LV/labels.inc | 2 +- program/localization/lv_LV/messages.inc | 2 +- program/localization/nl_NL/labels.inc | 42 +- program/localization/nl_NL/messages.inc | 181 +- program/localization/nn_NO/labels.inc | 82 +- program/localization/pl_PL/labels.inc | 30 +- program/localization/pl_PL/messages.inc | 18 +- program/localization/pt_BR/labels.inc | 21 +- program/localization/pt_BR/messages.inc | 49 +- program/localization/pt_PT/labels.inc | 22 +- program/localization/pt_PT/messages.inc | 19 +- program/localization/ru_RU/labels.inc | 2 +- program/localization/ru_RU/messages.inc | 2 +- program/localization/sk_SK/labels.inc | 4 +- program/localization/sk_SK/messages.inc | 4 +- program/localization/sl_SI/labels.inc | 28 +- program/localization/sl_SI/messages.inc | 21 +- program/localization/sv_SE/labels.inc | 19 +- program/localization/sv_SE/messages.inc | 13 +- program/localization/tr_TR/labels.inc | 2 +- program/localization/tr_TR/messages.inc | 2 +- program/localization/uk_UA/labels.inc | 32 +- program/localization/uk_UA/messages.inc | 23 +- program/localization/zh_CN/labels.inc | 108 +- program/localization/zh_CN/messages.inc | 23 +- program/steps/addressbook/copy.inc | 4 +- program/steps/addressbook/export.inc | 1 - program/steps/addressbook/func.inc | 82 +- program/steps/addressbook/import.inc | 4 +- program/steps/addressbook/list.inc | 7 +- program/steps/addressbook/mailto.inc | 34 +- program/steps/addressbook/save.inc | 12 +- program/steps/addressbook/search.inc | 79 +- program/steps/addressbook/upload_photo.inc | 2 +- program/steps/mail/addcontact.inc | 16 +- program/steps/mail/attachments.inc | 31 +- program/steps/mail/autocomplete.inc | 81 +- program/steps/mail/check_recent.inc | 30 +- program/steps/mail/compose.inc | 283 +-- program/steps/mail/folders.inc | 4 +- program/steps/mail/func.inc | 89 +- program/steps/mail/get.inc | 65 +- program/steps/mail/list.inc | 9 +- program/steps/mail/mark.inc | 4 +- program/steps/mail/move_del.inc | 6 +- program/steps/mail/search.inc | 28 +- program/steps/mail/sendmail.inc | 152 +- program/steps/mail/show.inc | 78 +- program/steps/settings/edit_folder.inc | 9 +- program/steps/settings/edit_identity.inc | 4 +- program/steps/settings/folders.inc | 8 +- program/steps/settings/func.inc | 69 +- program/steps/settings/save_folder.inc | 2 +- program/steps/settings/save_prefs.inc | 18 +- program/steps/utils/killcache.inc | 18 +- program/steps/utils/spell.inc | 15 +- program/steps/utils/spell_html.inc | 6 +- skins/default/addressbook.css | 10 +- skins/default/common.css | 37 +- skins/default/editor_content.css | 9 +- skins/default/functions.js | 173 +- skins/default/ie6hacks.css | 11 +- skins/default/images/icons/folders.gif | Bin 2430 -> 2568 bytes skins/default/images/icons/folders.png | Bin 4771 -> 4957 bytes skins/default/images/messageicons.gif | Bin 1687 -> 1998 bytes skins/default/images/messageicons.png | Bin 2354 -> 4062 bytes skins/default/includes/messagetoolbar.html | 2 +- skins/default/mail.css | 57 +- skins/default/print.css | 4 +- skins/default/templates/addressbook.html | 4 +- skins/default/templates/mail.html | 1 + skins/default/templates/message.html | 3 +- skins/default/templates/messagepreview.html | 2 +- 239 files changed, 14175 insertions(+), 5173 deletions(-) create mode 100644 INSTALL.orig rename plugins/enigma/{config.inc.php => config.inc.php.dist} (100%) create mode 100644 plugins/managesieve/localization/lv_LV.inc create mode 100644 plugins/managesieve/package.xml create mode 100644 plugins/managesieve/skins/default/images/add.png create mode 100644 plugins/managesieve/skins/default/images/del.png create mode 100644 plugins/managesieve/skins/default/images/down_small.gif create mode 100644 plugins/managesieve/skins/default/images/filter.png create mode 100644 plugins/managesieve/skins/default/images/up_small.gif create mode 100644 plugins/managesieve/skins/default/managesieve_mail.css delete mode 100644 plugins/managesieve/skins/default/managesieve_toolbar.png create mode 100644 plugins/managesieve/tests/parser_body.phpt create mode 100644 plugins/managesieve/tests/parser_imapflags.phpt create mode 100644 plugins/managesieve/tests/parser_include.phpt create mode 100644 plugins/managesieve/tests/parser_kep14.phpt create mode 100644 plugins/managesieve/tests/parser_prefix.phpt create mode 100644 plugins/managesieve/tests/parser_relational.phpt create mode 100644 plugins/managesieve/tests/parser_vacation.phpt create mode 100644 plugins/managesieve/tests/parser_variables.phpt create mode 100644 plugins/managesieve/tests/parset_subaddress.phpt create mode 100644 plugins/new_user_dialog/localization/bg_BG.inc create mode 100644 plugins/newmail_notifier/localization/de_CH.inc create mode 100644 plugins/newmail_notifier/localization/de_DE.inc create mode 100644 plugins/newmail_notifier/localization/lv_LV.inc create mode 100644 plugins/newmail_notifier/localization/pt_BR.inc create mode 100644 plugins/newmail_notifier/localization/ru_RU.inc create mode 100644 plugins/newmail_notifier/mail.png create mode 100644 plugins/userinfo/localization/fr_FR.inc create mode 100644 plugins/userinfo/localization/ro_RO.inc create mode 100644 program/include/rcmail.php.orig create mode 100644 program/include/rcube_imap_cache.php diff --git a/CHANGELOG b/CHANGELOG index f4daec4..c872df3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,96 +1,80 @@ CHANGELOG Roundcube Webmail =========================== -- Fix bug where the last identity is used on reply (#1488101) -- Fix locked folder rename option on servers supporting RFC2086 only (#1488089) -- Fix encoding of LDAP contacts identifiers (#1488079) -- Fix session race conditions when composing new messages -- jQuery 1.6.4 -- Fix handling of binary attachments encoded with quoted-printable (#1488065) -- Fix text-overflow:ellipsis issues on messages list in FF7 and Webkit (#1488061) -- Fix handling of links with IP address -- Fix bug where message list filter was reset on folder compacting (#1488076) +RELEASE 0.7 +----------- +- Make Roundcube render the Email Standards Project Acid Test correctly +- Replace prompt() with jQuery UI dialog (#1485135) +- Fix navigation in messages search results +- Improved handling of some malformed values encoded with quoted-printable (#1488232) +- Add possibility to do LDAP bind before searching for bind DN +- Fix handling of empty <U> tags in HTML messages (#1488225) +- Add content filter for embedded attachments to protect from XSS on IE (#1487895) +- Use strpos() instead of strstr() when possible (#1488211) +- Fix handling HTML entities when converting HTML to text (#1488212) +- Fix fit_string_to_size() renders browser and ui unresponsive (#1488207) +- Fix handling of invalid characters in request (#1488124) +- Fix merging some configuration options in update.sh script (#1485864) +- Fix so TEXT key will remove all HEADER keys in IMAP SEARCH (#1488208) +- Fix handling contact photo url with https:// prefix (#1488202) +- Fix possible infinite redirect on attachment preview (#1488199) +- Improved clickjacking protection for browsers which don't support X-Frame-Options headers +- Fixed bug where similiar folder names were highlighted wrong (#1487860) +- Fixed bug in handling link with '!' character in it (#1488195) +- Fixed bug where session ID's length was limited to 40 characters (#1488196) +- TinyMCE security issue: removed moxieplayer (embedding flv and mp4 is not supported anymore) -RELEASE 0.6-RC --------------- -- jQuery 1.6.3 -- Fallback to mail_domain in LDAP variable replacements; added 'host' to 'user_create' hook arguments (#1488024) -- Fixed wrong vCard type parameter mobile (#1488067) -- Fixed vCard WORKFAX issue (#1488046) -- Add vCard's Profile URL support (#1488062) -- Fix imap_cache setting to values other than 'db' (#1488060) -- Fix handling of attachments inside message/rfc822 parts (#1488026) -- Make list of mimetypes that open in preview window configurable (#1487625) -- Added plugin hook 'message_part_get' for attachment downloads -- Fixed selecting identity on reply/forward (#1487981) -- Fix image type check for contact photo uploads - -RELEASE 0.6-beta +RELEASE 0.7-beta ---------------- -- Added unique connection identifier to IMAP debug messages -- Add option to hide selected LDAP addressbook on the list -- Add client-side checking of uploaded files size -- Add newlines between organization, department, jobtitle (#1488028) -- Recalculate date when replying to a message and localize the cite header (#1487675) -- Fix handling of email addresses with quoted local part (#1487939) -- Fix EOL character in vCard exports (#1487873) -- Added optional "multithreading" autocomplete feature -- Plugin API: Added 'config_get' hook -- Fixed new_user_identity plugin to work with updated rcube_ldap class (#1487994) -- Plugin API: added folder_delete and folder_rename hooks -- Added possibility to undo last contact delete operation -- Fix sorting of contact groups after group create (#1487747) -- Add optional textual upload progress indicator (#1486039) -- Fix parsing URLs containing commas (#1487970) -- Added vertical splitter for books/groups list in addressbook (#1487923) -- Improved namespace roots handling in folder manager -- Added searching in all addressbook sources -- Added addressbook source selection in contacts import -- Implement LDAPv3 Virtual List View (VLV) for paged results listing -- Use 'address_template' config option when adding a new address block (#1487944) -- Added addressbook advanced search -- Add popup with basic fields selection for addressbook search -- Case-insensitive matching in autocompletion (#1487933) -- Added option to force spellchecking before sending a message (#1485458) -- Fix handling of "<" character in contact data, search fields and folder names (#1487864) -- Fix saving "<" character in identity name and organization fields (#1487864) -- Added option to specify to which address book add new contacts -- Added plugin hook for keep-alive requests -- Store user preferences in session when write-master is not available and session is stored in memcache, write them later -- Improve performence of folder manager operations -- Fix default_port option handling in Installer when config.inc.php file exists (#1487925) -- Removed option focus_on_new_message, added newmail_notifier plugin -- Added general rcube_cache class with Memcache and APC support -- Improved caching performance by skipping writes of unchanged data -- Option enable_caching replaced by imap_cache and messages_cache options -- Fix WORKFAX saving in address book (#1487910) -- Add forward-as-attachment feature -- jQuery-1.6.2 (#1487913, #1487144) -- Improve display name composition when saving contacts (#1487143) -- Fix problems with subfolders of INBOX folder on some IMAP servers (#1487725) -- Fix handling of folders that doesn't belong to any namespace (#1487637) -- Enable multiselection for attachments uploading in capable browsers (#1485969) -- Add possibility to change HTML editor configuration by skin -- Fix a bug where selecting too many contacts would produce too large URI request (#1487892) -- Improve performance by including files with absolute path (#1487849) -- Move folder name truncation to client/skin (#1485412) -- Added plugin hook for request token creation -- Replace LDAP vars in group queries (#1487837) -- Fix vcard folding with uncode characters (#1487868) -- Keep all submitted data if contact form validation fails (#1487865) -- Handle uncode strings in rcube_addressbook::normalize_string() (#1487866) -- Fix handling of debug_level=4 in ajax requests (#1487831) -- Enable TinyMCE's contextmenu (#1487014) -- Allow multiple concurrent compose sessions -- New config option for custom logo -- Allow skins to define/override texts with <roundcube:label /> -- Add simple ACL rights/namespace handling in folder manager -- Force IE to send referers (#1487806) -- Better display of vcard import results (#1485457) -- Improved vcard import -- Interactive update script with improved DB schema check -- Fix problem with contactgroupmembers table creation on MySQL 4.x, add index on contact_id column -- Add LDAP SASL bind and proxy authentication (#1486692) -- Replying to a sent message puts the old recipient as the new recipient (#1487074) -- Fulltext search over (almost) all data for contacts -- Extend address book with rich contact information +- Fix handling of HTML form elements in messages (#1485137) +- Fix regression in setting recipient to self when replying to a Sent message (#1487074) +- Fix listing of folders in hidden namespaces (#1486796) +- Don't consider \Noselect flag when building folders tree (#1488004) +- Fix sorting autocomplete results (#1488084) +- Add option to set session name (#1486433) +- Add option to skip alternative email addresses in autocompletion +- Fix inconsistent behaviour of Compose button in Drafts folder, add Edit button for drafts +- Fix problem with parsing HTML message body with non-unicode characters (#1487813) +- Add option to define matching method for addressbook search (#1486564, #1487907) +- Make email recipients separator configurable +- Fix so folders with \Noinferiors attribute aren't listed in parent selector +- Fix handling of curly brackets in URLs (#1488168) +- Fix handling of dates (birthday/anniversary) in contact data (#1488147) +- Fix error on opening searched LDAP contact (#1488144) +- Fix redundant line break in flowed format (#1488146) +- Fix IDN address validation issue (#1488137) +- Fix JS error when dst_active checkbox doesn't exist (#1488133) +- Autocomplete LDAP records when adding contacts from mail (#1488073) +- Plugin API: added 'ready' hook (#1488063) +- Ignore DSN request when it isn't supported by SMTP server (#1487800) +- Make sure LDAP name fields aren't arrays (#1488108) +- Fixed imap test to non-default port when using ssl (#1488118) +- Force all files to be overwritten when updating (#1488117) +- Fix issue where it wasn't possible to change list view mode in folder manager for INBOX (#1488107) +- Fix namespace handling in special folders settings (#1488112) +- Disable time limit for CLI scripts (#1488109) +- Fix misleading display when chaning editor type (#1488104) +- Add loading indicator on contact delete +- Fix bug where after delete message rows can be added to the list of another folder (#1487752) +- Add notice on autocompletion that not all records were displayed +- Add option 'searchonly' for LDAP address books +- Add Priority filter to the messages list +- Cache synchronization using QRESYNC/CONDSTORE +- Trigger 'new_messages' hook for all checked folders (#1488083) +- Make date/time format user configurable; drop 'date_today' config option +- Fix setting title for truncated subject in IE (#1487128) +- Fix displaying multipart/alternative messages with only one part (#1487938) +- Rewritten messages caching: + Indexes are stored in a separate table, so there's no need to store all messages in a folder + Added threads data caching + Flags are stored separately, so flag change doesn't cause DELETE+INSERT, just UPDATE +- Improved FETCH response handling +- Improvements in response tokenization method +- Use 'From' and 'To' labels instead of 'Sender' and 'Recipient' +- Fix username case-insensitivity issue in MySQL (#1488021) +- Addressbook Saved Searches +- Added spellchecker exceptions dictionary (shared or per-user) +- Added possibility to ignore words containing caps, numbers, symbols (spellcheck_ignore_* options) +- Added 'priority' column on messages list (#1486782) +- Localize forwarded message header (#1488058) + diff --git a/INSTALL b/INSTALL index 9b07b2b..3fc6f5d 100644 --- a/INSTALL +++ b/INSTALL @@ -9,7 +9,7 @@ wiki page at http://trac.roundcube.net/wiki REQUIREMENTS ============ -* The Apache or Lighttpd Webserver +* The Apache, Lighttpd, Cherokee or Hiawatha web server * .htaccess support allowing overrides for DirectoryIndex * PHP Version 5.2.1 or greater including - PCRE, DOM, JSON, XML, Session, Sockets (required) diff --git a/INSTALL.orig b/INSTALL.orig new file mode 100644 index 0000000..493baf7 --- /dev/null +++ b/INSTALL.orig @@ -0,0 +1,233 @@ +INTRODUCTION +============ + +This file describes the basic steps to install Roundcube Webmail on your +web server. For additional information, please also consult the project's +wiki page at http://trac.roundcube.net/wiki + + +REQUIREMENTS +============ + +* The Apache, Lighttpd, Cherokee or Hiawatha web server +* .htaccess support allowing overrides for DirectoryIndex +* PHP Version 5.2.1 or greater including + - PCRE, DOM, JSON, XML, Session, Sockets (required) + - libiconv (recommended) + - mbstring, fileinfo, mcrypt (optional) +* PEAR packages distributed with Roundcube or external: + - MDB2 2.5.0 or newer + - Mail_Mime 1.8.1 or newer + - Net_SMTP 1.4.2 or newer + - Net_IDNA2 0.1.1 or newer + - Auth_SASL 1.0.3 or newer +* php.ini options (see .htaccess file): + - error_reporting E_ALL & ~E_NOTICE (or lower) + - memory_limit > 16MB (increase as suitable to support large attachments) + - file_uploads enabled (for attachment upload features) + - session.auto_start disabled + - zend.ze1_compatibility_mode disabled + - suhosin.session.encrypt disabled + - mbstring.func_overload disabled + - magic_quotes_runtime disabled +* PHP compiled with OpenSSL to connect to IMAPS and to use the spell checker +* A MySQL (4.0.8 or newer), PostgreSQL, MSSQL database engine + or the SQLite extension for PHP +* One of the above databases with permission to create tables +* An SMTP server (recommended) or PHP configured for mail delivery + + +INSTALLATION +============ + +1. Decompress and put this folder somewhere inside your document root +2. Make sure that the following directories (and the files within) + are writable by the webserver + - /temp + - /logs +3. Create a new database and a database user for Roundcube (see DATABASE SETUP) +4. Point your browser to http://url-to-roundcube/installer/ +5. Follow the instructions of the install script (or see MANUAL CONFIGURATION) +6. After creating and testing the configuration, remove the installer directory +7. Done! + + +CONFIGURATION HINTS +=================== + +Roundcube writes internal errors to the 'errors' log file located in the logs +directory which can be configured in config/main.inc.php. If you want ordinary +PHP errors to be logged there as well, enable the 'php_value error_log' line +in the .htaccess file and set the path to the log file accordingly. + +By default the session_path settings of PHP are not modified by Roundcube. +However if you want to limit the session cookies to the directory where +Roundcube resides you can uncomment and configure the according line +in the .htaccess file. + + +DATABASE SETUP +============== + +Note: Database for Roundcube must use UTF-8 character set. + +* MySQL +------- +Setting up the mysql database can be done by creating an empty database, +importing the table layout and granting the proper permissions to the +roundcube user. Here is an example of that procedure: + +# mysql +> CREATE DATABASE roundcubemail /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; +> GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost + IDENTIFIED BY 'password'; +> quit + +# mysql roundcubemail < SQL/mysql.initial.sql + +Note 1: 'password' is the master password for the roundcube user. It is strongly +recommended you replace this with a more secure password. Please keep in +mind: You need to specify this password later in 'config/db.inc.php'. + + +* SQLite +-------- +You need sqlite 2 (preferably 2.8) to setup the sqlite db +(sqlite 3.x also doesn't work at the moment). Here is +an example how you can setup the sqlite.db for roundcube: + +# sqlite -init SQL/sqlite.initial.sql sqlite.db +Loading resources from SQL/sqlite.initial.sql +SQLite version 2.8.16 +Enter ".help" for instructions +sqlite> .exit +# chmod o+rw sqlite.db + +Make sure your configuration points to the sqlite.db file and that the +webserver can write to the file and the directory containing the file. + + +* PostgreSQL +------------ +To use Roundcube with PostgreSQL support you have to follow these +simple steps, which have to be done as the postgres system user (or +which ever is the database superuser): + +$ createuser roundcube +$ createdb -O roundcube -E UNICODE roundcubemail +$ psql roundcubemail + +roundcubemail =# ALTER USER roundcube WITH PASSWORD 'the_new_password'; +roundcubemail =# \c - roundcube +roundcubemail => \i SQL/postgres.initial.sql + +All this has been tested with PostgreSQL 8.x and 7.4.x. Older +versions don't have a -O option for the createdb, so if you are +using that version you'll have to change ownership of the DB later. + + +Database cleaning +----------------- +Do keep your database slick and clean we recommend to periodically execute +bin/cleandb.sh which finally removes all records that are marked as deleted. +Best solution is to install a cronjob running this script daily. + + + +MANUAL CONFIGURATION +==================== + +First of all, rename the files config/*.inc.php.dist to config/*.inc.php. +You can then change these files according to your environment and your needs. +Details about the config parameters can be found in the config files. +See http://trac.roundcube.net/wiki/Howto_Install for even more guidance. + +You can also modify the default .htaccess file. This is necessary to +increase the allowed size of file attachments, for example: + php_value upload_max_filesize 2M + + +UPGRADING +========= + +If you already have a previous version of Roundcube installed, +please refer to the instructions in UPGRADING guide. + + +OPTIMISING +========== + +There are two forms of optimisation here, compression and caching, both aimed +at increasing an end user's experience using Roundcube Webmail. Compression +allows the static web pages to be delivered with less bandwidth. The index.php +of Roundcube Webmail already enables compression on its output. The settings +below allow compression to occur for all static files. Caching sets HTTP +response headers that enable a user's web client to understand what is static +and how to cache it. + +The caching directives used are: + * Etags - sets at tag so the client can request is the page has changed + * Cache-control - defines the age of the page and that the page is 'public' + This enables clients to cache javascript files that don't have private + information between sessions even if using HTTPS. It also allows proxies + to share the same cached page between users. + * Expires - provides another hint to increase the lifetime of static pages. + +For more information refer to RFC 2616. + +Side effects: +------------- +These directives are designed for production use. If you are using this in +a development environment you may get horribly confused if your webclient +is caching stuff that you changed on the server. Disabling the expires +parts below should save you some grief. + +If you are changing the skins, it is recommended that you copy content to +a different directory apart from 'default'. + +Apache: +------- +To enable these features in apache the following modules need to be enabled: + * mod_deflate + * mod_expires + * mod_headers + +The optimisation is already included in the .htaccess file in the top +directory of your installation. + +If you are using Apache version 2.2.9 and later, in the .htaccess file +change the 'append' word to 'merge' for a more correct response. Keeping +as 'append' shouldn't cause any problems though changing to merge will +eliminate the possibility of duplicate 'public' headers in Cache-control. + +Lighttpd: +--------- +With Lightty the addition of Expire: tags by mod_expire is incompatible with +the addition of "Cache-control: public". Using Cache-control 'public' is +used below as it is assumed to give a better caching result. + +Enable modules in server.modules: + "mod_setenv" + "mod_compress" + +Mod_compress is a server side cache of compressed files to improve its performance. + +$HTTP["host"] == "www.example.com" { + + static-file.etags = "enable" + # http://redmine.lighttpd.net/projects/lighttpd/wiki/Etag.use-mtimeDetails + etag.use-mtime = "enable" + + # http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModSetEnv + $HTTP["url"] =~ "^/roundcubemail/(plugins|skins|program)" { + setenv.add-response-header = ( "Cache-Control" => "public, max-age=2592000") + } + + # http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModCompress + # set compress.cache-dir to somewhere outside the docroot. + compress.cache-dir = var.statedir + "/cache/compress" + + compress.filetype = ("text/plain", "text/html", "text/javascript", "text/css", "text/xml", "image/gif", "image/png") +} + + diff --git a/SQL/mssql.initial.sql b/SQL/mssql.initial.sql index 4aa6fc9..c141141 100644 --- a/SQL/mssql.initial.sql +++ b/SQL/mssql.initial.sql @@ -7,6 +7,33 @@ CREATE TABLE [dbo].[cache] ( ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO +CREATE TABLE [dbo].[cache_index] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [changed] [datetime] NOT NULL , + [valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[cache_thread] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [changed] [datetime] NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[cache_messages] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [uid] [int] NOT NULL , + [changed] [datetime] NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL + [flags] [int](1) NOT NULL , +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + CREATE TABLE [dbo].[contacts] ( [contact_id] [int] IDENTITY (1, 1) NOT NULL , [user_id] [int] NOT NULL , @@ -53,27 +80,8 @@ CREATE TABLE [dbo].[identities] ( ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -CREATE TABLE [dbo].[messages] ( - [message_id] [int] IDENTITY (1, 1) NOT NULL , - [user_id] [int] NOT NULL , - [del] [tinyint] NOT NULL , - [cache_key] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , - [created] [datetime] NOT NULL , - [idx] [int] NOT NULL , - [uid] [int] NOT NULL , - [subject] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL , - [from] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL , - [to] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL , - [cc] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL , - [date] [datetime] NOT NULL , - [size] [int] NOT NULL , - [headers] [text] COLLATE Latin1_General_CI_AI NOT NULL , - [structure] [text] COLLATE Latin1_General_CI_AI NULL -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO - CREATE TABLE [dbo].[session] ( - [sess_id] [varchar] (32) COLLATE Latin1_General_CI_AI NOT NULL , + [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , [created] [datetime] NOT NULL , [changed] [datetime] NULL , [ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL , @@ -93,6 +101,22 @@ CREATE TABLE [dbo].[users] ( ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO +CREATE TABLE [dbo].[dictionary] ( + [user_id] [int] , + [language] [varchar] (5) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[searches] ( + [search_id] [int] IDENTITY (1, 1) NOT NULL , + [user_id] [int] NOT NULL , + [type] [tinyint] NOT NULL , + [name] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + ALTER TABLE [dbo].[cache] WITH NOCHECK ADD PRIMARY KEY CLUSTERED ( @@ -100,6 +124,27 @@ ALTER TABLE [dbo].[cache] WITH NOCHECK ADD ) ON [PRIMARY] GO +ALTER TABLE [dbo].[cache_index] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_thread] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_messages] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox],[uid] + ) ON [PRIMARY] +GO + ALTER TABLE [dbo].[contacts] WITH NOCHECK ADD CONSTRAINT [PK_contacts_contact_id] PRIMARY KEY CLUSTERED ( @@ -128,13 +173,6 @@ ALTER TABLE [dbo].[identities] WITH NOCHECK ADD ) ON [PRIMARY] GO -ALTER TABLE [dbo].[messages] WITH NOCHECK ADD - PRIMARY KEY CLUSTERED - ( - [message_id] - ) ON [PRIMARY] -GO - ALTER TABLE [dbo].[session] WITH NOCHECK ADD CONSTRAINT [PK_session_sess_id] PRIMARY KEY CLUSTERED ( @@ -149,6 +187,13 @@ ALTER TABLE [dbo].[users] WITH NOCHECK ADD ) ON [PRIMARY] GO +ALTER TABLE [dbo].[searches] WITH NOCHECK ADD + CONSTRAINT [PK_searches_search_id] PRIMARY KEY CLUSTERED + ( + [search_id] + ) ON [PRIMARY] +GO + ALTER TABLE [dbo].[cache] ADD CONSTRAINT [DF_cache_user_id] DEFAULT ('0') FOR [user_id], CONSTRAINT [DF_cache_cache_key] DEFAULT ('') FOR [cache_key], @@ -164,6 +209,29 @@ GO CREATE INDEX [IX_cache_created] ON [dbo].[cache]([created]) ON [PRIMARY] GO +ALTER TABLE [dbo].[cache_index] ADD + CONSTRAINT [DF_cache_index_changed] DEFAULT (getdate()) FOR [changed], + CONSTRAINT [DF_cache_index_valid] DEFAULT ('0') FOR [valid] +GO + +CREATE INDEX [IX_cache_index_user_id] ON [dbo].[cache_index]([user_id]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_thread] ADD + CONSTRAINT [DF_cache_thread_changed] DEFAULT (getdate()) FOR [changed] +GO + +CREATE INDEX [IX_cache_thread_user_id] ON [dbo].[cache_thread]([user_id]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_messages] ADD + CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed], + CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags], +GO + +CREATE INDEX [IX_cache_messages_user_id] ON [dbo].[cache_messages]([user_id]) ON [PRIMARY] +GO + ALTER TABLE [dbo].[contacts] ADD CONSTRAINT [DF_contacts_user_id] DEFAULT (0) FOR [user_id], CONSTRAINT [DF_contacts_changed] DEFAULT (getdate()) FOR [changed], @@ -215,33 +283,6 @@ GO CREATE INDEX [IX_identities_user_id] ON [dbo].[identities]([user_id]) ON [PRIMARY] GO -ALTER TABLE [dbo].[messages] ADD - CONSTRAINT [DF_messages_user_id] DEFAULT (0) FOR [user_id], - CONSTRAINT [DF_messages_del] DEFAULT (0) FOR [del], - CONSTRAINT [DF_messages_cache_key] DEFAULT ('') FOR [cache_key], - CONSTRAINT [DF_messages_created] DEFAULT (getdate()) FOR [created], - CONSTRAINT [DF_messages_idx] DEFAULT (0) FOR [idx], - CONSTRAINT [DF_messages_uid] DEFAULT (0) FOR [uid], - CONSTRAINT [DF_messages_subject] DEFAULT ('') FOR [subject], - CONSTRAINT [DF_messages_from] DEFAULT ('') FOR [from], - CONSTRAINT [DF_messages_to] DEFAULT ('') FOR [to], - CONSTRAINT [DF_messages_cc] DEFAULT ('') FOR [cc], - CONSTRAINT [DF_messages_date] DEFAULT (getdate()) FOR [date], - CONSTRAINT [DF_messages_size] DEFAULT (0) FOR [size] -GO - -CREATE INDEX [IX_messages_user_id] ON [dbo].[messages]([user_id]) ON [PRIMARY] -GO - -CREATE INDEX [IX_messages_cache_key] ON [dbo].[messages]([cache_key]) ON [PRIMARY] -GO - -CREATE INDEX [IX_messages_uid] ON [dbo].[messages]([uid]) ON [PRIMARY] -GO - -CREATE INDEX [IX_messages_created] ON [dbo].[messages]([created]) ON [PRIMARY] -GO - ALTER TABLE [dbo].[session] ADD CONSTRAINT [DF_session_sess_id] DEFAULT ('') FOR [sess_id], CONSTRAINT [DF_session_created] DEFAULT (getdate()) FOR [created], @@ -264,6 +305,17 @@ GO CREATE INDEX [IX_users_alias] ON [dbo].[users]([alias]) ON [PRIMARY] GO +CREATE UNIQUE INDEX [IX_dictionary_user_language] ON [dbo].[dictionary]([user_id],[language]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[searches] ADD + CONSTRAINT [DF_searches_user] DEFAULT (0) FOR [user_id], + CONSTRAINT [DF_searches_type] DEFAULT (0) FOR [type], +GO + +CREATE UNIQUE INDEX [IX_searches_user_type_name] ON [dbo].[searches]([user_id],[type],[name]) ON [PRIMARY] +GO + ALTER TABLE [dbo].[identities] ADD CONSTRAINT [FK_identities_user_id] FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) ON DELETE CASCADE ON UPDATE CASCADE @@ -284,7 +336,17 @@ ALTER TABLE [dbo].[cache] ADD CONSTRAINT [FK_cache_user_id] ON DELETE CASCADE ON UPDATE CASCADE GO -ALTER TABLE [dbo].[messages] ADD CONSTRAINT [FK_messages_user_id] +ALTER TABLE [dbo].[cache_index] ADD CONSTRAINT [FK_cache_index_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +ALTER TABLE [dbo].[cache_thread] ADD CONSTRAINT [FK_cache_thread_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +ALTER TABLE [dbo].[cache_messages] ADD CONSTRAINT [FK_cache_messages_user_id] FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) ON DELETE CASCADE ON UPDATE CASCADE GO @@ -294,6 +356,11 @@ ALTER TABLE [dbo].[contactgroupmembers] ADD CONSTRAINT [FK_contactgroupmembers_c ON DELETE CASCADE ON UPDATE CASCADE GO +ALTER TABLE [dbo].[searches] ADD CONSTRAINT [FK_searches_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + -- Use trigger instead of foreign key (#1487112) -- "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." CREATE TRIGGER [contact_delete_member] ON [dbo].[contacts] diff --git a/SQL/mssql.upgrade.sql b/SQL/mssql.upgrade.sql index 606db60..eee5ae5 100644 --- a/SQL/mssql.upgrade.sql +++ b/SQL/mssql.upgrade.sql @@ -110,3 +110,137 @@ DELETE FROM [dbo].[messages] GO DELETE FROM [dbo].[cache] GO + +-- Updates from version 0.6 + +CREATE TABLE [dbo].[dictionary] ( + [user_id] [int] , + [language] [varchar] (5) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +CREATE UNIQUE INDEX [IX_dictionary_user_language] ON [dbo].[dictionary]([user_id],[language]) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[searches] ( + [search_id] [int] IDENTITY (1, 1) NOT NULL , + [user_id] [int] NOT NULL , + [type] [tinyint] NOT NULL , + [name] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +ALTER TABLE [dbo].[searches] WITH NOCHECK ADD + CONSTRAINT [PK_searches_search_id] PRIMARY KEY CLUSTERED + ( + [search_id] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[searches] ADD + CONSTRAINT [DF_searches_user] DEFAULT (0) FOR [user_id], + CONSTRAINT [DF_searches_type] DEFAULT (0) FOR [type], +GO + +CREATE UNIQUE INDEX [IX_searches_user_type_name] ON [dbo].[searches]([user_id],[type],[name]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[searches] ADD CONSTRAINT [FK_searches_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +DROP TABLE [dbo].[messages] +GO +CREATE TABLE [dbo].[cache_index] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [changed] [datetime] NOT NULL , + [valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[cache_thread] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [changed] [datetime] NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[cache_messages] ( + [user_id] [int] NOT NULL , + [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [uid] [int] NOT NULL , + [changed] [datetime] NOT NULL , + [data] [text] COLLATE Latin1_General_CI_AI NOT NULL + [flags] [int] NOT NULL , +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_index] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_thread] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_messages] WITH NOCHECK ADD + PRIMARY KEY CLUSTERED + ( + [user_id],[mailbox],[uid] + ) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_index] ADD + CONSTRAINT [DF_cache_index_changed] DEFAULT (getdate()) FOR [changed], + CONSTRAINT [DF_cache_index_valid] DEFAULT ('0') FOR [valid] +GO + +CREATE INDEX [IX_cache_index_user_id] ON [dbo].[cache_index]([user_id]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_thread] ADD + CONSTRAINT [DF_cache_thread_changed] DEFAULT (getdate()) FOR [changed] +GO + +CREATE INDEX [IX_cache_thread_user_id] ON [dbo].[cache_thread]([user_id]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_messages] ADD + CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed], + CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags] +GO + +CREATE INDEX [IX_cache_messages_user_id] ON [dbo].[cache_messages]([user_id]) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[cache_index] ADD CONSTRAINT [FK_cache_index_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +ALTER TABLE [dbo].[cache_thread] ADD CONSTRAINT [FK_cache_thread_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +ALTER TABLE [dbo].[cache_messages] ADD CONSTRAINT [FK_cache_messages_user_id] + FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id]) + ON DELETE CASCADE ON UPDATE CASCADE +GO + +-- Updates from version 0.7-beta + +ALTER TABLE [dbo].[session] ALTER COLUMN [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL +GO + diff --git a/SQL/mysql.initial.sql b/SQL/mysql.initial.sql index 14bbb96..94679f2 100644 --- a/SQL/mysql.initial.sql +++ b/SQL/mysql.initial.sql @@ -6,7 +6,7 @@ -- Table structure for table `session` CREATE TABLE `session` ( - `sess_id` varchar(40) NOT NULL, + `sess_id` varchar(128) NOT NULL, `created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `ip` varchar(40) NOT NULL, @@ -20,9 +20,9 @@ CREATE TABLE `session` ( CREATE TABLE `users` ( `user_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, - `username` varchar(128) NOT NULL, + `username` varchar(128) BINARY NOT NULL, `mail_host` varchar(128) NOT NULL, - `alias` varchar(128) NOT NULL, + `alias` varchar(128) BINARY NOT NULL, `created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `last_login` datetime DEFAULT NULL, `language` varchar(5), @@ -33,33 +33,6 @@ CREATE TABLE `users` ( ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; --- Table structure for table `messages` - -CREATE TABLE `messages` ( - `message_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, - `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', - `del` tinyint(1) NOT NULL DEFAULT '0', - `cache_key` varchar(128) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL, - `created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', - `idx` int(11) UNSIGNED NOT NULL DEFAULT '0', - `uid` int(11) UNSIGNED NOT NULL DEFAULT '0', - `subject` varchar(255) NOT NULL, - `from` varchar(255) NOT NULL, - `to` varchar(255) NOT NULL, - `cc` varchar(255) NOT NULL, - `date` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', - `size` int(11) UNSIGNED NOT NULL DEFAULT '0', - `headers` text NOT NULL, - `structure` text, - PRIMARY KEY(`message_id`), - CONSTRAINT `user_id_fk_messages` FOREIGN KEY (`user_id`) - REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, - INDEX `created_index` (`created`), - INDEX `index_index` (`user_id`, `cache_key`, `idx`), - UNIQUE `uniqueness` (`user_id`, `cache_key`, `uid`) -) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; - - -- Table structure for table `cache` CREATE TABLE `cache` ( @@ -76,6 +49,51 @@ CREATE TABLE `cache` ( ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; +-- Table structure for table `cache_index` + +CREATE TABLE `cache_index` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `valid` tinyint(1) NOT NULL DEFAULT '0', + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_cache_index` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + +-- Table structure for table `cache_thread` + +CREATE TABLE `cache_thread` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_cache_thread` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + +-- Table structure for table `cache_messages` + +CREATE TABLE `cache_messages` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `uid` int(11) UNSIGNED NOT NULL DEFAULT '0', + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `data` longtext NOT NULL, + `flags` int(11) NOT NULL DEFAULT '0', + CONSTRAINT `user_id_fk_cache_messages` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`, `uid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + -- Table structure for table `contacts` CREATE TABLE `contacts` ( @@ -144,4 +162,31 @@ CREATE TABLE `identities` ( ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; +-- Table structure for table `dictionary` + +CREATE TABLE `dictionary` ( + `user_id` int(10) UNSIGNED DEFAULT NULL, + `language` varchar(5) NOT NULL, + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_dictionary` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE `uniqueness` (`user_id`, `language`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + +-- Table structure for table `searches` + +CREATE TABLE `searches` ( + `search_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `type` int(3) NOT NULL DEFAULT '0', + `name` varchar(128) NOT NULL, + `data` text, + PRIMARY KEY(`search_id`), + CONSTRAINT `user_id_fk_searches` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE `uniqueness` (`user_id`, `type`, `name`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + /*!40014 SET FOREIGN_KEY_CHECKS=1 */; diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql index ed21bda..0761731 100644 --- a/SQL/mysql.update.sql +++ b/SQL/mysql.update.sql @@ -144,3 +144,71 @@ ALTER TABLE `contactgroupmembers` ADD INDEX `contactgroupmembers_contact_index` TRUNCATE TABLE `messages`; TRUNCATE TABLE `cache`; + +-- Updates from version 0.6 + +ALTER TABLE `users` CHANGE `alias` `alias` varchar(128) BINARY NOT NULL; +ALTER TABLE `users` CHANGE `username` `username` varchar(128) BINARY NOT NULL; + +CREATE TABLE `dictionary` ( + `user_id` int(10) UNSIGNED DEFAULT NULL, + `language` varchar(5) NOT NULL, + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_dictionary` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE `uniqueness` (`user_id`, `language`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +CREATE TABLE `searches` ( + `search_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `type` int(3) NOT NULL DEFAULT '0', + `name` varchar(128) NOT NULL, + `data` text, + PRIMARY KEY(`search_id`), + CONSTRAINT `user_id_fk_searches` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE `uniqueness` (`user_id`, `type`, `name`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE `messages`; + +CREATE TABLE `cache_index` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `valid` tinyint(1) NOT NULL DEFAULT '0', + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_cache_index` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +CREATE TABLE `cache_thread` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `data` longtext NOT NULL, + CONSTRAINT `user_id_fk_cache_thread` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +CREATE TABLE `cache_messages` ( + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', + `mailbox` varchar(255) BINARY NOT NULL, + `uid` int(11) UNSIGNED NOT NULL DEFAULT '0', + `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', + `data` longtext NOT NULL, + `flags` int(11) NOT NULL DEFAULT '0', + CONSTRAINT `user_id_fk_cache_messages` FOREIGN KEY (`user_id`) + REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + INDEX `changed_index` (`changed`), + PRIMARY KEY (`user_id`, `mailbox`, `uid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +-- Updates from version 0.7-beta + +ALTER TABLE `session` CHANGE `sess_id` `sess_id` varchar(128) NOT NULL; diff --git a/SQL/postgres.initial.sql b/SQL/postgres.initial.sql index 5350e79..3710dac 100644 --- a/SQL/postgres.initial.sql +++ b/SQL/postgres.initial.sql @@ -37,7 +37,7 @@ CREATE INDEX users_alias_id_idx ON users (alias); -- CREATE TABLE "session" ( - sess_id varchar(40) DEFAULT '' PRIMARY KEY, + sess_id varchar(128) DEFAULT '' PRIMARY KEY, created timestamp with time zone DEFAULT now() NOT NULL, changed timestamp with time zone DEFAULT now() NOT NULL, ip varchar(41) NOT NULL, @@ -67,7 +67,7 @@ CREATE SEQUENCE identity_ids CREATE TABLE identities ( identity_id integer DEFAULT nextval('identity_ids'::text) PRIMARY KEY, user_id integer NOT NULL - REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, changed timestamp with time zone DEFAULT now() NOT NULL, del smallint DEFAULT 0 NOT NULL, standard smallint DEFAULT 0 NOT NULL, @@ -178,7 +178,7 @@ CREATE SEQUENCE cache_ids CREATE TABLE "cache" ( cache_id integer DEFAULT nextval('cache_ids'::text) PRIMARY KEY, user_id integer NOT NULL - REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, cache_key varchar(128) DEFAULT '' NOT NULL, created timestamp with time zone DEFAULT now() NOT NULL, data text NOT NULL @@ -188,40 +188,91 @@ CREATE INDEX cache_user_id_idx ON "cache" (user_id, cache_key); CREATE INDEX cache_created_idx ON "cache" (created); -- --- Sequence "message_ids" --- Name: message_ids; Type: SEQUENCE; Schema: public; Owner: postgres +-- Table "cache_index" +-- Name: cache_index; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE cache_index ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + valid smallint NOT NULL DEFAULT 0, + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX cache_index_changed_idx ON cache_index (changed); + +-- +-- Table "cache_thread" +-- Name: cache_thread; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE cache_thread ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX cache_thread_changed_idx ON cache_thread (changed); + +-- +-- Table "cache_messages" +-- Name: cache_messages; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE cache_messages ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + uid integer NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + data text NOT NULL, + flags integer NOT NULL DEFAULT 0, + PRIMARY KEY (user_id, mailbox, uid) +); + +CREATE INDEX cache_messages_changed_idx ON cache_messages (changed); + +-- +-- Table "dictionary" +-- Name: dictionary; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE dictionary ( + user_id integer DEFAULT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + "language" varchar(5) NOT NULL, + data text NOT NULL, + CONSTRAINT dictionary_user_id_language_key UNIQUE (user_id, "language") +); + +-- +-- Sequence "searches_ids" +-- Name: searches_ids; Type: SEQUENCE; Schema: public; Owner: postgres -- -CREATE SEQUENCE message_ids +CREATE SEQUENCE search_ids INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; -- --- Table "messages" --- Name: messages; Type: TABLE; Schema: public; Owner: postgres +-- Table "searches" +-- Name: searches; Type: TABLE; Schema: public; Owner: postgres -- -CREATE TABLE messages ( - message_id integer DEFAULT nextval('message_ids'::text) PRIMARY KEY, +CREATE TABLE searches ( + search_id integer DEFAULT nextval('search_ids'::text) PRIMARY KEY, user_id integer NOT NULL - REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, - del smallint DEFAULT 0 NOT NULL, - cache_key varchar(128) DEFAULT '' NOT NULL, - created timestamp with time zone DEFAULT now() NOT NULL, - idx integer DEFAULT 0 NOT NULL, - uid integer DEFAULT 0 NOT NULL, - subject varchar(128) DEFAULT '' NOT NULL, - "from" varchar(128) DEFAULT '' NOT NULL, - "to" varchar(128) DEFAULT '' NOT NULL, - cc varchar(128) DEFAULT '' NOT NULL, - date timestamp with time zone NOT NULL, - size integer DEFAULT 0 NOT NULL, - headers text NOT NULL, - structure text, - CONSTRAINT messages_user_id_key UNIQUE (user_id, cache_key, uid) + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + "type" smallint DEFAULT 0 NOT NULL, + name varchar(128) NOT NULL, + data text NOT NULL, + CONSTRAINT searches_user_id_key UNIQUE (user_id, "type", name) ); - -CREATE INDEX messages_index_idx ON messages (user_id, cache_key, idx); -CREATE INDEX messages_created_idx ON messages (created); diff --git a/SQL/postgres.update.sql b/SQL/postgres.update.sql index 94513c5..c96669d 100644 --- a/SQL/postgres.update.sql +++ b/SQL/postgres.update.sql @@ -100,3 +100,72 @@ CREATE INDEX contactgroupmembers_contact_id_idx ON contactgroupmembers (contact_ TRUNCATE messages; TRUNCATE cache; + +-- Updates from version 0.6 + +CREATE TABLE dictionary ( + user_id integer DEFAULT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + "language" varchar(5) NOT NULL, + data text NOT NULL, + CONSTRAINT dictionary_user_id_language_key UNIQUE (user_id, "language") +); + +CREATE SEQUENCE search_ids + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + +CREATE TABLE searches ( + search_id integer DEFAULT nextval('search_ids'::text) PRIMARY KEY, + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + "type" smallint DEFAULT 0 NOT NULL, + name varchar(128) NOT NULL, + data text NOT NULL, + CONSTRAINT searches_user_id_key UNIQUE (user_id, "type", name) +); + +DROP SEQUENCE messages_ids; +DROP TABLE messages; + +CREATE TABLE cache_index ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + valid smallint NOT NULL DEFAULT 0, + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX cache_index_changed_idx ON cache_index (changed); + +CREATE TABLE cache_thread ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX cache_thread_changed_idx ON cache_thread (changed); + +CREATE TABLE cache_messages ( + user_id integer NOT NULL + REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE, + mailbox varchar(255) NOT NULL, + uid integer NOT NULL, + changed timestamp with time zone DEFAULT now() NOT NULL, + data text NOT NULL, + flags integer NOT NULL DEFAULT 0, + PRIMARY KEY (user_id, mailbox, uid) +); + +CREATE INDEX cache_messages_changed_idx ON cache_messages (changed); + +-- Updates from version 0.7-beta + +ALTER TABLE "session" ALTER sess_id TYPE varchar(128); diff --git a/SQL/sqlite.initial.sql b/SQL/sqlite.initial.sql index d2885e9..8c8da5c 100644 --- a/SQL/sqlite.initial.sql +++ b/SQL/sqlite.initial.sql @@ -1,7 +1,7 @@ -- Roundcube Webmail initial database structure -- --- Table structure for table `cache` +-- Table structure for table cache -- CREATE TABLE cache ( @@ -9,7 +9,7 @@ CREATE TABLE cache ( user_id integer NOT NULL default 0, cache_key varchar(128) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', - data longtext NOT NULL + data text NOT NULL ); CREATE INDEX ix_cache_user_cache_key ON cache(user_id, cache_key); @@ -110,7 +110,7 @@ CREATE INDEX ix_users_alias ON users(alias); -- CREATE TABLE session ( - sess_id varchar(40) NOT NULL PRIMARY KEY, + sess_id varchar(128) NOT NULL PRIMARY KEY, created datetime NOT NULL default '0000-00-00 00:00:00', changed datetime NOT NULL default '0000-00-00 00:00:00', ip varchar(40) NOT NULL default '', @@ -121,28 +121,81 @@ CREATE INDEX ix_session_changed ON session (changed); -- -------------------------------------------------------- --- --- Table structure for table messages --- +-- +-- Table structure for table dictionary +-- -CREATE TABLE messages ( - message_id integer NOT NULL PRIMARY KEY, - user_id integer NOT NULL default '0', - del tinyint NOT NULL default '0', - cache_key varchar(128) NOT NULL default '', - created datetime NOT NULL default '0000-00-00 00:00:00', - idx integer NOT NULL default '0', - uid integer NOT NULL default '0', - subject varchar(255) NOT NULL default '', - "from" varchar(255) NOT NULL default '', - "to" varchar(255) NOT NULL default '', - "cc" varchar(255) NOT NULL default '', - "date" datetime NOT NULL default '0000-00-00 00:00:00', - size integer NOT NULL default '0', - headers text NOT NULL, - structure text +CREATE TABLE dictionary ( + user_id integer DEFAULT NULL, + "language" varchar(5) NOT NULL, + data text NOT NULL +); + +CREATE UNIQUE INDEX ix_dictionary_user_language ON dictionary (user_id, "language"); + +-- -------------------------------------------------------- + +-- +-- Table structure for table searches +-- + +CREATE TABLE searches ( + search_id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL DEFAULT '0', + "type" smallint NOT NULL DEFAULT '0', + name varchar(128) NOT NULL, + data text NOT NULL +); + +CREATE UNIQUE INDEX ix_searches_user_type_name (user_id, type, name); + +-- -------------------------------------------------------- + +-- +-- Table structure for table cache_index +-- + +CREATE TABLE cache_index ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + valid smallint NOT NULL DEFAULT '0', + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX ix_cache_index_changed ON cache_index (changed); + +-- -------------------------------------------------------- + +-- +-- Table structure for table cache_thread +-- + +CREATE TABLE cache_thread ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX ix_cache_thread_changed ON cache_thread (changed); + +-- -------------------------------------------------------- + +-- +-- Table structure for table cache_messages +-- + +CREATE TABLE cache_messages ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + uid integer NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + data text NOT NULL, + flags integer NOT NULL DEFAULT '0', + PRIMARY KEY (user_id, mailbox, uid) ); -CREATE UNIQUE INDEX ix_messages_user_cache_uid ON messages (user_id,cache_key,uid); -CREATE INDEX ix_messages_index ON messages (user_id,cache_key,idx); -CREATE INDEX ix_messages_created ON messages (created); +CREATE INDEX ix_cache_messages_changed ON cache_messages (changed); diff --git a/SQL/sqlite.update.sql b/SQL/sqlite.update.sql index 30c3ae9..92f6da1 100644 --- a/SQL/sqlite.update.sql +++ b/SQL/sqlite.update.sql @@ -223,6 +223,75 @@ INSERT INTO contacts (contact_id, user_id, changed, del, name, email, firstname, CREATE INDEX ix_contacts_user_id ON contacts(user_id, email); DROP TABLE contacts_tmp; + DELETE FROM messages; DELETE FROM cache; CREATE INDEX ix_contactgroupmembers_contact_id ON contactgroupmembers (contact_id); + +-- Updates from version 0.6 + +CREATE TABLE dictionary ( + user_id integer DEFAULT NULL, + "language" varchar(5) NOT NULL, + data text NOT NULL +); + +CREATE UNIQUE INDEX ix_dictionary_user_language ON dictionary (user_id, "language"); + +CREATE TABLE searches ( + search_id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL DEFAULT '0', + "type" smallint NOT NULL DEFAULT '0', + name varchar(128) NOT NULL, + data text NOT NULL +); + +CREATE UNIQUE INDEX ix_searches_user_type_name (user_id, type, name); + +DROP TABLE messages; + +CREATE TABLE cache_index ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + valid smallint NOT NULL DEFAULT '0', + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX ix_cache_index_changed ON cache_index (changed); + +CREATE TABLE cache_thread ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + data text NOT NULL, + PRIMARY KEY (user_id, mailbox) +); + +CREATE INDEX ix_cache_thread_changed ON cache_thread (changed); + +CREATE TABLE cache_messages ( + user_id integer NOT NULL, + mailbox varchar(255) NOT NULL, + uid integer NOT NULL, + changed datetime NOT NULL default '0000-00-00 00:00:00', + data text NOT NULL, + flags integer NOT NULL DEFAULT '0', + PRIMARY KEY (user_id, mailbox, uid) +); + +CREATE INDEX ix_cache_messages_changed ON cache_messages (changed); + +-- Updates from version 0.7-beta + +DROP TABLE session; +CREATE TABLE session ( + sess_id varchar(128) NOT NULL PRIMARY KEY, + created datetime NOT NULL default '0000-00-00 00:00:00', + changed datetime NOT NULL default '0000-00-00 00:00:00', + ip varchar(40) NOT NULL default '', + vars text NOT NULL +); + +CREATE INDEX ix_session_changed ON session (changed); diff --git a/bin/indexcontacts.sh b/bin/indexcontacts.sh index d552be6..cbeffe9 100755 --- a/bin/indexcontacts.sh +++ b/bin/indexcontacts.sh @@ -16,14 +16,14 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: indexcontacts.sh 4623 2011-03-28 06:49:02Z alec $ + $Id: indexcontacts.sh 5307 2011-10-05 09:28:25Z alec $ */ define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); require_once INSTALL_PATH.'program/include/clisetup.php'; - +ini_set('memory_limit', -1); // connect to DB $RCMAIL = rcmail::get_instance(); @@ -47,7 +47,7 @@ while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) { unset($row['words']); $contacts->update($row['ID'], $row); } - + echo "done.\n"; } diff --git a/bin/installto.sh b/bin/installto.sh index 33652dc..bcba57c 100755 --- a/bin/installto.sh +++ b/bin/installto.sh @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: installto.sh 4677 2011-04-20 13:10:45Z alec $ + $Id: installto.sh 5311 2011-10-06 08:20:11Z thomasb $ */ @@ -45,13 +45,13 @@ if (strtolower($input) == 'y') { $err = false; echo "Copying files to target location..."; foreach (array('program','installer','bin','SQL','plugins','skins/default') as $dir) { - if (!system("rsync -avuC " . INSTALL_PATH . "$dir/* $target_dir/$dir/")) { + if (!system("rsync -avC " . INSTALL_PATH . "$dir/* $target_dir/$dir/")) { $err = true; break; } } foreach (array('index.php','.htaccess','config/main.inc.php.dist','config/db.inc.php.dist','CHANGELOG','README','UPGRADING') as $file) { - if (!system("rsync -avu " . INSTALL_PATH . "$file $target_dir/$file")) { + if (!system("rsync -av " . INSTALL_PATH . "$file $target_dir/$file")) { $err = true; break; } diff --git a/bin/jsshrink.sh b/bin/jsshrink.sh index be5aad1..9cfd660 100755 --- a/bin/jsshrink.sh +++ b/bin/jsshrink.sh @@ -1,10 +1,11 @@ #!/bin/sh JS_DIR=`dirname "$0"`/../program/js +JAR_DIR='/tmp' CLOSURE_COMPILER_URL='http://closure-compiler.googlecode.com/files/compiler-latest.zip' do_shrink() { rm -f "$2" - java -jar compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js="$1" --js_output_file="$2" + java -jar $JAR_DIR/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js="$1" --js_output_file="$2" } if [ ! -d "$JS_DIR" ]; then @@ -12,6 +13,10 @@ if [ ! -d "$JS_DIR" ]; then exit 1 fi +if [ ! -w "$JAR_DIR" ]; then + JAR_DIR=`dirname "$0"` +fi + if java -version >/dev/null 2>&1; then : else @@ -19,16 +24,16 @@ else exit 1 fi -if [ ! -r "compiler.jar" ]; then +if [ ! -r "$JAR_DIR/compiler.jar" ]; then if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then wget "$CLOSURE_COMPILER_URL" -O "/tmp/$$.zip" elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then curl "$CLOSURE_COMPILER_URL" -o "/tmp/$$.zip" else - echo "Please download $CLOSURE_COMPILER_URL and extract compiler.jar to this directory." + echo "Please download $CLOSURE_COMPILER_URL and extract compiler.jar to $JAR_DIR/." exit 1 fi - unzip "/tmp/$$.zip" "compiler.jar" + (cd $JAR_DIR && unzip "/tmp/$$.zip" "compiler.jar") rm -f "/tmp/$$.zip" fi diff --git a/config/db.inc.php.dist b/config/db.inc.php.dist index 78cd968..c1464f9 100644 --- a/config/db.inc.php.dist +++ b/config/db.inc.php.dist @@ -39,34 +39,24 @@ $rcmail_config['db_persistent'] = FALSE; // you can define specific table names used to store webmail data $rcmail_config['db_table_users'] = 'users'; - $rcmail_config['db_table_identities'] = 'identities'; - $rcmail_config['db_table_contacts'] = 'contacts'; - $rcmail_config['db_table_contactgroups'] = 'contactgroups'; - $rcmail_config['db_table_contactgroupmembers'] = 'contactgroupmembers'; - $rcmail_config['db_table_session'] = 'session'; - $rcmail_config['db_table_cache'] = 'cache'; - -$rcmail_config['db_table_messages'] = 'messages'; +$rcmail_config['db_table_cache_index'] = 'cache_index'; +$rcmail_config['db_table_cache_thread'] = 'cache_thread'; +$rcmail_config['db_table_cache_messages'] = 'cache_messages'; // you can define specific sequence names used in PostgreSQL $rcmail_config['db_sequence_users'] = 'user_ids'; - $rcmail_config['db_sequence_identities'] = 'identity_ids'; - $rcmail_config['db_sequence_contacts'] = 'contact_ids'; - $rcmail_config['db_sequence_contactgroups'] = 'contactgroups_ids'; - $rcmail_config['db_sequence_cache'] = 'cache_ids'; - -$rcmail_config['db_sequence_messages'] = 'message_ids'; +$rcmail_config['db_sequence_searches'] = 'search_ids'; // end db config file diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 824085c..6957577 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -5,7 +5,7 @@ | Main configuration file | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -222,6 +222,9 @@ $rcmail_config['session_lifetime'] = 10; // session domain: .example.org $rcmail_config['session_domain'] = ''; +// session name. Default: 'roundcube_sessid' +$rcmail_config['session_name'] = null; + // Backend to use for session storage. Can either be 'db' (default) or 'memcache' // If set to memcache, a list of servers need to be specified in 'memcache_hosts' // Make sure the Memcache extension (http://pecl.php.net/package/memcache) version >= 2.0.0 is installed @@ -369,25 +372,30 @@ $rcmail_config['message_sort_col'] = ''; $rcmail_config['message_sort_order'] = 'DESC'; // These cols are shown in the message list. Available cols are: -// subject, from, to, cc, replyto, date, size, status, flag, attachment +// subject, from, to, cc, replyto, date, size, status, flag, attachment, 'priority' $rcmail_config['list_cols'] = array('subject', 'status', 'from', 'date', 'size', 'flag', 'attachment'); // the default locale setting (leave empty for auto-detection) // RFC1766 formatted language name like en_US, de_DE, de_CH, fr_FR, pt_BR $rcmail_config['language'] = null; -// use this format for short date display (date or strftime format) -$rcmail_config['date_short'] = 'D H:i'; +// use this format for date display (date or strftime format) +$rcmail_config['date_format'] = 'Y-m-d'; -// use this format for detailed date/time formatting (date or strftime format) -$rcmail_config['date_long'] = 'd.m.Y H:i'; +// give this choice of date formats to the user to select from +$rcmail_config['date_formats'] = array('Y-m-d', 'd-m-Y', 'Y/m/d', 'm/d/Y', 'd/m/Y', 'd.m.Y', 'j.n.Y'); -// use this format for today's date display (date or strftime format) -// Note: $ character will be replaced with 'Today' label -$rcmail_config['date_today'] = 'H:i'; +// use this format for time display (date or strftime format) +$rcmail_config['time_format'] = 'H:i'; -// use this format for date display without time (date or strftime format) -$rcmail_config['date_format'] = 'Y-m-d'; +// give this choice of time formats to the user to select from +$rcmail_config['time_formats'] = array('G:i', 'H:i', 'g:i a', 'h:i A'); + +// use this format for short date display (derived from date_format and time_format) +$rcmail_config['date_short'] = 'D H:i'; + +// use this format for detailed date/time formatting (derived from date_format and time_format) +$rcmail_config['date_long'] = 'Y-m-d H:i'; // store draft message is this mailbox // leave blank if draft messages should not be stored @@ -413,7 +421,7 @@ $rcmail_config['trash_mbox'] = 'Trash'; // NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP) $rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash'); -// automatically create the above listed default folders on login +// automatically create the above listed default folders on first login $rcmail_config['create_default_folders'] = false; // protect the default folders from renames, deletes, and subscription changes @@ -427,6 +435,10 @@ $rcmail_config['quota_zero_as_unlimited'] = false; // requires to be compiled with Open SSL support $rcmail_config['enable_spellcheck'] = true; +// Enables spellchecker exceptions dictionary. +// Setting it to 'shared' will make the dictionary shared by all users. +$rcmail_config['spellcheck_dictionary'] = false; + // Set the spell checking engine. 'googie' is the default. 'pspell' is also available, // but requires the Pspell extensions. When using Nox Spell Server, also set 'googie' here. $rcmail_config['spellcheck_engine'] = 'googie'; @@ -442,6 +454,18 @@ $rcmail_config['spellcheck_uri'] = ''; // Leave empty for default set of available language. $rcmail_config['spellcheck_languages'] = NULL; +// Makes that words with all letters capitalized will be ignored (e.g. GOOGLE) +$rcmail_config['spellcheck_ignore_caps'] = false; + +// Makes that words with numbers will be ignored (e.g. g00gle) +$rcmail_config['spellcheck_ignore_nums'] = false; + +// Makes that words with symbols will be ignored (e.g. g@@gle) +$rcmail_config['spellcheck_ignore_syms'] = false; + +// Use this char/string to separate recipients when composing a new message +$rcmail_config['recipients_separator'] = ','; + // don't let users set pagesize to more than this value if set $rcmail_config['max_pagesize'] = 200; @@ -517,14 +541,21 @@ $rcmail_config['ldap_public']['Verisign'] = array( // The login name is used to search for the DN to bind with 'search_base_dn' => '', 'search_filter' => '', // e.g. '(&(objectClass=posixAccount)(uid=%u))' + // DN and password to bind as before searching for bind DN, if anonymous search is not allowed + 'search_bind_dn' => '', + 'search_bind_pw' => '', + // Default for %dn variable if search doesn't return DN value + 'search_dn_default' => '', // Optional authentication identifier to be used as SASL authorization proxy // bind_dn need to be empty 'auth_cid' => '', // SASL authentication method (for proxy auth), e.g. DIGEST-MD5 'auth_method' => '', - // Indicates if the addressbook shall be displayed on the list. + // Indicates if the addressbook shall be hidden from the list. // With this option enabled you can still search/view contacts. 'hidden' => false, + // Indicates if the addressbook shall not list contacts but only allows searching. + 'searchonly' => false, // Indicates if we can write to the LDAP directory or not. // If writable is true then these fields need to be populated: // LDAP_Object_Classes, required_fields, LDAP_rdn @@ -564,6 +595,7 @@ $rcmail_config['ldap_public']['Verisign'] = array( 'numsub_filter' => '(objectClass=organizationalUnit)', // with VLV, we also use numSubOrdinates to query the total number of records. Set this filter to get all numSubOrdinates attributes for counting 'sizelimit' => '0', // Enables you to limit the count of entries fetched. Setting this to 0 means no limit. 'timelimit' => '0', // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit. + 'referrals' => true|false, // Sets the LDAP_OPT_REFERRALS option. Mostly used in multi-domain Active Directory setups // definition for contact groups (uncomment if no groups are supported) // for the groups base_dn, the user replacements %fu, %u, $d and %dc work as for base_dn (see above) @@ -573,8 +605,8 @@ $rcmail_config['ldap_public']['Verisign'] = array( 'base_dn' => '', 'filter' => '(objectClass=groupOfNames)', 'object_classes' => array("top", "groupOfNames"), - // name of the member attribute, e.g. uniqueMember - 'member_attr' => 'member', + 'member_attr' => 'member', // name of the member attribute, e.g. uniqueMember + 'name_attr' => 'cn', // attribute to be used as group name ), ); */ @@ -601,6 +633,13 @@ $rcmail_config['autocomplete_max'] = 15; // available placeholders: {street}, {locality}, {zipcode}, {country}, {region} $rcmail_config['address_template'] = '{street}<br/>{locality} {zipcode}<br/>{country} {region}'; +// Matching mode for addressbook search (including autocompletion) +// 0 - partial (*abc*), default +// 1 - strict (abc) +// 2 - prefix (abc*) +// Note: For LDAP sources fuzzy_search must be enabled to use 'partial' or 'prefix' mode +$rcmail_config['addressbook_search_mode'] = 0; + // ---------------------------------- // USER PREFERENCES // ---------------------------------- @@ -617,8 +656,8 @@ $rcmail_config['pagesize'] = 40; // use this timezone to display date/time $rcmail_config['timezone'] = 'auto'; -// is daylight saving On? -$rcmail_config['dst_active'] = (bool)date('I'); +// is daylight saving On? Default: (bool)date('I'); +$rcmail_config['dst_active'] = null; // prefer displaying HTML messages $rcmail_config['prefer_html'] = true; @@ -748,4 +787,7 @@ $rcmail_config['default_addressbook'] = null; // Enables spell checking before sending a message. $rcmail_config['spellcheck_before_send'] = false; +// Skip alternative email addresses in autocompletion (show one address per contact) +$rcmail_config['autocomplete_single'] = false; + // end of config file diff --git a/index.php b/index.php index e3e55d7..1a7fceb 100644 --- a/index.php +++ b/index.php @@ -2,7 +2,7 @@ /* +-------------------------------------------------------------------------+ | Roundcube Webmail IMAP Client | - | Version 0.6 | + | Version 0.7 | | | | Copyright (C) 2005-2011, The Roundcube Dev Team | | | @@ -23,7 +23,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-------------------------------------------------------------------------+ - $Id: index.php 5292 2011-09-28 19:16:41Z thomasb $ + $Id: index.php 5582 2011-12-09 08:55:40Z thomasb $ */ @@ -33,6 +33,9 @@ require_once 'program/include/iniset.php'; // init application, start session, init output class, etc. $RCMAIL = rcmail::get_instance(); +// Make the whole PHP output non-cacheable (#1487797) +send_nocacheing_headers(); + // turn on output buffering ob_start(); @@ -177,7 +180,7 @@ if (empty($RCMAIL->user->ID)) { ) ); } - + if ($session_error || $_REQUEST['_err'] == 'session') $OUTPUT->show_message('sessionerror', 'error', null, true, -1); @@ -192,7 +195,7 @@ else { // check client X-header to verify request origin if ($OUTPUT->ajax_call) { if (rc_request_header('X-Roundcube-Request') != $RCMAIL->get_request_token() && !$RCMAIL->config->get('devel_mode')) { - header('HTTP/1.1 404 Not Found'); + header('HTTP/1.1 403 Forbidden'); die("Invalid Request"); } } @@ -211,6 +214,12 @@ else { } } +// we're ready, user is authenticated and the request is safe +$plugin = $RCMAIL->plugins->exec_hook('ready', array('task' => $RCMAIL->task, 'action' => $RCMAIL->action)); +$RCMAIL->set_task($plugin['task']); +$RCMAIL->action = $plugin['action']; + + // handle special actions if ($RCMAIL->action == 'keep-alive') { $OUTPUT->reset(); diff --git a/installer/rcube_install.php b/installer/rcube_install.php index ff3f7a4..dbe662a 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -142,20 +142,22 @@ class rcube_install foreach ($this->config as $prop => $default) { - $value = (isset($_POST["_$prop"]) || $this->bool_config_props[$prop]) ? $_POST["_$prop"] : $default; + $is_default = !isset($_POST["_$prop"]); + $value = !$is_default || $this->bool_config_props[$prop] ? $_POST["_$prop"] : $default; // convert some form data - if ($prop == 'debug_level') { - $val = 0; - if (is_array($value)) + if ($prop == 'debug_level' && !$is_default) { + if (is_array($value)) { + $val = 0; foreach ($value as $dbgval) $val += intval($dbgval); - $value = $val; + $value = $val; + } } else if ($which == 'db' && $prop == 'db_dsnw' && !empty($_POST['_dbtype'])) { if ($_POST['_dbtype'] == 'sqlite') $value = sprintf('%s://%s?mode=0646', $_POST['_dbtype'], $_POST['_dbname']{0} == '/' ? '/' . $_POST['_dbname'] : $_POST['_dbname']); - else + else if ($_POST['_dbtype']) $value = sprintf('%s://%s:%s@%s/%s', $_POST['_dbtype'], rawurlencode($_POST['_dbuser']), rawurlencode($_POST['_dbpass']), $_POST['_dbhost'], $_POST['_dbname']); } @@ -177,9 +179,9 @@ class rcube_install $value = '%p'; } else if ($prop == 'default_imap_folders') { - $value = Array(); + $value = array(); foreach ($this->config['default_imap_folders'] as $_folder) { - switch($_folder) { + switch ($_folder) { case 'Drafts': $_folder = $this->config['drafts_mbox']; break; case 'Sent': $_folder = $this->config['sent_mbox']; break; case 'Junk': $_folder = $this->config['junk_mbox']; break; @@ -206,7 +208,7 @@ class rcube_install // replace the matching line in config file $out = preg_replace( '/(\$rcmail_config\[\''.preg_quote($prop).'\'\])\s+=\s+(.+);/Uie', - "'\\1 = ' . rcube_install::_dump_var(\$value) . ';'", + "'\\1 = ' . rcube_install::_dump_var(\$value, \$prop) . ';'", $out); } @@ -299,7 +301,7 @@ class rcube_install $current = $this->config; $this->config = array(); $this->load_defaults(); - + foreach ($this->replaced_config as $prop => $replacement) { if (isset($current[$prop])) { if ($prop == 'skin_path') @@ -328,9 +330,9 @@ class rcube_install if ($current['keep_alive'] && $current['session_lifetime'] < $current['keep_alive']) $current['session_lifetime'] = max(10, ceil($current['keep_alive'] / 60) * 2); - + $this->config = array_merge($this->config, $current); - + foreach ((array)$current['ldap_public'] as $key => $values) { $this->config['ldap_public'][$key] = $current['ldap_public'][$key]; } @@ -614,7 +616,22 @@ class rcube_install } - static function _dump_var($var) { + static function _dump_var($var, $name=null) { + // special values + switch ($name) { + case 'syslog_facility': + $list = array(32 => 'LOG_AUTH', 80 => 'LOG_AUTHPRIV', 72 => ' LOG_CRON', + 24 => 'LOG_DAEMON', 0 => 'LOG_KERN', 128 => 'LOG_LOCAL0', + 136 => 'LOG_LOCAL1', 144 => 'LOG_LOCAL2', 152 => 'LOG_LOCAL3', + 160 => 'LOG_LOCAL4', 168 => 'LOG_LOCAL5', 176 => 'LOG_LOCAL6', + 184 => 'LOG_LOCAL7', 48 => 'LOG_LPR', 16 => 'LOG_MAIL', + 56 => 'LOG_NEWS', 40 => 'LOG_SYSLOG', 8 => 'LOG_USER', 64 => 'LOG_UUCP'); + if ($val = $list[$var]) + return $val; + break; + } + + if (is_array($var)) { if (empty($var)) { return 'array()'; diff --git a/installer/test.php b/installer/test.php index 02a1ceb..2dd3305 100644 --- a/installer/test.php +++ b/installer/test.php @@ -382,18 +382,20 @@ $pass_field = new html_passwordfield(array('name' => '_pass', 'id' => 'imappass' <?php if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user'])) { - + echo '<p>Connecting to ' . Q($_POST['_host']) . '...<br />'; - - $a_host = parse_url($_POST['_host']); + + $imap_host = trim($_POST['_host']); + $imap_port = $RCI->getprop('default_port'); + $a_host = parse_url($imap_host); + if ($a_host['host']) { $imap_host = $a_host['host']; - $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; - $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : $CONFIG['default_port']); - } - else { - $imap_host = trim($_POST['_host']); - $imap_port = $RCI->getprop('default_port'); + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; + if (isset($a_host['port'])) + $imap_port = $a_host['port']; + else if ($imap_ssl && $imap_ssl != 'tls' && (!$imap_port || $imap_port == 143)) + $imap_port = 993; } $imap_host = idn_to_ascii($imap_host); diff --git a/plugins/acl/acl.js b/plugins/acl/acl.js index 4b1431a..c4011a8 100644 --- a/plugins/acl/acl.js +++ b/plugins/acl/acl.js @@ -1,7 +1,7 @@ /** * ACL plugin script * - * @version 0.6.1 + * @version 0.6.3 * @author Aleksander Machniak <alec@alec.pl> */ @@ -315,6 +315,9 @@ rcube_webmail.prototype.acl_init_form = function(id) this.acl_form.show(); if (type == 'user') name_input.focus(); + + // unfocus the list, make backspace key in name input field working + this.acl_list.blur(); } // Returns class name according to ACL comparision result diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 976b362..3a5fd1a 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -3,7 +3,7 @@ /** * Folders Access Control Lists Management (RFC4314, RFC2086) * - * @version 0.6.1 + * @version @package_version@ * @author Aleksander Machniak <alec@alec.pl> * * @@ -87,11 +87,15 @@ class acl extends rcube_plugin $this->load_config(); $search = get_input_value('_search', RCUBE_INPUT_GPC, true); + $sid = get_input_value('_id', RCUBE_INPUT_GPC); $users = array(); if ($this->init_ldap()) { - $this->ldap->set_pagesize(15); - $result = $this->ldap->search('*', $search); + $max = (int) $this->rc->config->get('autocomplete_max', 15); + $mode = (int) $this->rc->config->get('addressbook_search_mode'); + + $this->ldap->set_pagesize($max); + $result = $this->ldap->search('*', $search, $mode); foreach ($result->records as $record) { $user = $record['uid']; @@ -112,7 +116,7 @@ class acl extends rcube_plugin sort($users, SORT_LOCALE_STRING); - $this->rc->output->command('ksearch_query_results', $users, $search); + $this->rc->output->command('ksearch_query_results', $users, $search, $sid); $this->rc->output->send(); } @@ -186,6 +190,10 @@ class acl extends rcube_plugin 'aclrights' => array($this, 'templ_rights'), )); + $this->rc->output->set_env('autocomplete_max', (int)$this->rc->config->get('autocomplete_max', 15)); + $this->rc->output->set_env('autocomplete_min_length', $this->rc->config->get('autocomplete_min_length')); + $this->rc->output->add_label('autocompletechars', 'autocompletemore'); + $args['form']['sharing'] = array( 'name' => Q($this->gettext('sharing')), 'content' => $this->rc->output->parse('acl.table', false, false), @@ -619,7 +627,6 @@ class acl extends rcube_plugin $acl = $this->rc->imap->get_acl('INBOX'); if (is_array($acl)) { $regexp = '/^' . preg_quote($_SESSION['username'], '/') . '@(.*)$/'; - $regexp = '/^' . preg_quote('aleksander.machniak', '/') . '@(.*)$/'; foreach (array_keys($acl) as $name) { if (preg_match($regexp, $name, $matches)) { $domain = $matches[1]; diff --git a/plugins/acl/skins/default/acl.css b/plugins/acl/skins/default/acl.css index e46a1d0..cf3391f 100644 --- a/plugins/acl/skins/default/acl.css +++ b/plugins/acl/skins/default/acl.css @@ -61,6 +61,12 @@ background-color: #CC3333; } +#acltable tr.unfocused td +{ + color: #FFFFFF; + background-color: #929292; +} + #acladvswitch { position: absolute; diff --git a/plugins/archive/archive.js b/plugins/archive/archive.js index a837508..5c576e1 100644 --- a/plugins/archive/archive.js +++ b/plugins/archive/archive.js @@ -27,7 +27,9 @@ if (window.rcmail) { // set css style for archive folder var li; - if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon && (li = rcmail.get_folder_li(rcmail.env.archive_folder))) + if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon + && (li = rcmail.get_folder_li(rcmail.env.archive_folder, '', true)) + ) $(li).css('background-image', 'url(' + rcmail.env.archive_folder_icon + ')'); }) } diff --git a/plugins/archive/archive.php b/plugins/archive/archive.php index 843b612..a568062 100644 --- a/plugins/archive/archive.php +++ b/plugins/archive/archive.php @@ -100,7 +100,7 @@ class archive extends rcube_plugin // load folders list when needed if ($CURR_SECTION) $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, - 'maxlength' => 30, 'exceptions' => array('INBOX'))); + 'maxlength' => 30, 'exceptions' => array('INBOX'), 'folder_filter' => 'mail', 'folder_rights' => 'w')); else $select = new html_select(); diff --git a/plugins/archive/localization/fr_FR.inc b/plugins/archive/localization/fr_FR.inc index f44f30f..498a091 100644 --- a/plugins/archive/localization/fr_FR.inc +++ b/plugins/archive/localization/fr_FR.inc @@ -2,7 +2,7 @@ $labels = array(); $labels['buttontitle'] = 'Archiver ce message'; -$labels['archived'] = 'Message archivé avec success'; +$labels['archived'] = 'Message archivé avec success'; $labels['archivefolder'] = 'Archive'; ?> diff --git a/plugins/archive/package.xml b/plugins/archive/package.xml index c442a5c..c549fc9 100644 --- a/plugins/archive/package.xml +++ b/plugins/archive/package.xml @@ -13,10 +13,9 @@ <email>roundcube@gmail.com</email> <active>yes</active> </lead> - <date>2010-02-06</date> - <time>12:12:00</time> + <date>2011-11-23</date> <version> - <release>1.4</release> + <release>1.5</release> <api>1.4</api> </version> <stability> @@ -35,14 +34,21 @@ <tasks:replace from="@name@" to="name" type="package-info"/> <tasks:replace from="@package_version@" to="version" type="package-info"/> </file> - <file name="localization/en_US.inc" role="data"></file> <file name="localization/cs_CZ.inc" role="data"></file> <file name="localization/de_CH.inc" role="data"></file> <file name="localization/de_DE.inc" role="data"></file> + <file name="localization/en_US.inc" role="data"></file> + <file name="localization/es_AR.inc" role="data"></file> + <file name="localization/es_ES.inc" role="data"></file> <file name="localization/et_EE.inc" role="data"></file> <file name="localization/fr_FR.inc" role="data"></file> + <file name="localization/gl_ES.inc" role="data"></file> + <file name="localization/ja_JP.inc" role="data"></file> + <file name="localization/nl_NL.inc" role="data"></file> <file name="localization/pl_PL.inc" role="data"></file> + <file name="localization/pt_BR.inc" role="data"></file> <file name="localization/ru_RU.inc" role="data"></file> + <file name="localization/sv_SE.inc" role="data"></file> <file name="localization/zh_TW.inc" role="data"></file> <file name="skins/default/archive_act.png" role="data"></file> <file name="skins/default/archive_pas.png" role="data"></file> diff --git a/plugins/enigma/README b/plugins/enigma/README index afb2322..22d6e51 100644 --- a/plugins/enigma/README +++ b/plugins/enigma/README @@ -18,7 +18,7 @@ Enigma Plugin Status: - Parsing of decrypted messages into array (see rcube_mime_struct) and then into rcube_message_part structure (create core class rcube_mime_parser or take over PEAR::Mail_mimeDecode package and improve it) - Sending encrypted/signed messages (probably some changes in core will be needed) -- Per-Identity settings (including keys/certs) (+ split Identities details page into tabs) +- Per-Identity settings (including keys/certs) - Handling big messages with temp files (including changes in Roundcube core) - Performance improvements (some caching, code review) - better (and more) icons diff --git a/plugins/enigma/config.inc.php b/plugins/enigma/config.inc.php.dist similarity index 100% rename from plugins/enigma/config.inc.php rename to plugins/enigma/config.inc.php.dist diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index b9ccff5..5901b58 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -412,9 +412,6 @@ class enigma_ui private function compose_ui() { - if (!is_array($_SESSION['compose']) || $_SESSION['compose']['id'] != get_input_value('_id', RCUBE_INPUT_GET)) - return; - // Options menu button // @TODO: make this work with non-default skins $this->enigma->add_button(array( diff --git a/plugins/http_authentication/http_authentication.php b/plugins/http_authentication/http_authentication.php index fa074f0..be49b52 100644 --- a/plugins/http_authentication/http_authentication.php +++ b/plugins/http_authentication/http_authentication.php @@ -53,7 +53,7 @@ class http_authentication extends rcube_plugin return $args; } - + function logout($args) { // redirect to configured URL in order to clear HTTP auth credentials diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index e354064..0550612 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,4 +1,36 @@ +- Fixed setting test type to :is when none is specified +- Fixed javascript error in IE8 + +* version 5.0-rc1 [2011-11-17] +----------------------------------------------------------- +- Fixed sorting of scripts, scripts including aware of the sort order +- Fixed import of rules with unsupported tests +- Added 'address' and 'envelope' tests support +- Added 'body' extension support (RFC5173) +- Added 'subaddress' extension support (RFC5233) +- Added comparators support +- Changed Sender/Recipient labels to From/To +- Fixed importing rule names from Ingo +- Fixed handling of extensions disabled in config + +* version 5.0-beta [2011-10-17] +----------------------------------------------------------- +- Added possibility to create a filter based on selected message "in-place" - Fixed import from Horde-INGO (#1488064) +- Add managesieve_script_name option for default name of the script (#1487956) +- Fixed handling of enabled magic_quotes_gpc setting +- Fixed PHP warning on connection error when submitting filter form +- Fixed bug where new action row with flags wasn't handled properly +- Added managesieve_connect hook for plugins +- Fixed doubled Filter tab on page refresh +- Added filters set selector in filter form when invoked in mail task +- Improved script parser, added support for include and variables extensions +- Added Kolab's KEP:14 support (http://wiki.kolab.org/User:Greve/Drafts/KEP:14) +- Use smaller action/rule buttons +- UI redesign: added possibility to move filter to any place using drag&drop + (instead of up/down buttons), added filter sets list object, added more + 'loading' messages +- Added option to hide some scripts (managesieve_filename_exceptions) * version 4.3 [2011-07-28] ----------------------------------------------------------- diff --git a/plugins/managesieve/config.inc.php.dist b/plugins/managesieve/config.inc.php.dist index 905cfef..cb9b2a9 100644 --- a/plugins/managesieve/config.inc.php.dist +++ b/plugins/managesieve/config.inc.php.dist @@ -31,6 +31,9 @@ $rcmail_config['managesieve_usetls'] = false; // default contents of filters script (eg. default spam filter) $rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global'; +// The name of the script which will be used when there's no user script +$rcmail_config['managesieve_script_name'] = 'managesieve'; + // Sieve RFC says that we should use UTF-8 endcoding for mailbox names, // but some implementations does not covert UTF-8 to modified UTF-7. // Defaults to UTF7-IMAP @@ -50,4 +53,15 @@ $rcmail_config['managesieve_disabled_extensions'] = array(); // Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve $rcmail_config['managesieve_debug'] = false; +// Enables features described in http://wiki.kolab.org/KEP:14 +$rcmail_config['managesieve_kolab_master'] = false; + +// Script name extension used for scripts including. Dovecot uses '.sieve', +// Cyrus uses '.siv'. Doesn't matter if you have managesieve_kolab_master disabled. +$rcmail_config['managesieve_filename_extension'] = '.sieve'; + +// List of reserved script names (without extension). +// Scripts listed here will be not presented to the user. +$rcmail_config['managesieve_filename_exceptions'] = array(); + ?> diff --git a/plugins/managesieve/lib/rcube_sieve.php b/plugins/managesieve/lib/rcube_sieve.php index 3e52809..7c4f0aa 100644 --- a/plugins/managesieve/lib/rcube_sieve.php +++ b/plugins/managesieve/lib/rcube_sieve.php @@ -1,13 +1,27 @@ <?php /** - Classes for managesieve operations (using PEAR::Net_Sieve) - - Author: Aleksander Machniak <alec@alec.pl> - - $Id: rcube_sieve.php 5203 2011-09-12 06:44:56Z alec $ - -*/ + * Classes for managesieve operations (using PEAR::Net_Sieve) + * + * Copyright (C) 2008-2011, The Roundcube Dev Team + * Copyright (C) 2011, Kolab Systems AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * $Id: rcube_sieve.php 5452 2011-11-18 14:44:48Z alec $ + * + */ // Managesieve Protocol: RFC5804 @@ -30,7 +44,6 @@ class rcube_sieve public $script; // rcube_sieve_script object public $current; // name of currently loaded script - private $disabled; // array of disabled extensions private $exts; // array of supported extensions @@ -75,7 +88,17 @@ class rcube_sieve } $this->exts = $this->get_extensions(); - $this->disabled = $disabled; + + // disable features by config + if (!empty($disabled)) { + // we're working on lower-cased names + $disabled = array_map('strtolower', (array) $disabled); + foreach ($disabled as $ext) { + if (($idx = array_search($ext, $this->exts)) !== false) { + unset($this->exts[$idx]); + } + } + } } public function __destruct() { @@ -195,7 +218,7 @@ class rcube_sieve { if ($this->exts) return $this->exts; - + if (!$this->sieve) return $this->_set_error(SIEVE_ERROR_INTERNAL); @@ -286,23 +309,28 @@ class rcube_sieve */ private function _parse($txt) { - // try to parse from Roundcube format - $script = new rcube_sieve_script($txt, $this->disabled, $this->exts); - - // ... else try to import from different formats - if (empty($script->content)) { - $script = $this->_import_rules($txt); - $script = new rcube_sieve_script($script, $this->disabled, $this->exts); + // parse + $script = new rcube_sieve_script($txt, $this->exts); + // fix/convert to Roundcube format + if (!empty($script->content)) { // replace all elsif with if+stop, we support only ifs foreach ($script->content as $idx => $rule) { + if (empty($rule['type']) || !preg_match('/^(if|elsif|else)$/', $rule['type'])) { + continue; + } + + $script->content[$idx]['type'] = 'if'; + // 'stop' not found? foreach ($rule['actions'] as $action) { if (preg_match('/^(stop|vacation)$/', $action['type'])) { continue 2; } } - $script->content[$idx]['actions'][] = array('type' => 'stop'); + if (empty($script->content[$idx+1]) || $script->content[$idx+1]['type'] != 'if') { + $script->content[$idx]['actions'][] = array('type' => 'stop'); + } } } @@ -343,48 +371,6 @@ class rcube_sieve return $this->save_script($name, $content); } - private function _import_rules($script) - { - $i = 0; - $name = array(); - - // Squirrelmail (Avelsieve) - if (preg_match('/(#START_SIEVE_RULE.*END_SIEVE_RULE)\r?\n/', $script)) { - $tokens = preg_split('/(#START_SIEVE_RULE.*END_SIEVE_RULE)\r?\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE); - foreach ($tokens as $token) { - if (preg_match('/^#START_SIEVE_RULE.*/', $token, $matches)) { - $name[$i] = "unnamed rule ".($i+1); - $content .= "# rule:[".$name[$i]."]\n"; - } - elseif (isset($name[$i])) { - // This preg_replace is added because I've found some Avelsieve scripts - // with rules containing "if" here. I'm not sure it was working - // before without this or not. - $token = preg_replace('/^if\s+/', '', trim($token)); - $content .= "if $token\n"; - $i++; - } - } - } - // Horde (INGO) - else if (preg_match('/(# .+)\r?\n/', $script)) { - $tokens = preg_split('/(# .+)\r?\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE); - foreach($tokens as $token) { - if (preg_match('/^# (.+)/', $token, $matches)) { - $name[$i] = $matches[1]; - $content .= "# rule:[" . $name[$i] . "]\n"; - } - elseif (isset($name[$i])) { - $token = str_replace(":comparator \"i;ascii-casemap\" ", "", $token); - $content .= $token . "\n"; - $i++; - } - } - } - - return $content; - } - private function _set_error($error) { $this->error = $error; diff --git a/plugins/managesieve/lib/rcube_sieve_script.php b/plugins/managesieve/lib/rcube_sieve_script.php index 871fb14..04bcc4c 100644 --- a/plugins/managesieve/lib/rcube_sieve_script.php +++ b/plugins/managesieve/lib/rcube_sieve_script.php @@ -1,20 +1,37 @@ <?php /** - Class for operations on Sieve scripts - - Author: Aleksander Machniak <alec@alec.pl> - - $Id: rcube_sieve_script.php 4806 2011-05-24 08:32:01Z alec $ - -*/ + * Class for operations on Sieve scripts + * + * Copyright (C) 2008-2011, The Roundcube Dev Team + * Copyright (C) 2011, Kolab Systems AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * $Id: rcube_sieve_script.php 5452 2011-11-18 14:44:48Z alec $ + * + */ class rcube_sieve_script { public $content = array(); // script rules array - private $supported = array( // extensions supported by class - 'fileinto', // RFC3028 + private $vars = array(); // "global" variables + private $prefix = ''; // script header (comments) + private $supported = array( // Sieve extensions supported by class + 'fileinto', // RFC5228 + 'envelope', // RFC5228 'reject', // RFC5429 'ereject', // RFC5429 'copy', // RFC3894 @@ -23,57 +40,34 @@ class rcube_sieve_script 'regex', // draft-ietf-sieve-regex-01 'imapflags', // draft-melnikov-sieve-imapflags-06 'imap4flags', // RFC5232 - // TODO: body, notify + 'include', // draft-ietf-sieve-include-12 + 'variables', // RFC5229 + 'body', // RFC5173 + 'subaddress', // RFC5233 + // @TODO: enotify/notify, spamtest+virustest, mailbox, date ); - private $capabilities; - /** * Object constructor * * @param string Script's text content - * @param array List of disabled extensions * @param array List of capabilities supported by server */ - public function __construct($script, $disabled=null, $capabilities=null) + public function __construct($script, $capabilities=array()) { - if (!empty($disabled)) { - // we're working on lower-cased names - $disabled = array_map('strtolower', (array) $disabled); - foreach ($disabled as $ext) { - if (($idx = array_search($ext, $this->supported)) !== false) { + $capabilities = array_map('strtolower', (array) $capabilities); + + // disable features by server capabilities + if (!empty($capabilities)) { + foreach ($this->supported as $idx => $ext) { + if (!in_array($ext, $capabilities)) { unset($this->supported[$idx]); } } } - $this->capabilities = $capabilities; - $this->content = $this->_parse_text($script); - } - - /** - * Adds script contents as text to the script array (at the end) - * - * @param string Text script contents - */ - public function add_text($script) - { - $content = $this->_parse_text($script); - $result = false; - - // check existsing script rules names - foreach ($this->content as $idx => $elem) { - $names[$elem['name']] = $idx; - } - - foreach ($content as $elem) { - if (!isset($names[$elem['name']])) { - array_push($this->content, $elem); - $result = true; - } - } - - return $result; + // Parse text content of the script + $this->_parse_text($script); } /** @@ -81,6 +75,8 @@ class rcube_sieve_script * * @param string Rule name * @param array Rule content (as array) + * + * @return int The index of the new rule */ public function add_rule($content) { @@ -113,162 +109,344 @@ class rcube_sieve_script return false; } + /** + * Sets "global" variable + * + * @param string $name Variable name + * @param string $value Variable value + * @param array $mods Variable modifiers + */ + public function set_var($name, $value, $mods = array()) + { + // Check if variable exists + for ($i=0, $len=count($this->vars); $i<$len; $i++) { + if ($this->vars[$i]['name'] == $name) { + break; + } + } + + $var = array_merge($mods, array('name' => $name, 'value' => $value)); + $this->vars[$i] = $var; + } + + /** + * Unsets "global" variable + * + * @param string $name Variable name + */ + public function unset_var($name) + { + // Check if variable exists + foreach ($this->vars as $idx => $var) { + if ($var['name'] == $name) { + unset($this->vars[$idx]); + break; + } + } + } + + /** + * Gets the value of "global" variable + * + * @param string $name Variable name + * + * @return string Variable value + */ + public function get_var($name) + { + // Check if variable exists + for ($i=0, $len=count($this->vars); $i<$len; $i++) { + if ($this->vars[$i]['name'] == $name) { + return $this->vars[$i]['name']; + } + } + } + + /** + * Sets script header content + * + * @param string $text Header content + */ + public function set_prefix($text) + { + $this->prefix = $text; + } + /** * Returns script as text */ public function as_text() { - $script = ''; - $exts = array(); - $idx = 0; + $output = ''; + $exts = array(); + $idx = 0; + + if (!empty($this->vars)) { + if (in_array('variables', (array)$this->supported)) { + $has_vars = true; + array_push($exts, 'variables'); + } + foreach ($this->vars as $var) { + if (empty($has_vars)) { + // 'variables' extension not supported, put vars in comments + $output .= sprintf("# %s %s\n", $var['name'], $var['value']); + } + else { + $output .= 'set '; + foreach (array_diff(array_keys($var), array('name', 'value')) as $opt) { + $output .= ":$opt "; + } + $output .= self::escape_string($var['name']) . ' ' . self::escape_string($var['value']) . ";\n"; + } + } + } // rules foreach ($this->content as $rule) { $extension = ''; - $tests = array(); - $i = 0; + $script = ''; + $tests = array(); + $i = 0; // header - $script .= '# rule:[' . $rule['name'] . "]\n"; + if (!empty($rule['name']) && strlen($rule['name'])) { + $script .= '# rule:[' . $rule['name'] . "]\n"; + } // constraints expressions - foreach ($rule['tests'] as $test) { - $tests[$i] = ''; - switch ($test['test']) { - case 'size': - $tests[$i] .= ($test['not'] ? 'not ' : ''); - $tests[$i] .= 'size :' . ($test['type']=='under' ? 'under ' : 'over ') . $test['arg']; - break; - case 'true': - $tests[$i] .= ($test['not'] ? 'false' : 'true'); - break; - case 'exists': - $tests[$i] .= ($test['not'] ? 'not ' : ''); - $tests[$i] .= 'exists ' . self::escape_string($test['arg']); - break; - case 'header': - $tests[$i] .= ($test['not'] ? 'not ' : ''); + if (!empty($rule['tests'])) { + foreach ($rule['tests'] as $test) { + $tests[$i] = ''; + switch ($test['test']) { + case 'size': + $tests[$i] .= ($test['not'] ? 'not ' : ''); + $tests[$i] .= 'size :' . ($test['type']=='under' ? 'under ' : 'over ') . $test['arg']; + break; - // relational operator + comparator - if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) { - array_push($exts, 'relational'); - array_push($exts, 'comparator-i;ascii-numeric'); + case 'true': + $tests[$i] .= ($test['not'] ? 'false' : 'true'); + break; - $tests[$i] .= 'header :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"'; - } - else { - if ($test['type'] == 'regex') { - array_push($exts, 'regex'); + case 'exists': + $tests[$i] .= ($test['not'] ? 'not ' : ''); + $tests[$i] .= 'exists ' . self::escape_string($test['arg']); + break; + + case 'header': + $tests[$i] .= ($test['not'] ? 'not ' : ''); + $tests[$i] .= 'header'; + + if (!empty($test['type'])) { + // relational operator + comparator + if (preg_match('/^(value|count)-([gteqnl]{2})/', $test['type'], $m)) { + array_push($exts, 'relational'); + array_push($exts, 'comparator-i;ascii-numeric'); + + $tests[$i] .= ' :' . $m[1] . ' "' . $m[2] . '" :comparator "i;ascii-numeric"'; + } + else { + $this->add_comparator($test, $tests[$i], $exts); + + if ($test['type'] == 'regex') { + array_push($exts, 'regex'); + } + + $tests[$i] .= ' :' . $test['type']; + } } - $tests[$i] .= 'header :' . $test['type']; - } + $tests[$i] .= ' ' . self::escape_string($test['arg1']); + $tests[$i] .= ' ' . self::escape_string($test['arg2']); + break; - $tests[$i] .= ' ' . self::escape_string($test['arg1']); - $tests[$i] .= ' ' . self::escape_string($test['arg2']); - break; + case 'address': + case 'envelope': + if ($test['test'] == 'envelope') { + array_push($exts, 'envelope'); + } + + $tests[$i] .= ($test['not'] ? 'not ' : ''); + $tests[$i] .= $test['test']; + + if (!empty($test['part'])) { + $tests[$i] .= ' :' . $test['part']; + if ($test['part'] == 'user' || $test['part'] == 'detail') { + array_push($exts, 'subaddress'); + } + } + + $this->add_comparator($test, $tests[$i], $exts); + + if (!empty($test['type'])) { + if ($test['type'] == 'regex') { + array_push($exts, 'regex'); + } + $tests[$i] .= ' :' . $test['type']; + } + + $tests[$i] .= ' ' . self::escape_string($test['arg1']); + $tests[$i] .= ' ' . self::escape_string($test['arg2']); + break; + + case 'body': + array_push($exts, 'body'); + + $tests[$i] .= ($test['not'] ? 'not ' : '') . 'body'; + + $this->add_comparator($test, $tests[$i], $exts); + + if (!empty($test['part'])) { + $tests[$i] .= ' :' . $test['part']; + + if (!empty($test['content']) && $test['part'] == 'content') { + $tests[$i] .= ' ' . self::escape_string($test['content']); + } + } + + if (!empty($test['type'])) { + if ($test['type'] == 'regex') { + array_push($exts, 'regex'); + } + $tests[$i] .= ' :' . $test['type']; + } + + $tests[$i] .= ' ' . self::escape_string($test['arg']); + break; + } + $i++; } - $i++; } // disabled rule: if false #.... - $script .= 'if ' . ($rule['disabled'] ? 'false # ' : ''); + if (!empty($tests)) { + $script .= 'if ' . ($rule['disabled'] ? 'false # ' : ''); - if (empty($tests)) { - $tests_str = 'true'; - } - else if (count($tests) > 1) { - $tests_str = implode(', ', $tests); - } - else { - $tests_str = $tests[0]; - } + if (count($tests) > 1) { + $tests_str = implode(', ', $tests); + } + else { + $tests_str = $tests[0]; + } - if ($rule['join'] || count($tests) > 1) { - $script .= sprintf('%s (%s)', $rule['join'] ? 'allof' : 'anyof', $tests_str); - } - else { - $script .= $tests_str; + if ($rule['join'] || count($tests) > 1) { + $script .= sprintf('%s (%s)', $rule['join'] ? 'allof' : 'anyof', $tests_str); + } + else { + $script .= $tests_str; + } + $script .= "\n{\n"; } - $script .= "\n{\n"; // action(s) - foreach ($rule['actions'] as $action) { - switch ($action['type']) { + if (!empty($rule['actions'])) { + foreach ($rule['actions'] as $action) { + $action_script = ''; + + switch ($action['type']) { + + case 'fileinto': + array_push($exts, 'fileinto'); + $action_script .= 'fileinto '; + if ($action['copy']) { + $action_script .= ':copy '; + array_push($exts, 'copy'); + } + $action_script .= self::escape_string($action['target']); + break; - case 'fileinto': - array_push($exts, 'fileinto'); - $script .= "\tfileinto "; - if ($action['copy']) { - $script .= ':copy '; - array_push($exts, 'copy'); - } - $script .= self::escape_string($action['target']) . ";\n"; - break; + case 'redirect': + $action_script .= 'redirect '; + if ($action['copy']) { + $action_script .= ':copy '; + array_push($exts, 'copy'); + } + $action_script .= self::escape_string($action['target']); + break; - case 'redirect': - $script .= "\tredirect "; - if ($action['copy']) { - $script .= ':copy '; - array_push($exts, 'copy'); - } - $script .= self::escape_string($action['target']) . ";\n"; - break; + case 'reject': + case 'ereject': + array_push($exts, $action['type']); + $action_script .= $action['type'].' ' + . self::escape_string($action['target']); + break; - case 'reject': - case 'ereject': - array_push($exts, $action['type']); - $script .= "\t".$action['type']." " - . self::escape_string($action['target']) . ";\n"; - break; + case 'addflag': + case 'setflag': + case 'removeflag': + if (in_array('imap4flags', $this->supported)) + array_push($exts, 'imap4flags'); + else + array_push($exts, 'imapflags'); - case 'addflag': - case 'setflag': - case 'removeflag': - if (is_array($this->capabilities) && in_array('imap4flags', $this->capabilities)) - array_push($exts, 'imap4flags'); - else - array_push($exts, 'imapflags'); + $action_script .= $action['type'].' ' + . self::escape_string($action['target']); + break; - $script .= "\t".$action['type']." " - . self::escape_string($action['target']) . ";\n"; - break; + case 'keep': + case 'discard': + case 'stop': + $action_script .= $action['type']; + break; - case 'keep': - case 'discard': - case 'stop': - $script .= "\t" . $action['type'] .";\n"; - break; + case 'include': + array_push($exts, 'include'); + $action_script .= 'include '; + foreach (array_diff(array_keys($action), array('target', 'type')) as $opt) { + $action_script .= ":$opt "; + } + $action_script .= self::escape_string($action['target']); + break; - case 'vacation': - array_push($exts, 'vacation'); - $script .= "\tvacation"; - if (!empty($action['days'])) - $script .= " :days " . $action['days']; - if (!empty($action['addresses'])) - $script .= " :addresses " . self::escape_string($action['addresses']); - if (!empty($action['subject'])) - $script .= " :subject " . self::escape_string($action['subject']); - if (!empty($action['handle'])) - $script .= " :handle " . self::escape_string($action['handle']); - if (!empty($action['from'])) - $script .= " :from " . self::escape_string($action['from']); - if (!empty($action['mime'])) - $script .= " :mime"; - $script .= " " . self::escape_string($action['reason']) . ";\n"; - break; + case 'set': + array_push($exts, 'variables'); + $action_script .= 'set '; + foreach (array_diff(array_keys($action), array('name', 'value', 'type')) as $opt) { + $action_script .= ":$opt "; + } + $action_script .= self::escape_string($action['name']) . ' ' . self::escape_string($action['value']); + break; + + case 'vacation': + array_push($exts, 'vacation'); + $action_script .= 'vacation'; + if (!empty($action['days'])) + $action_script .= " :days " . $action['days']; + if (!empty($action['addresses'])) + $action_script .= " :addresses " . self::escape_string($action['addresses']); + if (!empty($action['subject'])) + $action_script .= " :subject " . self::escape_string($action['subject']); + if (!empty($action['handle'])) + $action_script .= " :handle " . self::escape_string($action['handle']); + if (!empty($action['from'])) + $action_script .= " :from " . self::escape_string($action['from']); + if (!empty($action['mime'])) + $action_script .= " :mime"; + $action_script .= " " . self::escape_string($action['reason']); + break; + } + + if ($action_script) { + $script .= !empty($tests) ? "\t" : ''; + $script .= $action_script . ";\n"; + } } } - $script .= "}\n"; - $idx++; + if ($script) { + $output .= $script . (!empty($tests) ? "}\n" : ''); + $idx++; + } } // requires if (!empty($exts)) - $script = 'require ["' . implode('","', array_unique($exts)) . "\"];\n" . $script; + $output = 'require ["' . implode('","', array_unique($exts)) . "\"];\n" . $output; - return $script; + if (!empty($this->prefix)) { + $output = $this->prefix . "\n\n" . $output; + } + + return $output; } /** @@ -296,35 +474,89 @@ class rcube_sieve_script */ private function _parse_text($script) { - $i = 0; - $content = array(); + $prefix = ''; + $options = array(); + + while ($script) { + $script = trim($script); + $rule = array(); + + // Comments + while (!empty($script) && $script[0] == '#') { + $endl = strpos($script, "\n"); + $line = $endl ? substr($script, 0, $endl) : $script; + + // Roundcube format + if (preg_match('/^# rule:\[(.*)\]/', $line, $matches)) { + $rulename = $matches[1]; + } + // KEP:14 variables + else if (preg_match('/^# (EDITOR|EDITOR_VERSION) (.+)$/', $line, $matches)) { + $this->set_var($matches[1], $matches[2]); + } + // Horde-Ingo format + else if (!empty($options['format']) && $options['format'] == 'INGO' + && preg_match('/^# (.*)/', $line, $matches) + ) { + $rulename = $matches[1]; + } + else if (empty($options['prefix'])) { + $prefix .= $line . "\n"; + } + + $script = ltrim(substr($script, strlen($line) + 1)); + } + + // handle script header + if (empty($options['prefix'])) { + $options['prefix'] = true; + if ($prefix && strpos($prefix, 'horde.org/ingo')) { + $options['format'] = 'INGO'; + } + } - // tokenize rules - if ($tokens = preg_split('/(# rule:\[.*\])\r?\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE)) { - foreach($tokens as $token) { - if (preg_match('/^# rule:\[(.*)\]/', $token, $matches)) { - $content[$i]['name'] = $matches[1]; + // Control structures/blocks + if (preg_match('/^(if|else|elsif)/i', $script)) { + $rule = $this->_tokenize_rule($script); + if (strlen($rulename) && !empty($rule)) { + $rule['name'] = $rulename; } - else if (isset($content[$i]['name']) && sizeof($content[$i]) == 1) { - if ($rule = $this->_tokenize_rule($token)) { - $content[$i] = array_merge($content[$i], $rule); - $i++; + } + // Simple commands + else { + $rule = $this->_parse_actions($script, ';'); + if (!empty($rule[0]) && is_array($rule)) { + // set "global" variables + if ($rule[0]['type'] == 'set') { + unset($rule[0]['type']); + $this->vars[] = $rule[0]; + } + else { + $rule = array('actions' => $rule); } - else // unknown rule format - unset($content[$i]); } } + + $rulename = ''; + + if (!empty($rule)) { + $this->content[] = $rule; + } } - return $content; + if (!empty($prefix)) { + $this->prefix = trim($prefix); + } } /** * Convert text script fragment to rule object * * @param string Text rule + * + * @return array Rule data */ - private function _tokenize_rule($content) + private function _tokenize_rule(&$content) { $cond = strtolower(self::tokenize($content, 1)); @@ -389,7 +621,7 @@ class rcube_sieve_script $header = array('test' => 'header', 'not' => $not, 'arg1' => '', 'arg2' => ''); for ($i=0, $len=count($tokens); $i<$len; $i++) { if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { - $i++; + $header['comparator'] = $tokens[++$i]; } else if (!is_array($tokens[$i]) && preg_match('/^:(count|value)$/i', $tokens[$i])) { $header['type'] = strtolower(substr($tokens[$i], 1)) . '-' . $tokens[++$i]; @@ -406,6 +638,52 @@ class rcube_sieve_script $tests[] = $header; break; + case 'address': + case 'envelope': + $header = array('test' => $token, 'not' => $not, 'arg1' => '', 'arg2' => ''); + for ($i=0, $len=count($tokens); $i<$len; $i++) { + if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { + $header['comparator'] = $tokens[++$i]; + } + else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) { + $header['type'] = strtolower(substr($tokens[$i], 1)); + } + else if (!is_array($tokens[$i]) && preg_match('/^:(localpart|domain|all|user|detail)$/i', $tokens[$i])) { + $header['part'] = strtolower(substr($tokens[$i], 1)); + } + else { + $header['arg1'] = $header['arg2']; + $header['arg2'] = $tokens[$i]; + } + } + + $tests[] = $header; + break; + + case 'body': + $header = array('test' => 'body', 'not' => $not, 'arg' => ''); + for ($i=0, $len=count($tokens); $i<$len; $i++) { + if (!is_array($tokens[$i]) && preg_match('/^:comparator$/i', $tokens[$i])) { + $header['comparator'] = $tokens[++$i]; + } + else if (!is_array($tokens[$i]) && preg_match('/^:(is|contains|matches|regex)$/i', $tokens[$i])) { + $header['type'] = strtolower(substr($tokens[$i], 1)); + } + else if (!is_array($tokens[$i]) && preg_match('/^:(raw|content|text)$/i', $tokens[$i])) { + $header['part'] = strtolower(substr($tokens[$i], 1)); + + if ($header['part'] == 'content') { + $header['content'] = $tokens[++$i]; + } + } + else { + $header['arg'] = $tokens[$i]; + } + } + + $tests[] = $header; + break; + case 'exists': $tests[] = array('test' => 'exists', 'not' => $not, 'arg' => array_pop($tokens)); @@ -427,9 +705,7 @@ class rcube_sieve_script } // ...and actions block - if ($tests) { - $actions = $this->_parse_actions($content); - } + $actions = $this->_parse_actions($content); if ($tests && $actions) { $result = array( @@ -447,10 +723,12 @@ class rcube_sieve_script /** * Parse body of actions section * - * @param string Text body + * @param string $content Text body + * @param string $end End of text separator + * * @return array Array of parsed action type/target pairs */ - private function _parse_actions($content) + private function _parse_actions(&$content, $end = '}') { $result = null; @@ -531,12 +809,72 @@ class rcube_sieve_script 'target' => $tokens[count($tokens)-1] ); break; + + case 'include': + $include = array('type' => 'include', 'target' => array_pop($tokens)); + + // Parameters: :once, :optional, :global, :personal + for ($i=0, $len=count($tokens); $i<$len; $i++) { + $tok = strtolower($tokens[$i]); + if ($tok[0] == ':') { + $include[substr($tok, 1)] = true; + } + } + + $result[] = $include; + break; + + case 'set': + $set = array('type' => 'set', 'value' => array_pop($tokens), 'name' => array_pop($tokens)); + + // Parameters: :lower :upper :lowerfirst :upperfirst :quotewildcard :length + for ($i=0, $len=count($tokens); $i<$len; $i++) { + $tok = strtolower($tokens[$i]); + if ($tok[0] == ':') { + $set[substr($tok, 1)] = true; + } + } + + $result[] = $set; + break; + + case 'require': + // skip, will be build according to used commands + // $result[] = array('type' => 'require', 'target' => $tokens); + break; + } + + if ($separator == $end) + break; } return $result; } + /** + * + */ + private function add_comparator($test, &$out, &$exts) + { + if (empty($test['comparator'])) { + return; + } + + if ($test['comparator'] == 'i;ascii-numeric') { + array_push($exts, 'relational'); + array_push($exts, 'comparator-i;ascii-numeric'); + } + else if (!in_array($test['comparator'], array('i;octet', 'i;ascii-casemap'))) { + array_push($exts, 'comparator-' . $test['comparator']); + } + + // skip default comparator + if ($test['comparator'] != 'i;ascii-casemap') { + $out .= ' :comparator ' . self::escape_string($test['comparator']); + } + } + /** * Escape special chars into quoted string value or multi-line string * or list of strings @@ -595,7 +933,7 @@ class rcube_sieve_script * @param mixed $num Number of tokens to return, 0 for all * or True for all tokens until separator is found. * Separator will be returned as last token. - * @param int $in_list Enable to called recursively inside a list + * @param int $in_list Enable to call recursively inside a list * * @return mixed Tokens array or string if $num=1 */ @@ -654,7 +992,7 @@ class rcube_sieve_script $str = substr($str, 1); if ($num === true) { $result[] = $sep; - break 2; + break 2; } break; @@ -684,7 +1022,7 @@ class rcube_sieve_script // String atom default: // empty or one character - if ($str === '') { + if ($str === '' || $str === null) { break 2; } if (strlen($str) < 2) { diff --git a/plugins/managesieve/localization/de_CH.inc b/plugins/managesieve/localization/de_CH.inc index c0fe389..1fcef1e 100644 --- a/plugins/managesieve/localization/de_CH.inc +++ b/plugins/managesieve/localization/de_CH.inc @@ -1,5 +1,20 @@ <?php +/* + +-----------------------------------------------------------------------+ + | localization/de_CH/labels.inc | + | | + | Language file of the Roundcube Webmail client | + | Copyright (C) 2011, The Roundcube Dev Team | + | Licensed under the GNU General Public License | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas <Unknown> | + +-----------------------------------------------------------------------+ + @version : importgettext.sh 5558 2011-12-07 08:51:01Z thomasb $ +*/ + +$labels = array(); $labels['filters'] = 'Filter'; $labels['managefilters'] = 'Verwalte eingehende Nachrichtenfilter'; $labels['filtername'] = 'Filtername'; @@ -17,12 +32,18 @@ $labels['filteris'] = 'ist gleich'; $labels['filterisnot'] = 'ist ungleich'; $labels['filterexists'] = 'ist vorhanden'; $labels['filternotexists'] = 'nicht vorhanden'; +$labels['filtermatches'] = 'entspricht Ausdruck'; +$labels['filternotmatches'] = 'entspricht nicht Ausdruck'; +$labels['filterregex'] = 'trifft regulären Ausdruck'; +$labels['filternotregex'] = 'entspricht regulärem Ausdruck'; $labels['filterunder'] = 'unter'; $labels['filterover'] = 'über'; $labels['addrule'] = 'Regel hinzufügen'; $labels['delrule'] = 'Regel löschen'; $labels['messagemoveto'] = 'Verschiebe Nachricht nach'; $labels['messageredirect'] = 'Leite Nachricht um nach'; +$labels['messagecopyto'] = 'Kopiere Nachricht nach'; +$labels['messagesendcopy'] = 'Sende Kopie an'; $labels['messagereply'] = 'Antworte mit Nachricht'; $labels['messagedelete'] = 'Nachricht löschen'; $labels['messagediscard'] = 'Discard with message'; @@ -35,18 +56,64 @@ $labels['recipient'] = 'Empfänger'; $labels['vacationaddresses'] = 'Zusätzliche Liste von Empfängern (Komma getrennt):'; $labels['vacationdays'] = 'Antwort wird erneut gesendet nach (in Tagen):'; $labels['vacationreason'] = 'Inhalt der Nachricht (Abwesenheitsgrund):'; +$labels['vacationsubject'] = 'Betreff'; $labels['rulestop'] = 'Regelauswertung anhalten'; +$labels['enable'] = 'Aktivieren/Deaktivieren'; +$labels['filterset'] = 'Filtersätze'; +$labels['filtersets'] = 'Filtersätze'; +$labels['filtersetadd'] = 'Filtersatz anlegen'; +$labels['filtersetdel'] = 'Aktuellen Filtersatz löschen'; +$labels['filtersetact'] = 'Aktuellen Filtersatz aktivieren'; +$labels['filtersetdeact'] = 'Aktuellen Filtersatz deaktivieren'; +$labels['filterdef'] = 'Filterdefinition'; +$labels['filtersetname'] = 'Filtersatzname'; +$labels['newfilterset'] = 'Neuer Filtersatz'; +$labels['active'] = 'aktiv'; +$labels['none'] = 'keine'; +$labels['fromset'] = 'aus Filtersatz'; +$labels['fromfile'] = 'aus Datei'; +$labels['filterdisabled'] = 'Filter deaktiviert'; +$labels['countisgreaterthan'] = 'Anzahl ist grösser als'; +$labels['countisgreaterthanequal'] = 'Anzahl ist gleich oder grösser als'; +$labels['countislessthan'] = 'Anzahl ist kleiner als'; +$labels['countislessthanequal'] = 'Anzahl ist gleich oder kleiner als'; +$labels['countequals'] = 'Anzahl ist gleich'; +$labels['countnotequals'] = 'Anzahl ist ungleich'; +$labels['valueisgreaterthan'] = 'Wert ist grösser als'; +$labels['valueisgreaterthanequal'] = 'Wert ist gleich oder grösser als'; +$labels['valueislessthan'] = 'Wert ist kleiner'; +$labels['valueislessthanequal'] = 'Wert ist gleich oder kleiner als'; +$labels['valueequals'] = 'Wert ist gleich'; +$labels['valuenotequals'] = 'Wert ist ungleich'; +$labels['setflags'] = 'Setze Markierungen'; +$labels['addflags'] = 'Füge Markierung hinzu'; +$labels['removeflags'] = 'Entferne Markierung'; +$labels['flagread'] = 'gelesen'; +$labels['flagdeleted'] = 'Gelöscht'; +$labels['flaganswered'] = 'Beantwortet'; +$labels['flagflagged'] = 'Markiert'; +$labels['flagdraft'] = 'Entwurf'; +$labels['filtercreate'] = 'Filter erstellen'; +$labels['usedata'] = 'Die folgenden Daten im Filter benutzen:'; +$labels['nextstep'] = 'Nächster Schritt'; +$labels['...'] = ''; +$labels['advancedopts'] = 'Erweiterte Optionen'; +$labels['body'] = 'Inhalt'; +$labels['address'] = 'Adresse'; +$labels['envelope'] = 'Umschlag'; +$labels['modifier'] = 'Wandler'; +$labels['text'] = 'Text'; +$labels['undecoded'] = 'kodiert (roh)'; +$labels['contenttype'] = 'Inhaltstyp'; +$labels['modtype'] = 'Typ:'; +$labels['allparts'] = 'alle'; +$labels['domain'] = 'Domain'; +$labels['localpart'] = 'lokaler Teil'; +$labels['user'] = 'Benutzer'; +$labels['detail'] = 'Detail'; +$labels['comparator'] = 'Komparator'; +$labels['default'] = 'Vorgabewert'; +$labels['octet'] = 'strikt (Oktet)'; +$labels['asciicasemap'] = 'Gross-/Kleinschreibung ignorieren'; +$labels['asciinumeric'] = 'numerisch (ascii-numeric)'; -$messages['filterunknownerror'] = 'Unbekannter Serverfehler'; -$messages['filterconnerror'] = 'Kann nicht zum Sieve-Server verbinden'; -$messages['filterdeleteerror'] = 'Fehler beim des löschen Filters. Serverfehler'; -$messages['filterdeleted'] = 'Filter erfolgreich gelöscht'; -$messages['filterdeleteconfirm'] = 'Möchten Sie den Filter löschen ?'; -$messages['filtersaved'] = 'Filter gespeichert'; -$messages['filtersaveerror'] = 'Serverfehler, konnte den Filter nicht speichern.'; -$messages['ruledeleteconfirm'] = 'Sicher, dass Sie die Regel löschen wollen?'; -$messages['actiondeleteconfirm'] = 'Sicher, dass Sie die ausgewaehlte Aktion löschen wollen?'; -$messages['forbiddenchars'] = 'Unerlaubte Zeichen im Feld'; -$messages['cannotbeempty'] = 'Feld darf nicht leer sein'; - -?> diff --git a/plugins/managesieve/localization/de_DE.inc b/plugins/managesieve/localization/de_DE.inc index e71d7e0..d78220c 100644 --- a/plugins/managesieve/localization/de_DE.inc +++ b/plugins/managesieve/localization/de_DE.inc @@ -1,9 +1,24 @@ <?php +/* + +-----------------------------------------------------------------------+ + | localization/de_DE/labels.inc | + | | + | Language file of the Roundcube Webmail client | + | Copyright (C) 2011, The Roundcube Dev Team | + | Licensed under the GNU General Public License | + | | + +-----------------------------------------------------------------------+ + | Author: Christoph Wickert <Unknown> | + +-----------------------------------------------------------------------+ + @version : importgettext.sh 5558 2011-12-07 08:51:01Z thomasb $ +*/ + +$labels = array(); $labels['filters'] = 'Filter'; -$labels['managefilters'] = 'Posteingangs-Filter verwalten'; +$labels['managefilters'] = 'Filter für eingehende Nachrichten verwalten'; $labels['filtername'] = 'Filtername'; -$labels['newfilter'] = 'Filter anlegen'; +$labels['newfilter'] = 'Neuer Filter'; $labels['filteradd'] = 'Filter hinzufügen'; $labels['filterdel'] = 'Filter löschen'; $labels['moveup'] = 'Nach oben'; @@ -17,17 +32,21 @@ $labels['filteris'] = 'ist gleich'; $labels['filterisnot'] = 'ist ungleich'; $labels['filterexists'] = 'existiert'; $labels['filternotexists'] = 'existiert nicht'; +$labels['filtermatches'] = 'trifft auf Ausdruck zu'; +$labels['filternotmatches'] = 'trifft nicht auf Ausdruck zu'; +$labels['filterregex'] = 'trifft auf regulären Ausdruck zu'; +$labels['filternotregex'] = 'trifft nicht auf regulären Ausdruck zu'; $labels['filterunder'] = 'unter'; $labels['filterover'] = 'über'; $labels['addrule'] = 'Regel hinzufügen'; $labels['delrule'] = 'Regel löschen'; -$labels['messagemoveto'] = 'Verschiebe Nachricht nach'; -$labels['messageredirect'] = 'Leite Nachricht um an'; -$labels['messagecopyto'] = 'Kopiere Nachricht nach'; -$labels['messagesendcopy'] = 'Sende Kopie an'; -$labels['messagereply'] = 'Antworte mit Nachricht'; -$labels['messagedelete'] = 'Lösche Nachricht'; -$labels['messagediscard'] = 'Weise ab mit Nachricht'; +$labels['messagemoveto'] = 'Nachricht verschieben nach'; +$labels['messageredirect'] = 'Nachricht umleiten an'; +$labels['messagecopyto'] = 'Nachricht kopieren nach'; +$labels['messagesendcopy'] = 'Kopie senden an'; +$labels['messagereply'] = 'Mit Nachricht antworten'; +$labels['messagedelete'] = 'Nachricht löschen'; +$labels['messagediscard'] = 'Abweisen mit Nachricht'; $labels['messagesrules'] = 'Für eingehende Nachrichten:'; $labels['messagesactions'] = '...führende folgende Aktionen aus:'; $labels['add'] = 'Hinzufügen'; @@ -37,13 +56,15 @@ $labels['recipient'] = 'Empfänger'; $labels['vacationaddresses'] = 'Zusätzliche Liste von E-Mail Empfängern (Komma getrennt):'; $labels['vacationdays'] = 'Wie oft sollen Nachrichten gesendet werden (in Tagen):'; $labels['vacationreason'] = 'Nachrichteninhalt (Abwesenheitsgrund):'; +$labels['vacationsubject'] = 'Nachrichtenbetreff'; $labels['rulestop'] = 'Regelauswertung anhalten'; +$labels['enable'] = 'Aktivieren/Deaktivieren'; $labels['filterset'] = 'Filtersätze'; +$labels['filtersets'] = 'Filtersätze'; $labels['filtersetadd'] = 'Filtersatz anlegen'; $labels['filtersetdel'] = 'Aktuellen Filtersatz löschen'; $labels['filtersetact'] = 'Aktuellen Filtersatz aktivieren'; $labels['filtersetdeact'] = 'Aktuellen Filtersatz deaktivieren'; -$labels['filtersetget'] = 'Filtersatz im Textformat herunterladen'; $labels['filterdef'] = 'Filterdefinition'; $labels['filtersetname'] = 'Filtersatzname'; $labels['newfilterset'] = 'Neuer Filtersatz'; @@ -64,29 +85,35 @@ $labels['valueislessthan'] = 'Wert ist kleiner'; $labels['valueislessthanequal'] = 'Wert ist gleich oder kleiner als'; $labels['valueequals'] = 'Wert ist gleich'; $labels['valuenotequals'] = 'Wert ist ungleich'; +$labels['setflags'] = 'Markierung an der Nachricht setzen'; +$labels['addflags'] = 'Markierung zur Nachricht hinzufügen'; +$labels['removeflags'] = 'Markierungen von der Nachricht entfernen'; +$labels['flagread'] = 'Gelesen'; +$labels['flagdeleted'] = 'Gelöscht'; +$labels['flaganswered'] = 'Beantwortet'; +$labels['flagflagged'] = 'Markiert'; +$labels['flagdraft'] = 'Entwurf'; +$labels['filtercreate'] = 'Filter erstellen'; +$labels['usedata'] = 'Die folgenden Daten im Filter benutzen:'; +$labels['nextstep'] = 'Nächster Schritt'; +$labels['...'] = '...'; +$labels['advancedopts'] = 'Erweiterte Optionen'; +$labels['body'] = 'Textkörper'; +$labels['address'] = 'Adresse'; +$labels['envelope'] = 'Umschlag'; +$labels['modifier'] = 'Modifikator:'; +$labels['text'] = 'Text'; +$labels['undecoded'] = 'Nicht dekodiert'; +$labels['contenttype'] = 'Inhaltstyp'; +$labels['modtype'] = 'Typ:'; +$labels['allparts'] = 'Alle'; +$labels['domain'] = 'Domäne'; +$labels['localpart'] = 'lokaler Teil'; +$labels['user'] = 'Benutzer'; +$labels['detail'] = 'Detail'; +$labels['comparator'] = 'Komperator:'; +$labels['default'] = 'Vorgabewert'; +$labels['octet'] = 'strikt (Oktett)'; +$labels['asciicasemap'] = 'GroÃ-/Kleinschreibung ignorieren'; +$labels['asciinumeric'] = 'numerisch (ascii-numeric)'; -$messages = array(); -$messages['filterunknownerror'] = 'Unbekannter Serverfehler'; -$messages['filterconnerror'] = 'Kann keine Verbindung mit Managesieve-Server herstellen'; -$messages['filterdeleteerror'] = 'Fehler beim Löschen des Filters. Serverfehler'; -$messages['filterdeleted'] = 'Filter erfolgreich gelöscht'; -$messages['filtersaved'] = 'Filter erfolgreich gespeichert'; -$messages['filtersaveerror'] = 'Fehler beim Speichern des Filters. Serverfehler'; -$messages['filterdeleteconfirm'] = 'Möchten Sie den ausgewählten Filter wirklich löschen?'; -$messages['ruledeleteconfirm'] = 'Sind Sie sicher, dass Sie die ausgewählte Regel löschen möchten?'; -$messages['actiondeleteconfirm'] = 'Sind Sie sicher, dass Sie die ausgewählte Aktion löschen möchten?'; -$messages['forbiddenchars'] = 'Unzulässige Zeichen im Eingabefeld'; -$messages['cannotbeempty'] = 'Eingabefeld darf nicht leer sein'; -$messages['setactivateerror'] = 'Kann ausgewählten Filtersatz nicht aktivieren. Serverfehler'; -$messages['setdeactivateerror'] = 'Kann ausgewählten Filtersatz nicht deaktivieren. Serverfehler'; -$messages['setdeleteerror'] = 'Kann ausgewählten Filtersatz nicht löschen. Serverfehler'; -$messages['setactivated'] = 'Filtersatz wurde erfolgreich aktiviert'; -$messages['setdeactivated'] = 'Filtersatz wurde erfolgreich deaktiviert'; -$messages['setdeleted'] = 'Filtersatz wurde erfolgreich gelöscht'; -$messages['setdeleteconfirm'] = 'Sind Sie sicher, dass Sie den ausgewählten Filtersatz löschen möchten?'; -$messages['setcreateerror'] = 'Kann Filtersatz nicht erstellen. Serverfehler'; -$messages['setcreated'] = 'Filtersatz wurde erfolgreich erstellt'; -$messages['emptyname'] = 'Kann Filtersatz nicht erstellen. Kein Name vergeben'; -$messages['nametoolong'] = 'Kann Filtersatz nicht erstellen. Name zu lang' - -?> diff --git a/plugins/managesieve/localization/en_US.inc b/plugins/managesieve/localization/en_US.inc index f08357e..94e0ba6 100644 --- a/plugins/managesieve/localization/en_US.inc +++ b/plugins/managesieve/localization/en_US.inc @@ -43,12 +43,13 @@ $labels['vacationdays'] = 'How often send messages (in days):'; $labels['vacationreason'] = 'Message body (vacation reason):'; $labels['vacationsubject'] = 'Message subject:'; $labels['rulestop'] = 'Stop evaluating rules'; +$labels['enable'] = 'Enable/Disable'; $labels['filterset'] = 'Filters set'; +$labels['filtersets'] = 'Filter sets'; $labels['filtersetadd'] = 'Add filters set'; $labels['filtersetdel'] = 'Delete current filters set'; $labels['filtersetact'] = 'Activate current filters set'; $labels['filtersetdeact'] = 'Deactivate current filters set'; -$labels['filtersetget'] = 'Download filters set in text format'; $labels['filterdef'] = 'Filter definition'; $labels['filtersetname'] = 'Filters set name'; $labels['newfilterset'] = 'New filters set'; @@ -77,29 +78,61 @@ $labels['flagdeleted'] = 'Deleted'; $labels['flaganswered'] = 'Answered'; $labels['flagflagged'] = 'Flagged'; $labels['flagdraft'] = 'Draft'; +$labels['filtercreate'] = 'Create filter'; +$labels['usedata'] = 'Use following data in the filter:'; +$labels['nextstep'] = 'Next Step'; +$labels['...'] = '...'; +$labels['advancedopts'] = 'Advanced options'; +$labels['body'] = 'Body'; +$labels['address'] = 'address'; +$labels['envelope'] = 'envelope'; +$labels['modifier'] = 'modifier:'; +$labels['text'] = 'text'; +$labels['undecoded'] = 'undecoded (raw)'; +$labels['contenttype'] = 'content type'; +$labels['modtype'] = 'type:'; +$labels['allparts'] = 'all'; +$labels['domain'] = 'domain'; +$labels['localpart'] = 'local part'; +$labels['user'] = 'user'; +$labels['detail'] = 'detail'; +$labels['comparator'] = 'comparator:'; +$labels['default'] = 'default'; +$labels['octet'] = 'strict (octet)'; +$labels['asciicasemap'] = 'case insensitive (ascii-casemap)'; +$labels['asciinumeric'] = 'numeric (ascii-numeric)'; $messages = array(); -$messages['filterunknownerror'] = 'Unknown server error'; -$messages['filterconnerror'] = 'Unable to connect to managesieve server'; -$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occured'; -$messages['filterdeleted'] = 'Filter deleted successfully'; -$messages['filtersaved'] = 'Filter saved successfully'; -$messages['filtersaveerror'] = 'Unable to save filter. Server error occured'; +$messages['filterunknownerror'] = 'Unknown server error.'; +$messages['filterconnerror'] = 'Unable to connect to server.'; +$messages['filterdeleteerror'] = 'Unable to delete filter. Server error occured.'; +$messages['filterdeleted'] = 'Filter deleted successfully.'; +$messages['filtersaved'] = 'Filter saved successfully.'; +$messages['filtersaveerror'] = 'Unable to save filter. Server error occured.'; $messages['filterdeleteconfirm'] = 'Do you really want to delete selected filter?'; $messages['ruledeleteconfirm'] = 'Are you sure, you want to delete selected rule?'; $messages['actiondeleteconfirm'] = 'Are you sure, you want to delete selected action?'; -$messages['forbiddenchars'] = 'Forbidden characters in field'; -$messages['cannotbeempty'] = 'Field cannot be empty'; -$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occured'; -$messages['setdeactivateerror'] = 'Unable to deactivate selected filters set. Server error occured'; -$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occured'; -$messages['setactivated'] = 'Filters set activated successfully'; -$messages['setdeactivated'] = 'Filters set deactivated successfully'; -$messages['setdeleted'] = 'Filters set deleted successfully'; +$messages['forbiddenchars'] = 'Forbidden characters in field.'; +$messages['cannotbeempty'] = 'Field cannot be empty.'; +$messages['ruleexist'] = 'Filter with specified name already exists.'; +$messages['setactivateerror'] = 'Unable to activate selected filters set. Server error occured.'; +$messages['setdeactivateerror'] = 'Unable to deactivate selected filters set. Server error occured.'; +$messages['setdeleteerror'] = 'Unable to delete selected filters set. Server error occured.'; +$messages['setactivated'] = 'Filters set activated successfully.'; +$messages['setdeactivated'] = 'Filters set deactivated successfully.'; +$messages['setdeleted'] = 'Filters set deleted successfully.'; $messages['setdeleteconfirm'] = 'Are you sure, you want to delete selected filters set?'; -$messages['setcreateerror'] = 'Unable to create filters set. Server error occured'; -$messages['setcreated'] = 'Filters set created successfully'; -$messages['emptyname'] = 'Unable to create filters set. Empty set name'; -$messages['nametoolong'] = 'Unable to create filters set. Name too long' +$messages['setcreateerror'] = 'Unable to create filters set. Server error occured.'; +$messages['setcreated'] = 'Filters set created successfully.'; +$messages['activateerror'] = 'Unable to enable selected filter(s). Server error occured.'; +$messages['deactivateerror'] = 'Unable to disable selected filter(s). Server error occured.'; +$messages['activated'] = 'Filter(s) disabled successfully.'; +$messages['deactivated'] = 'Filter(s) enabled successfully.'; +$messages['moved'] = 'Filter moved successfully.'; +$messages['moveerror'] = 'Unable to move selected filter. Server error occured.'; +$messages['nametoolong'] = 'Name too long.'; +$messages['namereserved'] = 'Reserved name.'; +$messages['setexist'] = 'Set already exists.'; +$messages['nodata'] = 'At least one position must be selected!'; ?> diff --git a/plugins/managesieve/localization/es_ES.inc b/plugins/managesieve/localization/es_ES.inc index 1dad18d..b6dbf16 100644 --- a/plugins/managesieve/localization/es_ES.inc +++ b/plugins/managesieve/localization/es_ES.inc @@ -53,6 +53,31 @@ $labels['none'] = 'ninguno'; $labels['fromset'] = 'de conjunto '; $labels['fromfile'] = 'de archivo'; $labels['filterdisabled'] = 'Filtro desactivado'; +$labels['filtermatches'] = 'coincide con la expresión'; +$labels['filternotmatches'] = 'no coincide con la expresión'; +$labels['filterregex'] = 'coincide con la expresión regular'; +$labels['filternotregex'] = 'no coincide con la expresión regular'; +$labels['vacationsubject'] = 'Asunto del Mensaje:'; +$labels['countisgreaterthan'] = 'contiene más que'; +$labels['countisgreaterthanequal'] = 'contiene más o igual que'; +$labels['countislessthan'] = 'contiene menos que'; +$labels['countislessthanequal'] = 'contiene menos o igual que'; +$labels['countequals'] = 'contiene igual que'; +$labels['countnotequals'] = 'contiene distinto que'; +$labels['valueisgreaterthan'] = 'el valor es mayor que'; +$labels['valueisgreaterthanequal'] = 'el valor es mayor o igual que'; +$labels['valueislessthan'] = 'el valor es menor que'; +$labels['valueislessthanequal'] = 'el valor es menor o igual que'; +$labels['valueequals'] = 'el valor es igual que'; +$labels['valuenotequals'] = 'el valor es distinto que'; +$labels['setflags'] = 'Etiquetar el mensaje'; +$labels['addflags'] = 'Agregar etiqueta al mensaje'; +$labels['removeflags'] = 'Eliminar etiquetas al mensaje'; +$labels['flagread'] = 'Leido'; +$labels['flagdeleted'] = 'Eliminado'; +$labels['flaganswered'] = 'Respondido'; +$labels['flagflagged'] = 'Marcado'; +$labels['flagdraft'] = 'Borrador'; $messages = array(); $messages['filterunknownerror'] = 'Error desconocido de servidor'; @@ -76,6 +101,7 @@ $messages['setdeleteconfirm'] = '¿Está seguro de que desea borrar el conjunto $messages['setcreateerror'] = 'Imposible crear el conjunto de filtros. Ha ocurrido un error en el servidor'; $messages['setcreated'] = 'Conjunto de filtros creado satisfactoriamente'; $messages['emptyname'] = 'Imposible crear el conjunto de filtros. Sin nombre'; -$messages['nametoolong'] = 'Imposible crear el conjunto de filtros. Nombre demasiado largo' +$messages['nametoolong'] = 'Imposible crear el conjunto de filtros. Nombre demasiado largo'; +$messages['setdeactivateerror'] = 'Imposible desactivar el conjunto de filtros seleccionado. Ha ocurrido un error en el servidor'; ?> diff --git a/plugins/managesieve/localization/lv_LV.inc b/plugins/managesieve/localization/lv_LV.inc new file mode 100644 index 0000000..b394588 --- /dev/null +++ b/plugins/managesieve/localization/lv_LV.inc @@ -0,0 +1,92 @@ +<?php + +$labels['filters'] = 'VÄstuļu filtri'; +$labels['managefilters'] = 'RediÄ£Ät ienÄkoÅ¡o vÄstuļu filtrus'; +$labels['filtername'] = 'Filtra nosaukums'; +$labels['newfilter'] = 'Jauns filtrs'; +$labels['filteradd'] = 'Pievienot filtru'; +$labels['filterdel'] = 'IzdzÄst filtru'; +$labels['moveup'] = 'PÄrvietot augÅ¡up'; +$labels['movedown'] = 'PÄrvietot lejup'; +$labels['filterallof'] = 'jÄatbilst visiem no sekojoÅ¡iem nosacÄ«jumiem'; +$labels['filteranyof'] = 'jÄatbilst jebkuram no sekojoÅ¡iem nosacÄ«jumiem'; +$labels['filterany'] = 'visÄm vÄstulÄm'; +$labels['filtercontains'] = 'satur'; +$labels['filternotcontains'] = 'nesatur'; +$labels['filteris'] = 'ir vienÄds ar'; +$labels['filterisnot'] = 'nav vienÄds ar'; +$labels['filterexists'] = 'eksistÄ'; +$labels['filternotexists'] = 'neeksistÄ'; +$labels['filterunder'] = 'zem'; +$labels['filterover'] = 'virs'; +$labels['addrule'] = 'Pievienot nosacÄ«jumu'; +$labels['delrule'] = 'IzdzÄst nosacÄ«jumu'; +$labels['messagemoveto'] = 'PÄrvietot vÄstuli uz'; +$labels['messageredirect'] = 'PÄradresÄt vÄstuli uz'; +$labels['messagecopyto'] = 'PÄrkopÄt vÄstuli uz'; +$labels['messagesendcopy'] = 'PÄrsÅ«tÄ«t vÄstules kopiju uz'; +$labels['messagereply'] = 'AutomÄtiski atbildÄt'; +$labels['messagedelete'] = 'IzdzÄst vÄstuli'; +$labels['messagediscard'] = 'IzdzÄst vÄstuli un atbildÄt'; +$labels['messagesrules'] = 'IenÄkoÅ¡ajÄm vÄstulÄm:'; +$labels['messagesactions'] = 'IzpildÄ«t sekojoÅ¡Äs darbÄ«bas:'; +$labels['add'] = 'Pievienot'; +$labels['del'] = 'DzÄst'; +$labels['sender'] = 'SÅ«tÄ«tÄjs'; +$labels['recipient'] = 'SaÅÄmÄjs'; +$labels['vacationaddresses'] = 'Ievadiet savu(s) e-pastu(s) caur komatu:'; +$labels['vacationdays'] = 'Cik dienu laikÄ vienam un tam paÅ¡am sÅ«tÄ«tÄjam neatbildÄt atkÄrtoti (piem., 7):'; +$labels['vacationreason'] = 'AtvaļinÄjuma vÄstules teksts:'; +$labels['rulestop'] = 'ApturÄt nosacÄ«jumu pÄrbaudi'; +$labels['filterset'] = 'Filtru kopa'; +$labels['filtersetadd'] = 'Pievienot filtru kopu'; +$labels['filtersetdel'] = 'IzdzÄst paÅ¡reizÄjo filtru kopu'; +$labels['filtersetact'] = 'AktivizÄt paÅ¡reizÄjo filtru kopu'; +$labels['filtersetdeact'] = 'DeaktivizÄt paÅ¡reizÄjo filtru kopu'; +$labels['filtersetget'] = 'LejupielÄdÄt filtru kopu teksta formÄtÄ'; +$labels['filterdef'] = 'Filtra apraksts'; +$labels['filtersetname'] = 'Filtru kopas nosaukums'; +$labels['newfilterset'] = 'Jauna filtru kopa'; +$labels['active'] = 'aktÄ«vs'; +$labels['none'] = 'nav'; +$labels['fromset'] = 'no kopas'; +$labels['fromfile'] = 'no faila'; +$labels['filterdisabled'] = 'Filtrs atslÄgts'; +$labels['countisgreaterthan'] = 'skaits ir lielÄks nekÄ'; +$labels['countisgreaterthanequal'] = 'skaits ir vienÄds vai lielÄks nekÄ'; +$labels['countislessthan'] = 'skaits ir mazÄks nekÄ'; +$labels['countislessthanequal'] = 'skaits ir vienÄds vai mazÄks nekÄ'; +$labels['countequals'] = 'skaits ir vienÄds ar'; +$labels['countnotequals'] = 'skaits nav vienÄds ar'; +$labels['valueisgreaterthan'] = 'vÄrtÄ«ba ir lielÄka nekÄ'; +$labels['valueisgreaterthanequal'] = 'vÄrtÄ«ba ir vienÄda vai lielÄka nekÄ'; +$labels['valueislessthan'] = 'vÄrtÄ«ba ir mazÄka nekÄ'; +$labels['valueislessthanequal'] = 'vÄrtÄ«ba ir vienÄda vai mazÄka nekÄ'; +$labels['valueequals'] = 'vÄrtÄ«ba ir vienÄda ar'; +$labels['valuenotequals'] = 'vÄrtÄ«ba nav vienÄda ar'; + +$messages = array(); +$messages['filterunknownerror'] = 'NezinÄma servera kļūda'; +$messages['filterconnerror'] = 'NeizdevÄs pieslÄgties ManageSieve serverim'; +$messages['filterdeleteerror'] = 'NeizdevÄs dzÄst filtru. Servera iekÅ¡ÄjÄ kļūda'; +$messages['filterdeleted'] = 'Filtrs veiksmÄ«gi izdzÄsts'; +$messages['filtersaved'] = 'Filtrs veiksmÄ«gi saglabÄts'; +$messages['filtersaveerror'] = 'NeizdevÄs saglabÄt filtru. Servera iekÅ¡ÄjÄ kļūda'; +$messages['filterdeleteconfirm'] = 'Vai tieÅ¡Äm vÄlaties dzÄst atzÄ«mÄto filtru?'; +$messages['ruledeleteconfirm'] = 'Vai tieÅ¡Äm vÄlaties dzÄst atzÄ«mÄto nosacÄ«jumu?'; +$messages['actiondeleteconfirm'] = 'Vai tieÅ¡Äm vÄlaties dzÄst atzÄ«mÄto darbÄ«bu?'; +$messages['forbiddenchars'] = 'Lauks satur aizliegtus simbolus'; +$messages['cannotbeempty'] = 'Lauks nedrÄ«kst bÅ«t tukÅ¡s'; +$messages['setactivateerror'] = 'NeizdevÄs aktivizÄt atzÄ«mÄto filtru kopu. Servera iekÅ¡ÄjÄ kļūda'; +$messages['setdeactivateerror'] = 'NeizdevÄs deaktivizÄt atzÄ«mÄto filtru kopu. Servera iekÅ¡ÄjÄ kļūda'; +$messages['setdeleteerror'] = 'NeizdevÄs izdzÄst atzÄ«mÄto filtru kopu. Servera iekÅ¡ÄjÄ kļūda'; +$messages['setactivated'] = 'Filtru kopa veiksmÄ«gi aktivizÄta'; +$messages['setdeactivated'] = 'Filtru kopa veiksmÄ«gi deaktivizÄta'; +$messages['setdeleted'] = 'Filtru kopa veiksmÄ«gi izdzÄsta'; +$messages['setdeleteconfirm'] = 'Vai tieÅ¡Äm vÄlaties dzÄst atzÄ«mÄto filtru kopu?'; +$messages['setcreateerror'] = 'NeizdevÄs izveidot filtru kopu. Servera iekÅ¡ÄjÄ kļūda'; +$messages['setcreated'] = 'Filtru kopa veiksmÄ«gi izveidota'; +$messages['emptyname'] = 'NeizdevÄs izveidot filtru kopu. Nav ievadÄ«ts kopas nosaukums'; +$messages['nametoolong'] = 'NeizdevÄs izveidot filtru kopu. PÄrÄk garÅ¡ kopas nosaukums' + +?> diff --git a/plugins/managesieve/localization/pl_PL.inc b/plugins/managesieve/localization/pl_PL.inc index 290dd1a..c0ec2ed 100644 --- a/plugins/managesieve/localization/pl_PL.inc +++ b/plugins/managesieve/localization/pl_PL.inc @@ -7,8 +7,8 @@ $labels['filtername'] = 'Nazwa filtru'; $labels['newfilter'] = 'Nowy filtr'; $labels['filteradd'] = 'Dodaj filtr'; $labels['filterdel'] = 'UsuÅ filtr'; -$labels['moveup'] = 'PrzenieÅ wyżej'; -$labels['movedown'] = 'PrzenieÅ niżej'; +$labels['enable'] = 'WÅÄ cz/WyÅÄ cz'; +$labels['filtersets'] = 'Zbiory fitrów'; $labels['filterallof'] = 'speÅniajÄ cych wszystkie poniższe kryteria'; $labels['filteranyof'] = 'speÅniajÄ cych dowolne z poniższych kryteriów'; $labels['filterany'] = 'wszystkich'; @@ -49,7 +49,6 @@ $labels['filtersetadd'] = 'Dodaj zbiór filtrów'; $labels['filtersetdel'] = 'UsuÅ bieÅ¼Ä cy zbiór filtrów'; $labels['filtersetact'] = 'Aktywuj bieÅ¼Ä cy zbiór filtrów'; $labels['filtersetdeact'] = 'Deaktywuj bieÅ¼Ä cy zbiór filtrów'; -$labels['filtersetget'] = 'Pobierz bieÅ¼Ä cy zbiór filtrów w formacie tekstowym'; $labels['filterdef'] = 'Definicja filtra'; $labels['filtersetname'] = 'Nazwa zbioru'; $labels['newfilterset'] = 'Nowy zbiór filtrów'; @@ -78,29 +77,61 @@ $labels['flagdeleted'] = 'UsuniÄta'; $labels['flaganswered'] = 'Z odpowiedziÄ '; $labels['flagflagged'] = 'Oflagowana'; $labels['flagdraft'] = 'Szkic'; +$labels['filtercreate'] = 'Utwóż filtr'; +$labels['usedata'] = 'Użyj nastÄpujÄ cych danych do utworzenia filtra:'; +$labels['nextstep'] = 'NastÄpny krok'; +$labels['...'] = '...'; +$labels['advancedopts'] = 'Zaawansowane opcje'; +$labels['body'] = 'TreÅÄ'; +$labels['address'] = 'adres'; +$labels['envelope'] = 'koperta (envelope)'; +$labels['modifier'] = 'modyfikator:'; +$labels['text'] = 'tekst'; +$labels['undecoded'] = 'nie (raw)'; +$labels['contenttype'] = 'typ czÄÅci (content type)'; +$labels['modtype'] = 'typ:'; +$labels['allparts'] = 'wszystkie'; +$labels['domain'] = 'domena'; +$labels['localpart'] = 'czÄÅÄ lokalna'; +$labels['user'] = 'użytkownik'; +$labels['detail'] = 'detal'; +$labels['comparator'] = 'komparator:'; +$labels['default'] = 'domyÅlny'; +$labels['octet'] = 'dokÅadny (octet)'; +$labels['asciicasemap'] = 'nierozróżniajÄ cy wielkoÅci liter (ascii-casemap)'; +$labels['asciinumeric'] = 'numeryczny (ascii-numeric)'; $messages = array(); -$messages['filterunknownerror'] = 'Nieznany bÅÄ d serwera'; -$messages['filterconnerror'] = 'Nie można nawiÄ zaÄ poÅÄ czenia z serwerem managesieve'; -$messages['filterdeleteerror'] = 'Nie można usunÄ Ä filtra. WystÄ piÅ bÅÄ d serwera'; -$messages['filterdeleted'] = 'Filtr zostaÅ usuniÄty pomyÅlnie'; +$messages['filterunknownerror'] = 'Nieznany bÅÄ d serwera.'; +$messages['filterconnerror'] = 'Nie można nawiÄ zaÄ poÅÄ czenia z serwerem.'; +$messages['filterdeleteerror'] = 'Nie można usunÄ Ä filtra. BÅÄ d serwera.'; +$messages['filterdeleted'] = 'Filtr zostaÅ usuniÄty pomyÅlnie.'; $messages['filterdeleteconfirm'] = 'Czy na pewno chcesz usunÄ Ä wybrany filtr?'; -$messages['filtersaved'] = 'Filtr zostaÅ zapisany pomyÅlnie'; +$messages['filtersaved'] = 'Filtr zostaÅ zapisany pomyÅlnie.'; $messages['filtersaveerror'] = 'Nie można zapisaÄ filtra. WystÄ piÅ bÅÄ d serwera.'; $messages['ruledeleteconfirm'] = 'Czy na pewno chcesz usunÄ Ä wybranÄ reguÅÄ?'; $messages['actiondeleteconfirm'] = 'Czy na pewno usunÄ Ä wybranÄ akcjÄ?'; -$messages['forbiddenchars'] = 'Pole zawiera niedozwolone znaki'; -$messages['cannotbeempty'] = 'Pole nie może byÄ puste'; -$messages['setactivateerror'] = 'Nie można aktywowaÄ wybranego zbioru filtrów. BÅÄ d serwera'; -$messages['setdeactivateerror'] = 'Nie można deaktywowaÄ wybranego zbioru filtrów. BÅÄ d serwera'; -$messages['setdeleteerror'] = 'Nie można usunÄ Ä wybranego zbioru filtrów. BÅÄ d serwera'; -$messages['setactivated'] = 'Zbiór filtrów zostaÅ aktywowany pomyÅlnie'; -$messages['setdeactivated'] = 'Zbiór filtrów zostaÅ deaktywowany pomyÅlnie'; -$messages['setdeleted'] = 'Zbiór filtrów zostaÅ usuniÄty pomyÅlnie'; +$messages['forbiddenchars'] = 'Pole zawiera niedozwolone znaki.'; +$messages['cannotbeempty'] = 'Pole nie może byÄ puste.'; +$messages['setactivateerror'] = 'Nie można aktywowaÄ wybranego zbioru filtrów. BÅÄ d serwera.'; +$messages['setdeactivateerror'] = 'Nie można deaktywowaÄ wybranego zbioru filtrów. BÅÄ d serwera.'; +$messages['setdeleteerror'] = 'Nie można usunÄ Ä wybranego zbioru filtrów. BÅÄ d serwera.'; +$messages['setactivated'] = 'Zbiór filtrów zostaÅ aktywowany pomyÅlnie.'; +$messages['setdeactivated'] = 'Zbiór filtrów zostaÅ deaktywowany pomyÅlnie.'; +$messages['setdeleted'] = 'Zbiór filtrów zostaÅ usuniÄty pomyÅlnie.'; $messages['setdeleteconfirm'] = 'Czy na pewno chcesz usunÄ Ä wybrany zbiór filtrów?'; -$messages['setcreateerror'] = 'Nie można utworzyÄ zbioru filtrów. BÅÄ d serwera'; -$messages['setcreated'] = 'Zbiór filtrów zostaÅ utworzony pomyÅlnie'; -$messages['emptyname'] = 'Nie można utworzyÄ zbioru filtrów. Pusta nazwa zbioru'; -$messages['nametoolong'] = 'Nie można utworzyÄ zbioru filtrów. Nazwa zbyt dÅuga' +$messages['setcreateerror'] = 'Nie można utworzyÄ zbioru filtrów. BÅÄ d serwera.'; +$messages['setcreated'] = 'Zbiór filtrów zostaÅ utworzony pomyÅlnie.'; +$messages['nodata'] = 'Należy wybraÄ co najmniej jednÄ pozycjÄ!'; +$messages['ruleexist'] = 'Filtr o podanej nazwie już istnieje.'; +$messages['activateerror'] = 'Nie można wÅÄ czyÄ wybranych filtrów. BÅÄ d serwera.'; +$messages['deactivateerror'] = 'Nie można wyÅÄ czyÄ wybranych filtrów. BÅÄ d serwera.'; +$messages['activated'] = 'Filtr(y) wyÅÄ czono pomyÅlnie.'; +$messages['deactivated'] = 'Filtr(y) wÅÄ czono pomyÅlnie.'; +$messages['moved'] = 'Filter zostaÅ przeniesiony pomyÅlnie.'; +$messages['moveerror'] = 'Nie można przenieÅÄ wybranego filtra. BÅÄ d serwera.'; +$messages['nametoolong'] = 'Zbyt dÅuga nazwa.'; +$messages['namereserved'] = 'Nazwa zarezerwowana.'; +$messages['setexist'] = 'Zbiór już istnieje.'; ?> diff --git a/plugins/managesieve/localization/pt_BR.inc b/plugins/managesieve/localization/pt_BR.inc index b48774e..af3f05a 100644 --- a/plugins/managesieve/localization/pt_BR.inc +++ b/plugins/managesieve/localization/pt_BR.inc @@ -32,7 +32,7 @@ $labels['add'] = 'Adicionar'; $labels['del'] = 'Excluir'; $labels['sender'] = 'Remetente'; $labels['recipient'] = 'Destinatário'; -$labels['vacationaddresses'] = 'Lista adicional de e-mails de remetente (separado por vÃrgula):'; +$labels['vacationaddresses'] = 'Lista adicional de e-mails destinatários (separado por vÃrgula):'; $labels['vacationdays'] = 'Enviar mensagens com que frequência (em dias):'; $labels['vacationreason'] = 'Corpo da mensagem (motivo de férias):'; $labels['rulestop'] = 'Parar de avaliar regras'; diff --git a/plugins/managesieve/managesieve.js b/plugins/managesieve/managesieve.js index ec6247a..a8bfaf2 100644 --- a/plugins/managesieve/managesieve.js +++ b/plugins/managesieve/managesieve.js @@ -1,56 +1,97 @@ -/* Sieve Filters (tab) */ +/* (Manage)Sieve Filters */ if (window.rcmail) { rcmail.addEventListener('init', function(evt) { + // add managesieve-create command to message_commands array, + // so it's state will be updated on message selection/unselection + if (rcmail.env.task == 'mail') { + if (rcmail.env.action != 'show') + rcmail.env.message_commands.push('managesieve-create'); + else + rcmail.enable_command('managesieve-create', true); + } + else { + var tab = $('<span>').attr('id', 'settingstabpluginmanagesieve').addClass('tablink'), + button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.managesieve') + .attr('title', rcmail.gettext('managesieve.managefilters')) + .html(rcmail.gettext('managesieve.filters')) + .appendTo(tab); + + // add tab + rcmail.add_element(tab, 'tabs'); + } + + if (rcmail.env.task == 'mail' || rcmail.env.action.indexOf('plugin.managesieve') != -1) { + // Create layer for form tips + if (!rcmail.env.framed) { + rcmail.env.ms_tip_layer = $('<div id="managesieve-tip" class="popupmenu"></div>'); + rcmail.env.ms_tip_layer.appendTo(document.body); + } + } - var tab = $('<span>').attr('id', 'settingstabpluginmanagesieve').addClass('tablink'); - var button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.managesieve') - .attr('title', rcmail.gettext('managesieve.managefilters')) - .html(rcmail.gettext('managesieve.filters')) - .appendTo(tab); - - // add button and register commands - rcmail.add_element(tab, 'tabs'); - rcmail.register_command('plugin.managesieve-save', function() { rcmail.managesieve_save() }, true); - rcmail.register_command('plugin.managesieve-add', function() { rcmail.managesieve_add() }, true); - rcmail.register_command('plugin.managesieve-del', function() { rcmail.managesieve_del() }, true); - rcmail.register_command('plugin.managesieve-up', function() { rcmail.managesieve_up() }, true); - rcmail.register_command('plugin.managesieve-down', function() { rcmail.managesieve_down() }, true); - rcmail.register_command('plugin.managesieve-set', function() { rcmail.managesieve_set() }, true); - rcmail.register_command('plugin.managesieve-setadd', function() { rcmail.managesieve_setadd() }, true); - rcmail.register_command('plugin.managesieve-setdel', function() { rcmail.managesieve_setdel() }, true); - rcmail.register_command('plugin.managesieve-setact', function() { rcmail.managesieve_setact() }, true); - rcmail.register_command('plugin.managesieve-setget', function() { rcmail.managesieve_setget() }, true); - - if (rcmail.env.action == 'plugin.managesieve') { + // register commands + rcmail.register_command('plugin.managesieve-save', function() { rcmail.managesieve_save() }); + rcmail.register_command('plugin.managesieve-act', function() { rcmail.managesieve_act() }); + rcmail.register_command('plugin.managesieve-add', function() { rcmail.managesieve_add() }); + rcmail.register_command('plugin.managesieve-del', function() { rcmail.managesieve_del() }); + rcmail.register_command('plugin.managesieve-move', function() { rcmail.managesieve_move() }); + rcmail.register_command('plugin.managesieve-setadd', function() { rcmail.managesieve_setadd() }); + rcmail.register_command('plugin.managesieve-setdel', function() { rcmail.managesieve_setdel() }); + rcmail.register_command('plugin.managesieve-setact', function() { rcmail.managesieve_setact() }); + rcmail.register_command('plugin.managesieve-setget', function() { rcmail.managesieve_setget() }); + + if (rcmail.env.action == 'plugin.managesieve' || rcmail.env.action == 'plugin.managesieve-save') { if (rcmail.gui_objects.sieveform) { rcmail.enable_command('plugin.managesieve-save', true); + + // small resize for header element + $('select[name="_header[]"]', rcmail.gui_objects.sieveform).each(function() { + if (this.value == '...') this.style.width = '40px'; + }); + + // resize dialog window + if (rcmail.env.action == 'plugin.managesieve' && rcmail.env.task == 'mail') { + parent.rcmail.managesieve_dialog_resize(rcmail.gui_objects.sieveform); + } + + $('input[type="text"]:first', rcmail.gui_objects.sieveform).focus(); } else { - rcmail.enable_command('plugin.managesieve-del', 'plugin.managesieve-up', - 'plugin.managesieve-down', false); rcmail.enable_command('plugin.managesieve-add', 'plugin.managesieve-setadd', !rcmail.env.sieveconnerror); } - // Create layer for form tips - if (!rcmail.env.framed) { - rcmail.env.ms_tip_layer = $('<div id="managesieve-tip" class="popupmenu"></div>'); - rcmail.env.ms_tip_layer.appendTo(document.body); - } + var i, p = rcmail, setcnt, set = rcmail.env.currentset; if (rcmail.gui_objects.filterslist) { - var p = rcmail; - rcmail.filters_list = new rcube_list_widget(rcmail.gui_objects.filterslist, {multiselect:false, draggable:false, keyboard:false}); + rcmail.filters_list = new rcube_list_widget(rcmail.gui_objects.filterslist, + {multiselect:false, draggable:true, keyboard:false}); rcmail.filters_list.addEventListener('select', function(o){ p.managesieve_select(o); }); + rcmail.filters_list.addEventListener('dragstart', function(o){ p.managesieve_dragstart(o); }); + rcmail.filters_list.addEventListener('dragend', function(e){ p.managesieve_dragend(e); }); + rcmail.filters_list.row_init = function (row) { + row.obj.onmouseover = function() { p.managesieve_focus_filter(row); }; + row.obj.onmouseout = function() { p.managesieve_unfocus_filter(row); }; + }; rcmail.filters_list.init(); rcmail.filters_list.focus(); + } - rcmail.enable_command('plugin.managesieve-set', true); - rcmail.enable_command('plugin.managesieve-setact', 'plugin.managesieve-setget', rcmail.gui_objects.filtersetslist.length); - rcmail.enable_command('plugin.managesieve-setdel', rcmail.gui_objects.filtersetslist.length > 1); + if (rcmail.gui_objects.filtersetslist) { + rcmail.filtersets_list = new rcube_list_widget(rcmail.gui_objects.filtersetslist, {multiselect:false, draggable:false, keyboard:false}); + rcmail.filtersets_list.addEventListener('select', function(o){ p.managesieve_setselect(o); }); + rcmail.filtersets_list.init(); + rcmail.filtersets_list.focus(); - $('#'+rcmail.buttons['plugin.managesieve-setact'][0].id).attr('title', rcmail.gettext('managesieve.filterset' - + (rcmail.gui_objects.filtersetslist.value == rcmail.env.active_set ? 'deact' : 'act'))); + if (set != null) { + set = rcmail.managesieve_setid(set); + rcmail.filtersets_list.shift_start = set; + rcmail.filtersets_list.highlight_row(set, false); + } + + setcnt = rcmail.filtersets_list.rowcount; + rcmail.enable_command('plugin.managesieve-set', true); + rcmail.enable_command('plugin.managesieve-setact', 'plugin.managesieve-setget', setcnt); + rcmail.enable_command('plugin.managesieve-setdel', setcnt > 1); } } if (rcmail.gui_objects.sieveform && rcmail.env.rule_disabled) @@ -59,7 +100,7 @@ if (window.rcmail) { }; /*********************************************************/ -/********* Managesieve filters methods *********/ +/********* Managesieve UI methods *********/ /*********************************************************/ rcube_webmail.prototype.managesieve_add = function() @@ -71,23 +112,41 @@ rcube_webmail.prototype.managesieve_add = function() rcube_webmail.prototype.managesieve_del = function() { var id = this.filters_list.get_single_selection(); - if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) - this.http_request('plugin.managesieve', - '_act=delete&_fid='+this.filters_list.rows[id].uid, true); + if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) { + var lock = this.set_busy(true, 'loading'); + this.http_post('plugin.managesieve', + '_act=delete&_fid='+this.filters_list.rows[id].uid, lock); + } }; -rcube_webmail.prototype.managesieve_up = function() +rcube_webmail.prototype.managesieve_act = function() { - var id = this.filters_list.get_single_selection(); - this.http_request('plugin.managesieve', - '_act=up&_fid='+this.filters_list.rows[id].uid, true); + var id = this.filters_list.get_single_selection(), + lock = this.set_busy(true, 'loading'); + + this.http_post('plugin.managesieve', + '_act=act&_fid='+this.filters_list.rows[id].uid, lock); }; -rcube_webmail.prototype.managesieve_down = function() +// Filter selection +rcube_webmail.prototype.managesieve_select = function(list) { - var id = this.filters_list.get_single_selection(); - this.http_request('plugin.managesieve', - '_act=down&_fid='+this.filters_list.rows[id].uid, true); + var id = list.get_single_selection(); + if (id != null) + this.load_managesieveframe(list.rows[id].uid); +}; + +// Set selection +rcube_webmail.prototype.managesieve_setselect = function(list) +{ + this.show_contentframe(false); + this.filters_list.clear(true); + this.enable_command('plugin.managesieve-setdel', list.rowcount > 1); + this.enable_command( 'plugin.managesieve-setact', 'plugin.managesieve-setget', true); + + var id = list.get_single_selection(); + if (id != null) + this.managesieve_list(this.env.filtersets[id]); }; rcube_webmail.prototype.managesieve_rowid = function(id) @@ -99,194 +158,275 @@ rcube_webmail.prototype.managesieve_rowid = function(id) return i; }; -rcube_webmail.prototype.managesieve_updatelist = function(action, name, id, disabled) +// Returns set's identifier +rcube_webmail.prototype.managesieve_setid = function(name) +{ + for (var i in this.env.filtersets) + if (this.env.filtersets[i] == name) + return i; +}; + +// Filters listing request +rcube_webmail.prototype.managesieve_list = function(script) +{ + var lock = this.set_busy(true, 'loading'); + + this.http_post('plugin.managesieve', '_act=list&_set='+urlencode(script), lock); +}; + +// Script download request +rcube_webmail.prototype.managesieve_setget = function() +{ + var id = this.filtersets_list.get_single_selection(), + script = this.env.filtersets[id]; + + location.href = this.env.comm_path+'&_action=plugin.managesieve&_act=setget&_set='+urlencode(script); +}; + +// Set activate/deactivate request +rcube_webmail.prototype.managesieve_setact = function() +{ + var id = this.filtersets_list.get_single_selection(), + lock = this.set_busy(true, 'loading'), + script = this.env.filtersets[id], + action = $('#rcmrow'+id).hasClass('disabled') ? 'setact' : 'deact'; + + this.http_post('plugin.managesieve', '_act='+action+'&_set='+urlencode(script), lock); +}; + +// Set delete request +rcube_webmail.prototype.managesieve_setdel = function() +{ + if (!confirm(this.get_label('managesieve.setdeleteconfirm'))) + return false; + + var id = this.filtersets_list.get_single_selection(), + lock = this.set_busy(true, 'loading'), + script = this.env.filtersets[id]; + + this.http_post('plugin.managesieve', '_act=setdel&_set='+urlencode(script), lock); +}; + +// Set add request +rcube_webmail.prototype.managesieve_setadd = function() +{ + this.filters_list.clear_selection(); + this.enable_command('plugin.managesieve-act', 'plugin.managesieve-del', false); + + if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) { + var lock = this.set_busy(true, 'loading'); + target = window.frames[this.env.contentframe]; + target.location.href = this.env.comm_path+'&_action=plugin.managesieve&_framed=1&_newset=1&_unlock='+lock; + } +}; + +rcube_webmail.prototype.managesieve_updatelist = function(action, o) { this.set_busy(true); switch (action) { - case 'delete': - this.filters_list.remove_row(this.managesieve_rowid(id)); - this.filters_list.clear_selection(); - this.enable_command('plugin.managesieve-del', 'plugin.managesieve-up', 'plugin.managesieve-down', false); + + // Delete filter row + case 'del': + var i, list = this.filters_list, rows = list.rows; + + list.remove_row(this.managesieve_rowid(o.id)); + list.clear_selection(); this.show_contentframe(false); + this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', false); // re-numbering filters - var i, rows = this.filters_list.rows; for (i=0; i<rows.length; i++) { - if (rows[i] != null && rows[i].uid > id) + if (rows[i] != null && rows[i].uid > o.id) rows[i].uid = rows[i].uid-1; } + break; - case 'down': - var from, fromstatus, status, rows = this.filters_list.rows; + // Update filter row + case 'update': + var i, row = $('#rcmrow'+o.id); + + if (o.name) + $('td', row).html(o.name); + if (o.disabled) + row.addClass('disabled'); + else + row.removeClass('disabled'); + + $('#disabled', $('iframe').contents()).prop('checked', o.disabled); - // we need only to replace filter names... - for (var i=0; i<rows.length; i++) { - if (rows[i]==null) { // removed row - continue; - } - else if (rows[i].uid == id) { - from = rows[i].obj; - fromstatus = $(from).hasClass('disabled'); - } - else if (rows[i].uid == id+1) { - name = rows[i].obj.cells[0].innerHTML; - status = $(rows[i].obj).hasClass('disabled'); - rows[i].obj.cells[0].innerHTML = from.cells[0].innerHTML; - from.cells[0].innerHTML = name; - $(from)[status?'addClass':'removeClass']('disabled'); - $(rows[i].obj)[fromstatus?'addClass':'removeClass']('disabled'); - this.filters_list.highlight_row(i); - break; - } - } - // ... and disable/enable Down button - this.filters_listbuttons(); break; - case 'up': - var from, status, fromstatus, rows = this.filters_list.rows; + // Add filter row to the list + case 'add': + var list = this.filters_list, + row = $('<tr><td class="name"></td></tr>'); + + $('td', row).html(o.name); + row.attr('id', 'rcmrow'+o.id); + if (o.disabled) + row.addClass('disabled'); + + list.insert_row(row.get(0)); + list.highlight_row(o.id); + + this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', true); - // we need only to replace filter names... - for (var i=0; i<rows.length; i++) { - if (rows[i] == null) { // removed row - continue; - } - else if (rows[i].uid == id-1) { - from = rows[i].obj; - fromstatus = $(from).hasClass('disabled'); - this.filters_list.highlight_row(i); - } - else if (rows[i].uid == id) { - name = rows[i].obj.cells[0].innerHTML; - status = $(rows[i].obj).hasClass('disabled'); - rows[i].obj.cells[0].innerHTML = from.cells[0].innerHTML; - from.cells[0].innerHTML = name; - $(from)[status?'addClass':'removeClass']('disabled'); - $(rows[i].obj)[fromstatus?'addClass':'removeClass']('disabled'); - break; - } - } - // ... and disable/enable Up button - this.filters_listbuttons(); break; - case 'update': - var rows = parent.rcmail.filters_list.rows; - for (var i=0; i<rows.length; i++) - if (rows[i] && rows[i].uid == id) { - rows[i].obj.cells[0].innerHTML = name; - if (disabled) - $(rows[i].obj).addClass('disabled'); - else - $(rows[i].obj).removeClass('disabled'); - break; - } + // Filling rules list + case 'list': + var i, tr, td, el, list = this.filters_list; + + if (o.clear) + list.clear(); + + for (i in o.list) { + el = o.list[i]; + tr = document.createElement('TR'); + td = document.createElement('TD'); + + td.innerHTML = el.name; + td.className = 'name'; + tr.id = 'rcmrow' + el.id; + if (el['class']) + tr.className = el['class']; + tr.appendChild(td); + + list.insert_row(tr); + } + + if (o.set) + list.highlight_row(o.set); + else + this.enable_command('plugin.managesieve-del', 'plugin.managesieve-act', false); + break; - case 'add': - var row, new_row, td, list = parent.rcmail.filters_list; - - if (!list) - break; - - for (var i=0; i<list.rows.length; i++) - if (list.rows[i] != null && String(list.rows[i].obj.id).match(/^rcmrow/)) - row = list.rows[i].obj; - - if (row) { - new_row = parent.document.createElement('tr'); - new_row.id = 'rcmrow'+id; - td = parent.document.createElement('td'); - new_row.appendChild(td); - list.insert_row(new_row, false); - if (disabled) - $(new_row).addClass('disabled'); - if (row.cells[0].className) - td.className = row.cells[0].className; - - td.innerHTML = name; - list.highlight_row(id); - - parent.rcmail.enable_command('plugin.managesieve-del', 'plugin.managesieve-up', true); + // Sactivate/deactivate set + case 'setact': + var id = this.managesieve_setid(o.name), row = $('#rcmrow' + id); + if (o.active) { + if (o.all) + $('tr', this.gui_objects.filtersetslist).addClass('disabled'); + row.removeClass('disabled'); } - else // refresh whole page - parent.rcmail.goto_url('plugin.managesieve'); + else + row.addClass('disabled'); + break; - } - this.set_busy(false); -}; + // Delete set row + case 'setdel': + var id = this.managesieve_setid(o.name); -rcube_webmail.prototype.managesieve_select = function(list) -{ - var id = list.get_single_selection(); - if (id != null) - this.load_managesieveframe(list.rows[id].uid); -}; + this.filtersets_list.remove_row(id); + this.filters_list.clear(); + this.show_contentframe(false); + this.enable_command('plugin.managesieve-setdel', 'plugin.managesieve-setact', 'plugin.managesieve-setget', false); -rcube_webmail.prototype.managesieve_save = function() -{ - if (parent.rcmail && parent.rcmail.filters_list && this.gui_objects.sieveform.name != 'filtersetform') { - var id = parent.rcmail.filters_list.get_single_selection(); - if (id != null) - this.gui_objects.sieveform.elements['_fid'].value = parent.rcmail.filters_list.rows[id].uid; + delete this.env.filtersets[id]; + + break; + + // Create set row + case 'setadd': + var id = 'S' + new Date().getTime(), + list = this.filtersets_list, + row = $('<tr class="disabled"><td class="name"></td></tr>'); + + $('td', row).html(o.name); + row.attr('id', 'rcmrow'+id); + + this.env.filtersets[id] = o.name; + list.insert_row(row.get(0)); + + // move row into its position on the list + if (o.index != list.rowcount-1) { + row.detach(); + var elem = $('tr:visible', list.list).get(o.index); + row.insertBefore(elem); + } + + list.select(id); + + break; } - this.gui_objects.sieveform.submit(); + + this.set_busy(false); }; // load filter frame rcube_webmail.prototype.load_managesieveframe = function(id) { - if (typeof(id) != 'undefined' && id != null) { - this.enable_command('plugin.managesieve-del', true); - this.filters_listbuttons(); - } - else - this.enable_command('plugin.managesieve-up', 'plugin.managesieve-down', 'plugin.managesieve-del', false); + var has_id = typeof(id) != 'undefined' && id != null; + this.enable_command('plugin.managesieve-act', 'plugin.managesieve-del', has_id); if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) { target = window.frames[this.env.contentframe]; var msgid = this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+'&_action=plugin.managesieve&_framed=1&_fid='+id+'&_unlock='+msgid; + target.location.href = this.env.comm_path+'&_action=plugin.managesieve&_framed=1' + +(id ? '&_fid='+id : '')+'&_unlock='+msgid; } }; -// enable/disable Up/Down buttons -rcube_webmail.prototype.filters_listbuttons = function() +// load filter frame +rcube_webmail.prototype.managesieve_dragstart = function(list) { - var id = this.filters_list.get_single_selection(), - rows = this.filters_list.rows; + var id = this.filters_list.get_single_selection(); - for (var i=0; i<rows.length; i++) { - if (rows[i] == null) { // removed row - } - else if (i == id) { - this.enable_command('plugin.managesieve-up', false); - break; - } - else { - this.enable_command('plugin.managesieve-up', true); - break; + this.drag_active = true; + this.drag_filter = id; +}; + +rcube_webmail.prototype.managesieve_dragend = function(e) +{ + if (this.drag_active) { + if (this.drag_filter_target) { + var lock = this.set_busy(true, 'loading'); + + this.show_contentframe(false); + this.http_post('plugin.managesieve', '_act=move&_fid='+this.drag_filter + +'&_to='+this.drag_filter_target, lock); } + this.drag_active = false; } +}; - for (var i=rows.length-1; i>0; i--) { - if (rows[i] == null) { // removed row - } - else if (i == id) { - this.enable_command('plugin.managesieve-down', false); - break; - } - else { - this.enable_command('plugin.managesieve-down', true); - break; - } - } +rcube_webmail.prototype.managesieve_focus_filter = function(row) +{ + var id = row.id.replace(/^rcmrow/, ''); + if (this.drag_active && id != this.drag_filter) { + this.drag_filter_target = id; + $(row.obj).addClass(id < this.drag_filter ? 'filtermoveup' : 'filtermovedown'); + } +}; + +rcube_webmail.prototype.managesieve_unfocus_filter = function(row) +{ + if (this.drag_active) { + $(row.obj).removeClass('filtermoveup filtermovedown'); + this.drag_filter_target = null; + } +}; + +/*********************************************************/ +/********* Filter Form methods *********/ +/*********************************************************/ + +// Form submition +rcube_webmail.prototype.managesieve_save = function() +{ + if (parent.rcmail && parent.rcmail.filters_list && this.gui_objects.sieveform.name != 'filtersetform') { + var id = parent.rcmail.filters_list.get_single_selection(); + if (id != null) + this.gui_objects.sieveform.elements['_fid'].value = parent.rcmail.filters_list.rows[id].uid; + } + this.gui_objects.sieveform.submit(); }; -// operations on filters form +// Operations on filters form rcube_webmail.prototype.managesieve_ruleadd = function(id) { this.http_post('plugin.managesieve', '_act=ruleadd&_rid='+id); @@ -311,6 +451,9 @@ rcube_webmail.prototype.managesieve_rulefill = function(content, id, after) rcube_webmail.prototype.managesieve_ruledel = function(id) { + if ($('#ruledel'+id).hasClass('disabled')) + return; + if (confirm(this.get_label('managesieve.ruledeleteconfirm'))) { var row = document.getElementById('rulerow'+id); row.parentNode.removeChild(row); @@ -341,6 +484,9 @@ rcube_webmail.prototype.managesieve_actionfill = function(content, id, after) rcube_webmail.prototype.managesieve_actiondel = function(id) { + if ($('#actiondel'+id).hasClass('disabled')) + return; + if (confirm(this.get_label('managesieve.actiondeleteconfirm'))) { var row = document.getElementById('actionrow'+id); row.parentNode.removeChild(row); @@ -383,155 +529,44 @@ rcube_webmail.prototype.managesieve_formbuttons = function(div) button = document.getElementById(buttons[i]); if (i>0 || buttons.length>1) { $(button).removeClass('disabled'); - button.removeAttribute('disabled'); } else { $(button).addClass('disabled'); - button.setAttribute('disabled', true); } } }; -// Set change -rcube_webmail.prototype.managesieve_set = function() -{ - var script = $(this.gui_objects.filtersetslist).val(); - location.href = this.env.comm_path+'&_action=plugin.managesieve&_set='+script; -}; - -// Script download -rcube_webmail.prototype.managesieve_setget = function() -{ - var script = $(this.gui_objects.filtersetslist).val(); - location.href = this.env.comm_path+'&_action=plugin.managesieve&_act=setget&_set='+script; -}; - -// Set activate -rcube_webmail.prototype.managesieve_setact = function() -{ - if (!this.gui_objects.filtersetslist) - return false; - - var script = this.gui_objects.filtersetslist.value, - action = (script == rcmail.env.active_set ? 'deact' : 'setact'); - - this.http_post('plugin.managesieve', '_act='+action+'&_set='+script); -}; - -// Set activate flag in sets list after set activation -rcube_webmail.prototype.managesieve_reset = function() -{ - if (!this.gui_objects.filtersetslist) - return false; - - var list = this.gui_objects.filtersetslist, - opts = list.getElementsByTagName('option'), - label = ' (' + this.get_label('managesieve.active') + ')', - regx = new RegExp(RegExp.escape(label)+'$'); - - for (var x=0; x<opts.length; x++) { - if (opts[x].value != rcmail.env.active_set && opts[x].innerHTML.match(regx)) - opts[x].innerHTML = opts[x].innerHTML.replace(regx, ''); - else if (opts[x].value == rcmail.env.active_set) - opts[x].innerHTML = opts[x].innerHTML + label; - } - - // change title of setact button - $('#'+rcmail.buttons['plugin.managesieve-setact'][0].id).attr('title', rcmail.gettext('managesieve.filterset' - + (list.value == rcmail.env.active_set ? 'deact' : 'act'))); -}; - -// Set delete -rcube_webmail.prototype.managesieve_setdel = function() -{ - if (!this.gui_objects.filtersetslist) - return false; - - if (!confirm(this.get_label('managesieve.setdeleteconfirm'))) - return false; - - var script = this.gui_objects.filtersetslist.value; - this.http_post('plugin.managesieve', '_act=setdel&_set='+script); -}; - -// Set add -rcube_webmail.prototype.managesieve_setadd = function() -{ - this.filters_list.clear_selection(); - this.enable_command('plugin.managesieve-up', 'plugin.managesieve-down', 'plugin.managesieve-del', false); - - if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) { - target = window.frames[this.env.contentframe]; - var msgid = this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+'&_action=plugin.managesieve&_framed=1&_newset=1&_unlock='+msgid; - } -}; - -rcube_webmail.prototype.managesieve_reload = function(set) -{ - this.env.reload_set = set; - window.setTimeout(function() { - location.href = rcmail.env.comm_path + '&_action=plugin.managesieve' - + (rcmail.env.reload_set ? '&_set=' + rcmail.env.reload_set : '') - }, 500); -}; - -// Register onmouse(leave/enter) events for tips on specified form element -rcube_webmail.prototype.managesieve_tip_register = function(tips) -{ - for (var n in tips) { - $('#'+tips[n][0]) - .bind('mouseenter', {str: tips[n][1]}, - function(e) { - var offset = $(this).offset(), - tip = rcmail.env.framed ? parent.rcmail.env.ms_tip_layer : rcmail.env.ms_tip_layer, - left = offset.left, - top = offset.top - 12; - - if (rcmail.env.framed) { - offset = $(parent.document.getElementById('filter-box')).offset(); - top += offset.top; - left += offset.left; - } - - tip.html(e.data.str) - top -= tip.height(); - - tip.css({left: left, top: top}).show(); - }) - .bind('mouseleave', - function(e) { - var tip = parent.rcmail && parent.rcmail.env.ms_tip_layer ? - parent.rcmail.env.ms_tip_layer : rcmail.env.ms_tip_layer; - tip.hide(); - }); - } -}; - -/*********************************************************/ -/********* Other Managesieve UI methods *********/ -/*********************************************************/ - function rule_header_select(id) { var obj = document.getElementById('header' + id), size = document.getElementById('rule_size' + id), op = document.getElementById('rule_op' + id), target = document.getElementById('rule_target' + id), - header = document.getElementById('custom_header' + id); + header = document.getElementById('custom_header' + id), + mod = document.getElementById('rule_mod' + id), + trans = document.getElementById('rule_trans' + id), + comp = document.getElementById('rule_comp' + id); if (obj.value == 'size') { size.style.display = 'inline'; op.style.display = 'none'; target.style.display = 'none'; header.style.display = 'none'; + mod.style.display = 'none'; + trans.style.display = 'none'; + comp.style.display = 'none'; } else { header.style.display = obj.value != '...' ? 'none' : 'inline'; size.style.display = 'none'; op.style.display = 'inline'; + comp.style.display = ''; rule_op_select(id); + mod.style.display = obj.value == 'body' ? 'none' : 'block'; + trans.style.display = obj.value == 'body' ? 'block' : 'none'; } + + obj.style.width = obj.value == '...' ? '40px' : ''; }; function rule_op_select(id) @@ -542,15 +577,45 @@ function rule_op_select(id) target.style.display = obj.value == 'exists' || obj.value == 'notexists' ? 'none' : 'inline'; }; +function rule_trans_select(id) +{ + var obj = document.getElementById('rule_trans_op' + id), + target = document.getElementById('rule_trans_type' + id); + + target.style.display = obj.value != 'content' ? 'none' : 'inline'; +}; + +function rule_mod_select(id) +{ + var obj = document.getElementById('rule_mod_op' + id), + target = document.getElementById('rule_mod_type' + id); + + target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline'; +}; + function rule_join_radio(value) { $('#rules').css('display', value == 'any' ? 'none' : 'block'); }; +function rule_adv_switch(id, elem) +{ + var elem = $(elem), enabled = elem.hasClass('hide'), adv = $('#rule_advanced'+id); + + if (enabled) { + adv.hide(); + elem.removeClass('hide').addClass('show'); + } + else { + adv.show(); + elem.removeClass('show').addClass('hide'); + } +} + function action_type_select(id) { var obj = document.getElementById('action_type' + id), - enabled = {}, + enabled = {}, elems = { mailbox: document.getElementById('action_mailbox' + id), target: document.getElementById('action_target' + id), @@ -579,3 +644,126 @@ function action_type_select(id) elems[x].style.display = !enabled[x] ? 'none' : 'inline'; } }; + +// Register onmouse(leave/enter) events for tips on specified form element +rcube_webmail.prototype.managesieve_tip_register = function(tips) +{ + var n, framed = parent.rcmail, + tip = framed ? parent.rcmail.env.ms_tip_layer : rcmail.env.ms_tip_layer; + + for (var n in tips) { + $('#'+tips[n][0]) + .bind('mouseenter', {str: tips[n][1]}, + function(e) { + var offset = $(this).offset(), + left = offset.left, + top = offset.top - 12; + + if (framed) { + offset = $((rcmail.env.task == 'mail' ? '#sievefilterform > iframe' : '#filter-box'), parent.document).offset(); + top += offset.top; + left += offset.left; + } + + tip.html(e.data.str) + top -= tip.height(); + + tip.css({left: left, top: top}).show(); + }) + .bind('mouseleave', function(e) { tip.hide(); }); + } +}; + +/*********************************************************/ +/********* Mail UI methods *********/ +/*********************************************************/ + +rcube_webmail.prototype.managesieve_create = function() +{ + if (!rcmail.env.sieve_headers || !rcmail.env.sieve_headers.length) + return; + + var i, html, buttons = {}, dialog = $("#sievefilterform"); + + // create dialog window + if (!dialog.length) { + dialog = $('<div id="sievefilterform"></div>'); + $('body').append(dialog); + } + + // build dialog window content + html = '<fieldset><legend>'+this.gettext('managesieve.usedata')+'</legend><ul>'; + for (i in rcmail.env.sieve_headers) + html += '<li><input type="checkbox" name="headers[]" id="sievehdr'+i+'" value="'+i+'" checked="checked" />' + +'<label for="sievehdr'+i+'">'+rcmail.env.sieve_headers[i][0]+':</label> '+rcmail.env.sieve_headers[i][1]+'</li>'; + html += '</ul></fieldset>'; + + dialog.html(html); + + // [Next Step] button action + buttons[this.gettext('managesieve.nextstep')] = function () { + // check if there's at least one checkbox checked + var hdrs = $('input[name="headers[]"]:checked', dialog); + if (!hdrs.length) { + alert(rcmail.gettext('managesieve.nodata')); + return; + } + + // build frame URL + var url = rcmail.get_task_url('mail'); + url = rcmail.add_url(url, '_action', 'plugin.managesieve'); + url = rcmail.add_url(url, '_framed', 1); + + hdrs.map(function() { + var val = rcmail.env.sieve_headers[this.value]; + url = rcmail.add_url(url, 'r['+this.value+']', val[0]+':'+val[1]); + }); + + // load form in the iframe + var frame = $('<iframe>').attr({src: url, frameborder: 0}) + dialog.empty().append(frame).dialog('dialog').resize(); + + // Change [Next Step] button with [Save] button + buttons = {}; + buttons[rcmail.gettext('save')] = function() { + var win = $('iframe', dialog).get(0).contentWindow; + win.rcmail.managesieve_save(); + }; + dialog.dialog('option', 'buttons', buttons); + }; + + // show dialog window + dialog.dialog({ + modal: false, + resizable: !bw.ie6, + closeOnEscape: (!bw.ie6 && !bw.ie7), // disable for performance reasons + title: this.gettext('managesieve.newfilter'), + close: function() { rcmail.managesieve_dialog_close(); }, + buttons: buttons, + minWidth: 600, + minHeight: 300, + height: 250 + }).show(); + + this.env.managesieve_dialog = dialog; +} + +rcube_webmail.prototype.managesieve_dialog_close = function() +{ + var dialog = this.env.managesieve_dialog; + + // BUG(?): if we don't remove the iframe first, it will be reloaded + dialog.html(''); + dialog.dialog('destroy').hide(); +} + +rcube_webmail.prototype.managesieve_dialog_resize = function(o) +{ + var dialog = this.env.managesieve_dialog, + win = $(window), form = $(o); + width = form.width(), height = form.height(), + w = win.width(), h = win.height(); + + dialog.dialog('option', { height: Math.min(h-20, height+120), width: Math.min(w-20, width+65) }) + .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?) +} diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index 2cb7122..d557907 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -7,12 +7,13 @@ * It's clickable interface which operates on text scripts and communicates * with server using managesieve protocol. Adds Filters tab in Settings. * - * @version 4.3 + * @version 5.0 * @author Aleksander Machniak <alec@alec.pl> * * Configuration (see config.inc.php.dist) * * Copyright (C) 2008-2011, The Roundcube Dev Team + * Copyright (C) 2011, Kolab Systems AG * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -27,12 +28,12 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * $Id: managesieve.php 4983 2011-07-28 07:31:16Z alec $ + * $Id: managesieve.php 5452 2011-11-18 14:44:48Z alec $ */ class managesieve extends rcube_plugin { - public $task = 'settings'; + public $task = 'mail|settings'; private $rc; private $sieve; @@ -41,29 +42,141 @@ class managesieve extends rcube_plugin private $tips = array(); private $script = array(); private $exts = array(); + private $list; + private $active = array(); private $headers = array( - 'subject' => 'Subject', - 'sender' => 'From', - 'recipient' => 'To', + 'subject' => 'Subject', + 'from' => 'From', + 'to' => 'To', ); + private $addr_headers = array( + // Required + "from", "to", "cc", "bcc", "sender", "resent-from", "resent-to", + // Additional (RFC 822 / RFC 2822) + "reply-to", "resent-reply-to", "resent-sender", "resent-cc", "resent-bcc", + // Non-standard (RFC 2076, draft-palme-mailext-headers-08.txt) + "for-approval", "for-handling", "for-comment", "apparently-to", "errors-to", + "delivered-to", "return-receipt-to", "x-admin", "read-receipt-to", + "x-confirm-reading-to", "return-receipt-requested", + "registered-mail-reply-requested-by", "mail-followup-to", "mail-reply-to", + "abuse-reports-to", "x-complaints-to", "x-report-abuse-to", + // Undocumented + "x-beenthere", + ); + + const VERSION = '5.0'; + const PROGNAME = 'Roundcube (Managesieve)'; function init() { - // add Tab label/title - $this->add_texts('localization/', array('filters','managefilters')); + $this->rc = rcmail::get_instance(); // register actions $this->register_action('plugin.managesieve', array($this, 'managesieve_actions')); $this->register_action('plugin.managesieve-save', array($this, 'managesieve_save')); - // include main js script + if ($this->rc->task == 'settings') { + $this->init_ui(); + } + else if ($this->rc->task == 'mail') { + // register message hook + $this->add_hook('message_headers_output', array($this, 'mail_headers')); + + // inject Create Filter popup stuff + if (empty($this->rc->action) || $this->rc->action == 'show') { + $this->mail_task_handler(); + } + } + } + + /** + * Initializes plugin's UI (localization, js script) + */ + private function init_ui() + { + if ($this->ui_initialized) + return; + + // load localization + $this->add_texts('localization/', array('filters','managefilters')); $this->include_script('managesieve.js'); + + $this->ui_initialized = true; + } + + /** + * Add UI elements to the 'mailbox view' and 'show message' UI. + */ + function mail_task_handler() + { + // use jQuery for popup window + $this->require_plugin('jqueryui'); + + // include js script and localization + $this->init_ui(); + + // include styles + $skin = $this->rc->config->get('skin'); + if (!file_exists($this->home."/skins/$skin/managesieve_mail.css")) + $skin = 'default'; + $this->include_stylesheet("skins/$skin/managesieve_mail.css"); + + // add 'Create filter' item to message menu + $this->api->add_content(html::tag('li', null, + $this->api->output->button(array( + 'command' => 'managesieve-create', + 'label' => 'managesieve.filtercreate', + 'type' => 'link', + 'classact' => 'filterlink active', + 'class' => 'filterlink', + ))), 'messagemenu'); + + // register some labels/messages + $this->rc->output->add_label('managesieve.newfilter', 'managesieve.usedata', + 'managesieve.nodata', 'managesieve.nextstep', 'save'); + + $this->rc->session->remove('managesieve_current'); } + /** + * Get message headers for popup window + */ + function mail_headers($args) + { + $headers = $args['headers']; + $ret = array(); + + if ($headers->subject) + $ret[] = array('Subject', $this->rc->imap->decode_header($headers->subject)); + + // @TODO: List-Id, others? + foreach (array('From', 'To') as $h) { + $hl = strtolower($h); + if ($headers->$hl) { + $list = $this->rc->imap->decode_address_list($headers->$hl); + foreach ($list as $item) { + if ($item['mailto']) { + $ret[] = array($h, $item['mailto']); + } + } + } + } + + if ($this->rc->action == 'preview') + $this->rc->output->command('parent.set_env', array('sieve_headers' => $ret)); + else + $this->rc->output->set_env('sieve_headers', $ret); + + + return $args; + } + + /** + * Loads configuration, initializes plugin (including sieve connection) + */ function managesieve_start() { - $this->rc = rcmail::get_instance(); $this->load_config(); // register UI objects @@ -85,33 +198,47 @@ class managesieve extends rcube_plugin $host = rcube_idn_to_ascii($host); + $plugin = $this->rc->plugins->exec_hook('managesieve_connect', array( + 'user' => $_SESSION['username'], + 'password' => $this->rc->decrypt($_SESSION['password']), + 'host' => $host, + 'port' => $port, + 'auth_type' => $this->rc->config->get('managesieve_auth_type'), + 'usetls' => $this->rc->config->get('managesieve_usetls', false), + 'disabled' => $this->rc->config->get('managesieve_disabled_extensions'), + 'debug' => $this->rc->config->get('managesieve_debug', false), + 'auth_cid' => $this->rc->config->get('managesieve_auth_cid'), + 'auth_pw' => $this->rc->config->get('managesieve_auth_pw'), + )); + // try to connect to managesieve server and to fetch the script - $this->sieve = new rcube_sieve($_SESSION['username'], - $this->rc->decrypt($_SESSION['password']), $host, $port, - $this->rc->config->get('managesieve_auth_type'), - $this->rc->config->get('managesieve_usetls', false), - $this->rc->config->get('managesieve_disabled_extensions'), - $this->rc->config->get('managesieve_debug', false), - $this->rc->config->get('managesieve_auth_cid'), - $this->rc->config->get('managesieve_auth_pw') + $this->sieve = new rcube_sieve( + $plugin['user'], + $plugin['password'], + $plugin['host'], + $plugin['port'], + $plugin['auth_type'], + $plugin['usetls'], + $plugin['disabled'], + $plugin['debug'], + $plugin['auth_cid'], + $plugin['auth_pw'] ); if (!($error = $this->sieve->error())) { + // Get list of scripts + $list = $this->list_scripts(); - $list = $this->sieve->get_scripts(); - $active = $this->sieve->get_active(); - $_SESSION['managesieve_active'] = $active; - - if (!empty($_GET['_set'])) { - $script_name = get_input_value('_set', RCUBE_INPUT_GET); + if (!empty($_GET['_set']) || !empty($_POST['_set'])) { + $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); } else if (!empty($_SESSION['managesieve_current'])) { $script_name = $_SESSION['managesieve_current']; } else { - // get active script - if ($active) { - $script_name = $active; + // get (first) active script + if (!empty($this->active[0])) { + $script_name = $this->active[0]; } else if ($list) { $script_name = $list[0]; @@ -120,19 +247,25 @@ class managesieve extends rcube_plugin else { // if script not exists build default script contents $script_file = $this->rc->config->get('managesieve_default'); - $script_name = 'roundcube'; + $script_name = $this->rc->config->get('managesieve_script_name'); + + if (empty($script_name)) + $script_name = 'roundcube'; + if ($script_file && is_readable($script_file)) $content = file_get_contents($script_file); - // add script and set it active - if ($this->sieve->save_script($script_name, $content)) - if ($this->sieve->activate($script_name)) - $_SESSION['managesieve_active'] = $script_name; + // add script and set it active + if ($this->sieve->save_script($script_name, $content)) { + $this->activate_script($script_name); + $this->list[] = $script_name; + } } } - if ($script_name) + if ($script_name) { $this->sieve->load($script_name); + } $error = $this->sieve->error(); } @@ -158,9 +291,9 @@ class managesieve extends rcube_plugin $this->script = array(); } else { - $this->script = $this->sieve->script->as_array(); $this->exts = $this->sieve->get_extensions(); - $this->rc->output->set_env('active_set', $_SESSION['managesieve_active']); + $this->script = $this->sieve->script->as_array(); + $this->rc->output->set_env('currentset', $this->sieve->current); $_SESSION['managesieve_current'] = $this->sieve->current; } @@ -169,94 +302,131 @@ class managesieve extends rcube_plugin function managesieve_actions() { - // Init plugin and handle managesieve connection + $this->init_ui(); + $error = $this->managesieve_start(); // Handle user requests if ($action = get_input_value('_act', RCUBE_INPUT_GPC)) { - $fid = (int) get_input_value('_fid', RCUBE_INPUT_GET); + $fid = (int) get_input_value('_fid', RCUBE_INPUT_POST); - if ($action == 'up' && !$error) { - if ($fid && isset($this->script[$fid]) && isset($this->script[$fid-1])) { - if ($this->sieve->script->update_rule($fid, $this->script[$fid-1]) !== false - && $this->sieve->script->update_rule($fid-1, $this->script[$fid]) !== false) { - $result = $this->sieve->save(); - } + if ($action == 'delete' && !$error) { + if (isset($this->script[$fid])) { + if ($this->sieve->script->delete_rule($fid)) + $result = $this->save_script(); - if ($result) { -// $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); - $this->rc->output->command('managesieve_updatelist', 'up', '', $fid); - } else - $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); + if ($result === true) { + $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation'); + $this->rc->output->command('managesieve_updatelist', 'del', array('id' => $fid)); + } else { + $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); + } } } - else if ($action == 'down' && !$error) { - if (isset($this->script[$fid]) && isset($this->script[$fid+1])) { - if ($this->sieve->script->update_rule($fid, $this->script[$fid+1]) !== false - && $this->sieve->script->update_rule($fid+1, $this->script[$fid]) !== false) { - $result = $this->sieve->save(); + else if ($action == 'move' && !$error) { + if (isset($this->script[$fid])) { + $to = (int) get_input_value('_to', RCUBE_INPUT_POST); + $rule = $this->script[$fid]; + + // remove rule + unset($this->script[$fid]); + $this->script = array_values($this->script); + + // add at target position + if ($to >= count($this->script)) { + $this->script[] = $rule; + } + else { + $script = array(); + foreach ($this->script as $idx => $r) { + if ($idx == $to) + $script[] = $rule; + $script[] = $r; + } + $this->script = $script; } + $this->sieve->script->content = $this->script; + $result = $this->save_script(); + if ($result === true) { -// $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); - $this->rc->output->command('managesieve_updatelist', 'down', '', $fid); + $result = $this->list_rules(); + + $this->rc->output->show_message('managesieve.moved', 'confirmation'); + $this->rc->output->command('managesieve_updatelist', 'list', + array('list' => $result, 'clear' => true, 'set' => $to)); } else { - $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); + $this->rc->output->show_message('managesieve.moveerror', 'error'); } } } - else if ($action == 'delete' && !$error) { + else if ($action == 'act' && !$error) { if (isset($this->script[$fid])) { - if ($this->sieve->script->delete_rule($fid)) - $result = $this->sieve->save(); + $rule = $this->script[$fid]; + $disabled = $rule['disabled'] ? true : false; + $rule['disabled'] = !$disabled; + $result = $this->sieve->script->update_rule($fid, $rule); + + if ($result !== false) + $result = $this->save_script(); if ($result === true) { - $this->rc->output->show_message('managesieve.filterdeleted', 'confirmation'); - $this->rc->output->command('managesieve_updatelist', 'delete', '', $fid); + if ($rule['disabled']) + $this->rc->output->show_message('managesieve.deactivated', 'confirmation'); + else + $this->rc->output->show_message('managesieve.activated', 'confirmation'); + $this->rc->output->command('managesieve_updatelist', 'update', + array('id' => $fid, 'disabled' => $rule['disabled'])); } else { - $this->rc->output->show_message('managesieve.filterdeleteerror', 'error'); + if ($rule['disabled']) + $this->rc->output->show_message('managesieve.deactivateerror', 'error'); + else + $this->rc->output->show_message('managesieve.activateerror', 'error'); } } } else if ($action == 'setact' && !$error) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC); - $result = $this->sieve->activate($script_name); + $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $result = $this->activate_script($script_name); + $kep14 = $this->rc->config->get('managesieve_kolab_master'); if ($result === true) { - $this->rc->output->set_env('active_set', $script_name); + $this->rc->output->set_env('active_sets', $this->active); $this->rc->output->show_message('managesieve.setactivated', 'confirmation'); - $this->rc->output->command('managesieve_reset'); - $_SESSION['managesieve_active'] = $script_name; + $this->rc->output->command('managesieve_updatelist', 'setact', + array('name' => $script_name, 'active' => true, 'all' => !$kep14)); } else { $this->rc->output->show_message('managesieve.setactivateerror', 'error'); } } else if ($action == 'deact' && !$error) { - $result = $this->sieve->deactivate(); + $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $result = $this->deactivate_script($script_name); if ($result === true) { - $this->rc->output->set_env('active_set', ''); + $this->rc->output->set_env('active_sets', $this->active); $this->rc->output->show_message('managesieve.setdeactivated', 'confirmation'); - $this->rc->output->command('managesieve_reset'); - $_SESSION['managesieve_active'] = ''; + $this->rc->output->command('managesieve_updatelist', 'setact', + array('name' => $script_name, 'active' => false)); } else { $this->rc->output->show_message('managesieve.setdeactivateerror', 'error'); } } else if ($action == 'setdel' && !$error) { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC); - $result = $this->sieve->remove($script_name); + $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); + $result = $this->remove_script($script_name); if ($result === true) { $this->rc->output->show_message('managesieve.setdeleted', 'confirmation'); - $this->rc->output->command('managesieve_reload'); + $this->rc->output->command('managesieve_updatelist', 'setdel', + array('name' => $script_name)); $this->rc->session->remove('managesieve_current'); } else { $this->rc->output->show_message('managesieve.setdeleteerror', 'error'); } } else if ($action == 'setget') { - $script_name = get_input_value('_set', RCUBE_INPUT_GPC); + $script_name = get_input_value('_set', RCUBE_INPUT_GPC, true); $script = $this->sieve->get_script($script_name); if (PEAR::isError($script)) @@ -281,14 +451,19 @@ class managesieve extends rcube_plugin echo $script; exit; } - elseif ($action == 'ruleadd') { + else if ($action == 'list') { + $result = $this->list_rules(); + + $this->rc->output->command('managesieve_updatelist', 'list', array('list' => $result)); + } + else if ($action == 'ruleadd') { $rid = get_input_value('_rid', RCUBE_INPUT_GPC); $id = $this->genid(); $content = $this->rule_div($fid, $id, false); $this->rc->output->command('managesieve_rulefill', $content, $id, $rid); } - elseif ($action == 'actionadd') { + else if ($action == 'actionadd') { $aid = get_input_value('_aid', RCUBE_INPUT_GPC); $id = $this->genid(); $content = $this->action_div($fid, $id, false); @@ -298,25 +473,76 @@ class managesieve extends rcube_plugin $this->rc->output->send(); } + else if ($this->rc->task == 'mail') { + // Initialize the form + $rules = get_input_value('r', RCUBE_INPUT_GET); + if (!empty($rules)) { + $i = 0; + foreach ($rules as $rule) { + list($header, $value) = explode(':', $rule, 2); + $tests[$i] = array( + 'type' => 'contains', + 'test' => 'header', + 'arg1' => $header, + 'arg2' => $value, + ); + $i++; + } + + $this->form = array( + 'join' => count($tests) > 1 ? 'allof' : 'anyof', + 'name' => '', + 'tests' => $tests, + 'actions' => array( + 0 => array('type' => 'fileinto'), + 1 => array('type' => 'stop'), + ), + ); + } + } $this->managesieve_send(); } function managesieve_save() { + // load localization + $this->add_texts('localization/', array('filters','managefilters')); + + // include main js script + if ($this->api->output->type == 'html') { + $this->include_script('managesieve.js'); + } + // Init plugin and handle managesieve connection $error = $this->managesieve_start(); // filters set add action if (!empty($_POST['_newset'])) { - $name = get_input_value('_name', RCUBE_INPUT_POST); - $copy = get_input_value('_copy', RCUBE_INPUT_POST); - $from = get_input_value('_from', RCUBE_INPUT_POST); - - if (!$name) - $error = 'managesieve.emptyname'; - else if (mb_strlen($name)>128) - $error = 'managesieve.nametoolong'; + + $name = get_input_value('_name', RCUBE_INPUT_POST, true); + $copy = get_input_value('_copy', RCUBE_INPUT_POST, true); + $from = get_input_value('_from', RCUBE_INPUT_POST); + $exceptions = $this->rc->config->get('managesieve_filename_exceptions'); + $kolab = $this->rc->config->get('managesieve_kolab_master'); + $name_uc = mb_strtolower($name); + $list = $this->list_scripts(); + + if (!$name) { + $this->errors['name'] = $this->gettext('cannotbeempty'); + } + else if (mb_strlen($name) > 128) { + $this->errors['name'] = $this->gettext('nametoolong'); + } + else if (!empty($exceptions) && in_array($name, (array)$exceptions)) { + $this->errors['name'] = $this->gettext('namereserved'); + } + else if (!empty($kolab) && in_array($name_uc, array('MASTER', 'USER', 'MANAGEMENT'))) { + $this->errors['name'] = $this->gettext('namereserved'); + } + else if (in_array($name, $list)) { + $this->errors['name'] = $this->gettext('setexist'); + } else if ($from == 'file') { // from file if (is_uploaded_file($_FILES['_file']['tmp_name'])) { @@ -325,13 +551,12 @@ class managesieve extends rcube_plugin // for security don't save script directly // check syntax before, like this... $this->sieve->load_script($file); - if (!$this->sieve->save($name)) { - $error = 'managesieve.setcreateerror'; + if (!$this->save_script($name)) { + $this->errors['file'] = $this->gettext('setcreateerror'); } } else { // upload failed $err = $_FILES['_file']['error']; - $error = true; if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { $msg = rcube_label(array('name' => 'filesizeerror', @@ -339,7 +564,7 @@ class managesieve extends rcube_plugin show_bytes(parse_bytes(ini_get('upload_max_filesize')))))); } else { - $error = 'fileuploaderror'; + $this->errors['file'] = $this->gettext('fileuploaderror'); } } } @@ -347,12 +572,19 @@ class managesieve extends rcube_plugin $error = 'managesieve.setcreateerror'; } - if (!$error) { + if (!$error && empty($this->errors)) { + // Find position of the new script on the list + $list[] = $name; + asort($list, SORT_LOCALE_STRING); + $list = array_values($list); + $index = array_search($name, $list); + $this->rc->output->show_message('managesieve.setcreated', 'confirmation'); - $this->rc->output->command('parent.managesieve_reload', $name); + $this->rc->output->command('parent.managesieve_updatelist', 'setadd', + array('name' => $name, 'index' => $index)); } else if ($msg) { $this->rc->output->command('display_message', $msg, 'error'); - } else { + } else if ($error) { $this->rc->output->show_message($error, 'error'); } } @@ -363,22 +595,27 @@ class managesieve extends rcube_plugin $join = trim(get_input_value('_join', RCUBE_INPUT_POST)); // and arrays - $headers = $_POST['_header']; - $cust_headers = $_POST['_custom_header']; - $ops = $_POST['_rule_op']; - $sizeops = $_POST['_rule_size_op']; - $sizeitems = $_POST['_rule_size_item']; - $sizetargets = $_POST['_rule_size_target']; - $targets = $_POST['_rule_target']; - $act_types = $_POST['_action_type']; - $mailboxes = $_POST['_action_mailbox']; - $act_targets = $_POST['_action_target']; - $area_targets = $_POST['_action_target_area']; - $reasons = $_POST['_action_reason']; - $addresses = $_POST['_action_addresses']; - $days = $_POST['_action_days']; - $subject = $_POST['_action_subject']; - $flags = $_POST['_action_flags']; + $headers = get_input_value('_header', RCUBE_INPUT_POST); + $cust_headers = get_input_value('_custom_header', RCUBE_INPUT_POST); + $ops = get_input_value('_rule_op', RCUBE_INPUT_POST); + $sizeops = get_input_value('_rule_size_op', RCUBE_INPUT_POST); + $sizeitems = get_input_value('_rule_size_item', RCUBE_INPUT_POST); + $sizetargets = get_input_value('_rule_size_target', RCUBE_INPUT_POST); + $targets = get_input_value('_rule_target', RCUBE_INPUT_POST, true); + $mods = get_input_value('_rule_mod', RCUBE_INPUT_POST); + $mod_types = get_input_value('_rule_mod_type', RCUBE_INPUT_POST); + $body_trans = get_input_value('_rule_trans', RCUBE_INPUT_POST); + $body_types = get_input_value('_rule_trans_type', RCUBE_INPUT_POST, true); + $comparators = get_input_value('_rule_comp', RCUBE_INPUT_POST); + $act_types = get_input_value('_action_type', RCUBE_INPUT_POST, true); + $mailboxes = get_input_value('_action_mailbox', RCUBE_INPUT_POST, true); + $act_targets = get_input_value('_action_target', RCUBE_INPUT_POST, true); + $area_targets = get_input_value('_action_target_area', RCUBE_INPUT_POST, true); + $reasons = get_input_value('_action_reason', RCUBE_INPUT_POST, true); + $addresses = get_input_value('_action_addresses', RCUBE_INPUT_POST, true); + $days = get_input_value('_action_days', RCUBE_INPUT_POST); + $subject = get_input_value('_action_subject', RCUBE_INPUT_POST, true); + $flags = get_input_value('_action_flags', RCUBE_INPUT_POST); // we need a "hack" for radiobuttons foreach ($sizeitems as $item) @@ -407,23 +644,101 @@ class managesieve extends rcube_plugin } else { foreach ($headers as $idx => $header) { - $header = $this->strip_value($header); - $target = $this->strip_value($targets[$idx], true); - $op = $this->strip_value($ops[$idx]); + $header = $this->strip_value($header); + $target = $this->strip_value($targets[$idx], true); + $operator = $this->strip_value($ops[$idx]); + $comparator = $this->strip_value($comparators[$idx]); + + if ($header == 'size') { + $sizeop = $this->strip_value($sizeops[$idx]); + $sizeitem = $this->strip_value($items[$idx]); + $sizetarget = $this->strip_value($sizetargets[$idx]); + + $this->form['tests'][$i]['test'] = 'size'; + $this->form['tests'][$i]['type'] = $sizeop; + $this->form['tests'][$i]['arg'] = $sizetarget; + + if ($sizetarget == '') + $this->errors['tests'][$i]['sizetarget'] = $this->gettext('cannotbeempty'); + else if (!preg_match('/^[0-9]+(K|M|G)?$/i', $sizetarget.$sizeitem, $m)) { + $this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars'); + $this->form['tests'][$i]['item'] = $sizeitem; + } + else + $this->form['tests'][$i]['arg'] .= $m[1]; + } + else if ($header == 'body') { + $trans = $this->strip_value($body_trans[$idx]); + $trans_type = $this->strip_value($body_types[$idx], true); - // normal header - if (in_array($header, $this->headers)) { - if (preg_match('/^not/', $op)) + if (preg_match('/^not/', $operator)) $this->form['tests'][$i]['not'] = true; - $type = preg_replace('/^not/', '', $op); + $type = preg_replace('/^not/', '', $operator); + + if ($type == 'exists') { + $this->errors['tests'][$i]['op'] = true; + } + + $this->form['tests'][$i]['test'] = 'body'; + $this->form['tests'][$i]['type'] = $type; + $this->form['tests'][$i]['arg'] = $target; + + if ($target == '' && $type != 'exists') + $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); + else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) + $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); + + $this->form['tests'][$i]['part'] = $trans; + if ($trans == 'content') { + $this->form['tests'][$i]['content'] = $trans_type; + } + } + else { + $cust_header = $headers = $this->strip_value($cust_headers[$idx]); + $mod = $this->strip_value($mods[$idx]); + $mod_type = $this->strip_value($mod_types[$idx]); + + if (preg_match('/^not/', $operator)) + $this->form['tests'][$i]['not'] = true; + $type = preg_replace('/^not/', '', $operator); + + if ($header == '...') { + $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); + + if (!count($headers)) + $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); + else { + foreach ($headers as $hr) + if (!preg_match('/^[a-z0-9-]+$/i', $hr)) + $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); + } + + if (empty($this->errors['tests'][$i]['header'])) + $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; + } if ($type == 'exists') { $this->form['tests'][$i]['test'] = 'exists'; - $this->form['tests'][$i]['arg'] = $header; + $this->form['tests'][$i]['arg'] = $header == '...' ? $cust_header : $header; } else { + $test = 'header'; + $header = $header == '...' ? $cust_header : $header; + + if ($mod == 'address' || $mod == 'envelope') { + $found = false; + if (empty($this->errors['tests'][$i]['header'])) { + foreach ((array)$header as $hdr) { + if (!in_array(strtolower(trim($hdr)), $this->addr_headers)) + $found = true; + } + } + if (!$found) + $test = $mod; + } + $this->form['tests'][$i]['type'] = $type; - $this->form['tests'][$i]['test'] = 'header'; + $this->form['tests'][$i]['test'] = $test; $this->form['tests'][$i]['arg1'] = $header; $this->form['tests'][$i]['arg2'] = $target; @@ -431,65 +746,20 @@ class managesieve extends rcube_plugin $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); + + if ($mod) { + $this->form['tests'][$i]['part'] = $mod_type; + } } } - else - switch ($header) { - case 'size': - $sizeop = $this->strip_value($sizeops[$idx]); - $sizeitem = $this->strip_value($items[$idx]); - $sizetarget = $this->strip_value($sizetargets[$idx]); - - $this->form['tests'][$i]['test'] = 'size'; - $this->form['tests'][$i]['type'] = $sizeop; - $this->form['tests'][$i]['arg'] = $sizetarget.$sizeitem; - - if ($sizetarget == '') - $this->errors['tests'][$i]['sizetarget'] = $this->gettext('cannotbeempty'); - else if (!preg_match('/^[0-9]+(K|M|G)*$/i', $sizetarget)) - $this->errors['tests'][$i]['sizetarget'] = $this->gettext('forbiddenchars'); - break; - case '...': - $cust_header = $headers = $this->strip_value($cust_headers[$idx]); - - if (preg_match('/^not/', $op)) - $this->form['tests'][$i]['not'] = true; - $type = preg_replace('/^not/', '', $op); - - if ($cust_header == '') - $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); - else { - $headers = preg_split('/[\s,]+/', $cust_header, -1, PREG_SPLIT_NO_EMPTY); - - if (!count($headers)) - $this->errors['tests'][$i]['header'] = $this->gettext('cannotbeempty'); - else { - foreach ($headers as $hr) - if (!preg_match('/^[a-z0-9-]+$/i', $hr)) - $this->errors['tests'][$i]['header'] = $this->gettext('forbiddenchars'); - } - } - if (empty($this->errors['tests'][$i]['header'])) - $cust_header = (is_array($headers) && count($headers) == 1) ? $headers[0] : $headers; + if ($header != 'size' && $comparator) { + if (preg_match('/^(value|count)/', $this->form['tests'][$i]['type'])) + $comparator = 'i;ascii-numeric'; + + $this->form['tests'][$i]['comparator'] = $comparator; + } - if ($type == 'exists') { - $this->form['tests'][$i]['test'] = 'exists'; - $this->form['tests'][$i]['arg'] = $cust_header; - } - else { - $this->form['tests'][$i]['test'] = 'header'; - $this->form['tests'][$i]['type'] = $type; - $this->form['tests'][$i]['arg1'] = $cust_header; - $this->form['tests'][$i]['arg2'] = $target; - - if ($target == '') - $this->errors['tests'][$i]['target'] = $this->gettext('cannotbeempty'); - else if (preg_match('/^(value|count)-/', $type) && !preg_match('/[0-9]+/', $target)) - $this->errors['tests'][$i]['target'] = $this->gettext('forbiddenchars'); - } - break; - } $i++; } } @@ -583,7 +853,7 @@ class managesieve extends rcube_plugin $i++; } - if (!$this->errors) { + if (!$this->errors && !$error) { // zapis skryptu if (!isset($this->script[$fid])) { $fid = $this->sieve->script->add_rule($this->form); @@ -592,15 +862,23 @@ class managesieve extends rcube_plugin $fid = $this->sieve->script->update_rule($fid, $this->form); if ($fid !== false) - $save = $this->sieve->save(); + $save = $this->save_script(); if ($save && $fid !== false) { $this->rc->output->show_message('managesieve.filtersaved', 'confirmation'); - $this->rc->output->add_script( - sprintf("rcmail.managesieve_updatelist('%s', '%s', %d, %d);", - isset($new) ? 'add' : 'update', Q($this->form['name']), - $fid, $this->form['disabled']), - 'foot'); + if ($this->rc->task != 'mail') { + $this->rc->output->command('parent.managesieve_updatelist', + isset($new) ? 'add' : 'update', + array( + 'name' => Q($this->form['name']), + 'id' => $fid, + 'disabled' => $this->form['disabled'] + )); + } + else { + $this->rc->output->command('managesieve_dialog_close'); + $this->rc->output->send('iframe'); + } } else { $this->rc->output->show_message('managesieve.filtersaveerror', 'error'); @@ -636,14 +914,9 @@ class managesieve extends rcube_plugin $attrib['id'] = 'rcmfilterslist'; // define list of cols to be displayed - $a_show_cols = array('managesieve.filtername'); + $a_show_cols = array('name'); - foreach($this->script as $idx => $filter) - $result[] = array( - 'managesieve.filtername' => $filter['name'], - 'id' => $idx, - 'class' => $filter['disabled'] ? 'disabled' : '', - ); + $result = $this->list_rules(); // create XHTML table $out = rcube_table_output($attrib, $result, $a_show_cols, 'id'); @@ -659,35 +932,56 @@ class managesieve extends rcube_plugin } // return the filters list as <SELECT> - function filtersets_list($attrib) + function filtersets_list($attrib, $no_env = false) { // add id to message list table if not specified if (!strlen($attrib['id'])) $attrib['id'] = 'rcmfiltersetslist'; - $list = $this->sieve->get_scripts(); - $active = $this->sieve->get_active(); - - $select = new html_select(array('name' => '_set', 'id' => $attrib['id'], - 'onchange' => 'rcmail.managesieve_set()')); + $list = $this->list_scripts(); if ($list) { asort($list, SORT_LOCALE_STRING); + } + + if (!empty($attrib['type']) && $attrib['type'] == 'list') { + // define list of cols to be displayed + $a_show_cols = array('name'); + + if ($list) { + foreach ($list as $idx => $set) { + $scripts['S'.$idx] = $set; + $result[] = array( + 'name' => Q($set), + 'id' => 'S'.$idx, + 'class' => !in_array($set, $this->active) ? 'disabled' : '', + ); + } + } + + // create XHTML table + $out = rcube_table_output($attrib, $result, $a_show_cols, 'id'); - foreach ($list as $set) - $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); + $this->rc->output->set_env('filtersets', $scripts); + $this->rc->output->include_script('list.js'); } + else { + $select = new html_select(array('name' => '_set', 'id' => $attrib['id'], + 'onchange' => $this->rc->task != 'mail' ? 'rcmail.managesieve_set()' : '')); + + if ($list) { + foreach ($list as $set) + $select->add($set, $set); + } - $out = $select->show($this->sieve->current); + $out = $select->show($this->sieve->current); + } // set client env - $this->rc->output->add_gui_object('filtersetslist', $attrib['id']); - $this->rc->output->add_label( - 'managesieve.setdeleteconfirm', - 'managesieve.active', - 'managesieve.filtersetact', - 'managesieve.filtersetdeact' - ); + if (!$no_env) { + $this->rc->output->add_gui_object('filtersetslist', $attrib['id']); + $this->rc->output->add_label('managesieve.setdeleteconfirm'); + } return $out; } @@ -737,16 +1031,18 @@ class managesieve extends rcube_plugin $out .= sprintf('<label for="%s">%s</label> ', 'from_none', Q($this->gettext('none'))); // filters set list - $list = $this->sieve->get_scripts(); - $active = $this->sieve->get_active(); - + $list = $this->list_scripts(); $select = new html_select(array('name' => '_copy', 'id' => '_copy')); if (is_array($list)) { asort($list, SORT_LOCALE_STRING); - foreach ($list as $set) - $select->add($set . ($set == $active ? ' ('.$this->gettext('active').')' : ''), $set); + if (!$copy) + $copy = $_SESSION['managesieve_current']; + + foreach ($list as $set) { + $select->add($set, $set); + } $out .= '<br /><input type="radio" id="from_set" name="_from" value="set"' .($selected=='set' ? ' checked="checked"' : '').'></input>'; @@ -756,7 +1052,7 @@ class managesieve extends rcube_plugin // script upload box $upload = new html_inputfield(array('name' => '_file', 'id' => '_file', 'size' => 30, - 'type' => 'file', 'class' => ($this->errors['name'] ? 'error' : ''))); + 'type' => 'file', 'class' => ($this->errors['file'] ? 'error' : ''))); $out .= '<br /><input type="radio" id="from_file" name="_from" value="file"' .($selected=='file' ? ' checked="checked"' : '').'></input>'; @@ -766,6 +1062,13 @@ class managesieve extends rcube_plugin $this->rc->output->add_gui_object('sieveform', 'filtersetform'); + if ($this->errors['name']) + $this->add_tip('_name', $this->errors['name'], true); + if ($this->errors['file']) + $this->add_tip('_file', $this->errors['file'], true); + + $this->print_tips(); + return $out; } @@ -803,10 +1106,17 @@ class managesieve extends rcube_plugin else $input_name = $input_name->show(); - $out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s<br /><br />\n", + $out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s\n", $field_id, Q($this->gettext('filtername')), $input_name); - $out .= '<fieldset><legend>' . Q($this->gettext('messagesrules')) . "</legend>\n"; + // filter set selector + if ($this->rc->task == 'mail') { + $out .= sprintf("\n <label for=\"%s\"><b>%s:</b></label> %s\n", + $field_id, Q($this->gettext('filterset')), + $this->filtersets_list(array('id' => 'sievescriptname'), true)); + } + + $out .= '<br /><br /><fieldset><legend>' . Q($this->gettext('messagesrules')) . "</legend>\n"; // any, allof, anyof radio buttons $field_id = '_allof'; @@ -882,50 +1192,60 @@ class managesieve extends rcube_plugin $rule = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id]; $rows_num = isset($this->form) ? sizeof($this->form['tests']) : sizeof($this->script[$fid]['tests']); - $out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : ''; - - $out .= '<table><tr><td class="rowactions">'; - // headers select $select_header = new html_select(array('name' => "_header[]", 'id' => 'header'.$id, 'onchange' => 'rule_header_select(' .$id .')')); foreach($this->headers as $name => $val) $select_header->add(Q($this->gettext($name)), Q($val)); + if (in_array('body', $this->exts)) + $select_header->add(Q($this->gettext('body')), 'body'); $select_header->add(Q($this->gettext('size')), 'size'); $select_header->add(Q($this->gettext('...')), '...'); // TODO: list arguments + $aout = ''; - if ((isset($rule['test']) && $rule['test'] == 'header') - && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers)) - $out .= $select_header->show($rule['arg1']); + if ((isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) + && !is_array($rule['arg1']) && in_array($rule['arg1'], $this->headers) + ) { + $aout .= $select_header->show($rule['arg1']); + } else if ((isset($rule['test']) && $rule['test'] == 'exists') - && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers)) - $out .= $select_header->show($rule['arg']); + && !is_array($rule['arg']) && in_array($rule['arg'], $this->headers) + ) { + $aout .= $select_header->show($rule['arg']); + } else if (isset($rule['test']) && $rule['test'] == 'size') - $out .= $select_header->show('size'); + $aout .= $select_header->show('size'); + else if (isset($rule['test']) && $rule['test'] == 'body') + $aout .= $select_header->show('body'); else if (isset($rule['test']) && $rule['test'] != 'true') - $out .= $select_header->show('...'); + $aout .= $select_header->show('...'); else - $out .= $select_header->show(); - - $out .= '</td><td class="rowtargets">'; + $aout .= $select_header->show(); - if ((isset($rule['test']) && $rule['test'] == 'header') - && (is_array($rule['arg1']) || !in_array($rule['arg1'], $this->headers))) - $custom = is_array($rule['arg1']) ? implode(', ', $rule['arg1']) : $rule['arg1']; - else if ((isset($rule['test']) && $rule['test'] == 'exists') - && (is_array($rule['arg']) || !in_array($rule['arg'], $this->headers))) - $custom = is_array($rule['arg']) ? implode(', ', $rule['arg']) : $rule['arg']; + if (isset($rule['test']) && in_array($rule['test'], array('header', 'address', 'envelope'))) { + if (is_array($rule['arg1'])) + $custom = implode(', ', $rule['arg1']); + else if (!in_array($rule['arg1'], $this->headers)) + $custom = $rule['arg1']; + } + else if (isset($rule['test']) && $rule['test'] == 'exists') { + if (is_array($rule['arg'])) + $custom = implode(', ', $rule['arg']); + else if (!in_array($rule['arg'], $this->headers)) + $custom = $rule['arg']; + } - $out .= '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> + $tout = '<div id="custom_header' .$id. '" style="display:' .(isset($custom) ? 'inline' : 'none'). '"> <input type="text" name="_custom_header[]" id="custom_header_i'.$id.'" ' . $this->error_class($id, 'test', 'header', 'custom_header_i') - .' value="' .Q($custom). '" size="20" /> </div>' . "\n"; + .' value="' .Q($custom). '" size="15" /> </div>' . "\n"; // matching type select (operator) $select_op = new html_select(array('name' => "_rule_op[]", 'id' => 'rule_op'.$id, 'style' => 'display:' .($rule['test']!='size' ? 'inline' : 'none'), + 'class' => 'operator_selector', 'onchange' => 'rule_op_select('.$id.')')); $select_op->add(Q($this->gettext('filtercontains')), 'contains'); $select_op->add(Q($this->gettext('filternotcontains')), 'notcontains'); @@ -935,54 +1255,64 @@ class managesieve extends rcube_plugin $select_op->add(Q($this->gettext('filternotexists')), 'notexists'); $select_op->add(Q($this->gettext('filtermatches')), 'matches'); $select_op->add(Q($this->gettext('filternotmatches')), 'notmatches'); - if (in_array('regex', $this->exts)) { + if (in_array('regex', $this->exts)) { $select_op->add(Q($this->gettext('filterregex')), 'regex'); $select_op->add(Q($this->gettext('filternotregex')), 'notregex'); } - if (in_array('relational', $this->exts)) { - $select_op->add(Q($this->gettext('countisgreaterthan')), 'count-gt'); - $select_op->add(Q($this->gettext('countisgreaterthanequal')), 'count-ge'); - $select_op->add(Q($this->gettext('countislessthan')), 'count-lt'); - $select_op->add(Q($this->gettext('countislessthanequal')), 'count-le'); - $select_op->add(Q($this->gettext('countequals')), 'count-eq'); - $select_op->add(Q($this->gettext('countnotequals')), 'count-ne'); - $select_op->add(Q($this->gettext('valueisgreaterthan')), 'value-gt'); - $select_op->add(Q($this->gettext('valueisgreaterthanequal')), 'value-ge'); - $select_op->add(Q($this->gettext('valueislessthan')), 'value-lt'); - $select_op->add(Q($this->gettext('valueislessthanequal')), 'value-le'); - $select_op->add(Q($this->gettext('valueequals')), 'value-eq'); - $select_op->add(Q($this->gettext('valuenotequals')), 'value-ne'); - } + if (in_array('relational', $this->exts)) { + $select_op->add(Q($this->gettext('countisgreaterthan')), 'count-gt'); + $select_op->add(Q($this->gettext('countisgreaterthanequal')), 'count-ge'); + $select_op->add(Q($this->gettext('countislessthan')), 'count-lt'); + $select_op->add(Q($this->gettext('countislessthanequal')), 'count-le'); + $select_op->add(Q($this->gettext('countequals')), 'count-eq'); + $select_op->add(Q($this->gettext('countnotequals')), 'count-ne'); + $select_op->add(Q($this->gettext('valueisgreaterthan')), 'value-gt'); + $select_op->add(Q($this->gettext('valueisgreaterthanequal')), 'value-ge'); + $select_op->add(Q($this->gettext('valueislessthan')), 'value-lt'); + $select_op->add(Q($this->gettext('valueislessthanequal')), 'value-le'); + $select_op->add(Q($this->gettext('valueequals')), 'value-eq'); + $select_op->add(Q($this->gettext('valuenotequals')), 'value-ne'); + } // target input (TODO: lists) - if ($rule['test'] == 'header') { - $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['type']); + if (in_array($rule['test'], array('header', 'address', 'envelope'))) { + $test = ($rule['not'] ? 'not' : '').($rule['type'] ? $rule['type'] : 'is'); $target = $rule['arg2']; } + else if ($rule['test'] == 'body') { + $test = ($rule['not'] ? 'not' : '').($rule['type'] ? $rule['type'] : 'is'); + $target = $rule['arg']; + } else if ($rule['test'] == 'size') { - $out .= $select_op->show(); - if (preg_match('/^([0-9]+)(K|M|G)*$/', $rule['arg'], $matches)) { + $test = ''; + $target = ''; + if (preg_match('/^([0-9]+)(K|M|G)?$/', $rule['arg'], $matches)) { $sizetarget = $matches[1]; $sizeitem = $matches[2]; } + else { + $sizetarget = $rule['arg']; + $sizeitem = $rule['item']; + } } else { - $out .= $select_op->show(($rule['not'] ? 'not' : '').$rule['test']); - $target = ''; + $test = ($rule['not'] ? 'not' : '').$rule['test']; + $target = ''; } - $out .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '" + $tout .= $select_op->show($test); + $tout .= '<input type="text" name="_rule_target[]" id="rule_target' .$id. '" value="' .Q($target). '" size="20" ' . $this->error_class($id, 'test', 'target', 'rule_target') . ' style="display:' . ($rule['test']!='size' && $rule['test'] != 'exists' ? 'inline' : 'none') . '" />'."\n"; $select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id)); - $select_size_op->add(Q($this->gettext('filterunder')), 'under'); $select_size_op->add(Q($this->gettext('filterover')), 'over'); + $select_size_op->add(Q($this->gettext('filterunder')), 'under'); - $out .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">'; - $out .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); - $out .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" ' + $tout .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">'; + $tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : ''); + $tout .= '<input type="text" name="_rule_size_target[]" id="rule_size_i'.$id.'" value="'.$sizetarget.'" size="10" ' . $this->error_class($id, 'test', 'sizetarget', 'rule_size_i') .' /> <input type="radio" name="_rule_size_item['.$id.']" value=""' . (!$sizeitem ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('B').' @@ -992,17 +1322,92 @@ class managesieve extends rcube_plugin . ($sizeitem=='M' ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('MB').' <input type="radio" name="_rule_size_item['.$id.']" value="G"' . ($sizeitem=='G' ? ' checked="checked"' : '') .' class="radio" />'.rcube_label('GB'); - $out .= '</div>'; + $tout .= '</div>'; + + // Advanced modifiers (address, envelope) + $select_mod = new html_select(array('name' => "_rule_mod[]", 'id' => 'rule_mod_op'.$id, + 'onchange' => 'rule_mod_select(' .$id .')')); + $select_mod->add(Q($this->gettext('none')), ''); + $select_mod->add(Q($this->gettext('address')), 'address'); + if (in_array('envelope', $this->exts)) + $select_mod->add(Q($this->gettext('envelope')), 'envelope'); + + $select_type = new html_select(array('name' => "_rule_mod_type[]", 'id' => 'rule_mod_type'.$id)); + $select_type->add(Q($this->gettext('allparts')), 'all'); + $select_type->add(Q($this->gettext('domain')), 'domain'); + $select_type->add(Q($this->gettext('localpart')), 'localpart'); + if (in_array('subaddress', $this->exts)) { + $select_type->add(Q($this->gettext('user')), 'user'); + $select_type->add(Q($this->gettext('detail')), 'detail'); + } + + $need_mod = $rule['test'] != 'size' && $rule['test'] != 'body'; + $mout = '<div id="rule_mod' .$id. '" class="adv" style="display:' . ($need_mod ? 'block' : 'none') .'">'; + $mout .= ' <span>'; + $mout .= Q($this->gettext('modifier')) . ' '; + $mout .= $select_mod->show($rule['test']); + $mout .= '</span>'; + $mout .= ' <span id="rule_mod_type' . $id . '"'; + $mout .= ' style="display:' . (in_array($rule['test'], array('address', 'envelope')) ? 'inline' : 'none') .'">'; + $mout .= Q($this->gettext('modtype')) . ' '; + $mout .= $select_type->show($rule['part']); + $mout .= '</span>'; + $mout .= '</div>'; + + // Advanced modifiers (body transformations) + $select_mod = new html_select(array('name' => "_rule_trans[]", 'id' => 'rule_trans_op'.$id, + 'onchange' => 'rule_trans_select(' .$id .')')); + $select_mod->add(Q($this->gettext('text')), 'text'); + $select_mod->add(Q($this->gettext('undecoded')), 'raw'); + $select_mod->add(Q($this->gettext('contenttype')), 'content'); + + $mout .= '<div id="rule_trans' .$id. '" class="adv" style="display:' . ($rule['test'] == 'body' ? 'block' : 'none') .'">'; + $mout .= ' <span>'; + $mout .= Q($this->gettext('modifier')) . ' '; + $mout .= $select_mod->show($rule['part']); + $mout .= '<input type="text" name="_rule_trans_type[]" id="rule_trans_type'.$id + . '" value="'.(is_array($rule['content']) ? implode(',', $rule['content']) : $rule['content']) + .'" size="20" style="display:' . ($rule['part'] == 'content' ? 'inline' : 'none') .'"' + . $this->error_class($id, 'test', 'part', 'rule_trans_type') .' />'; + $mout .= '</span>'; + $mout .= '</div>'; + + // Advanced modifiers (body transformations) + $select_comp = new html_select(array('name' => "_rule_comp[]", 'id' => 'rule_comp_op'.$id)); + $select_comp->add(Q($this->gettext('default')), ''); + $select_comp->add(Q($this->gettext('octet')), 'i;octet'); + $select_comp->add(Q($this->gettext('asciicasemap')), 'i;ascii-casemap'); + if (in_array('comparator-i;ascii-numeric', $this->exts)) { + $select_comp->add(Q($this->gettext('asciinumeric')), 'i;ascii-numeric'); + } + + $mout .= '<div id="rule_comp' .$id. '" class="adv" style="display:' . ($rule['test'] != 'size' ? 'block' : 'none') .'">'; + $mout .= ' <span>'; + $mout .= Q($this->gettext('comparator')) . ' '; + $mout .= $select_comp->show($rule['comparator']); + $mout .= '</span>'; + $mout .= '</div>'; + + // Build output table + $out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : ''; + $out .= '<table><tr>'; + $out .= '<td class="advbutton">'; + $out .= '<a href="#" id="ruleadv' . $id .'" title="'. Q($this->gettext('advancedopts')). '" + onclick="rule_adv_switch(' . $id .', this)" class="show"> </a>'; + $out .= '</td>'; + $out .= '<td class="rowactions">' . $aout . '</td>'; + $out .= '<td class="rowtargets">' . $tout . "\n"; + $out .= '<div id="rule_advanced' .$id. '" style="display:none">' . $mout . '</div>'; $out .= '</td>'; // add/del buttons $out .= '<td class="rowbuttons">'; - $out .= '<input type="button" id="ruleadd' . $id .'" value="'. Q($this->gettext('add')). '" - onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button" /> '; - $out .= '<input type="button" id="ruledel' . $id .'" value="'. Q($this->gettext('del')). '" - onclick="rcmail.managesieve_ruledel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"' - . ($rows_num<2 ? ' disabled="disabled"' : '') .' />'; - $out .= '</td></tr></table>'; + $out .= '<a href="#" id="ruleadd' . $id .'" title="'. Q($this->gettext('add')). '" + onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button add"></a>'; + $out .= '<a href="#" id="ruledel' . $id .'" title="'. Q($this->gettext('del')). '" + onclick="rcmail.managesieve_ruledel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>'; + $out .= '</td>'; + $out .= '</tr></table>'; $out .= $div ? "</div>\n" : ''; @@ -1019,7 +1424,7 @@ class managesieve extends rcube_plugin $out .= '<table><tr><td class="rowactions">'; // action select - $select_action = new html_select(array('name' => "_action_type[]", 'id' => 'action_type'.$id, + $select_action = new html_select(array('name' => "_action_type[$id]", 'id' => 'action_type'.$id, 'onchange' => 'action_type_select(' .$id .')')); if (in_array('fileinto', $this->exts)) $select_action->add(Q($this->gettext('messagemoveto')), 'fileinto'); @@ -1053,12 +1458,12 @@ class managesieve extends rcube_plugin // actions target inputs $out .= '<td class="rowtargets">'; // shared targets - $out .= '<input type="text" name="_action_target[]" id="action_target' .$id. '" ' - .'value="' .($action['type']=='redirect' ? Q($action['target'], 'strict', false) : ''). '" size="40" ' + $out .= '<input type="text" name="_action_target['.$id.']" id="action_target' .$id. '" ' + .'value="' .($action['type']=='redirect' ? Q($action['target'], 'strict', false) : ''). '" size="35" ' .'style="display:' .($action['type']=='redirect' ? 'inline' : 'none') .'" ' . $this->error_class($id, 'action', 'target', 'action_target') .' />'; - $out .= '<textarea name="_action_target_area[]" id="action_target_area' .$id. '" ' - .'rows="3" cols="40" '. $this->error_class($id, 'action', 'targetarea', 'action_target_area') + $out .= '<textarea name="_action_target_area['.$id.']" id="action_target_area' .$id. '" ' + .'rows="3" cols="35" '. $this->error_class($id, 'action', 'targetarea', 'action_target_area') .'style="display:' .(in_array($action['type'], array('reject', 'ereject')) ? 'inline' : 'none') .'">' . (in_array($action['type'], array('reject', 'ereject')) ? Q($action['target'], 'strict', false) : '') . "</textarea>\n"; @@ -1066,19 +1471,19 @@ class managesieve extends rcube_plugin // vacation $out .= '<div id="action_vacation' .$id.'" style="display:' .($action['type']=='vacation' ? 'inline' : 'none') .'">'; $out .= '<span class="label">'. Q($this->gettext('vacationreason')) .'</span><br />' - .'<textarea name="_action_reason[]" id="action_reason' .$id. '" ' - .'rows="3" cols="45" '. $this->error_class($id, 'action', 'reason', 'action_reason') . '>' + .'<textarea name="_action_reason['.$id.']" id="action_reason' .$id. '" ' + .'rows="3" cols="35" '. $this->error_class($id, 'action', 'reason', 'action_reason') . '>' . Q($action['reason'], 'strict', false) . "</textarea>\n"; $out .= '<br /><span class="label">' .Q($this->gettext('vacationsubject')) . '</span><br />' - .'<input type="text" name="_action_subject[]" id="action_subject'.$id.'" ' - .'value="' . (is_array($action['subject']) ? Q(implode(', ', $action['subject']), 'strict', false) : $action['subject']) . '" size="50" ' + .'<input type="text" name="_action_subject['.$id.']" id="action_subject'.$id.'" ' + .'value="' . (is_array($action['subject']) ? Q(implode(', ', $action['subject']), 'strict', false) : $action['subject']) . '" size="35" ' . $this->error_class($id, 'action', 'subject', 'action_subject') .' />'; $out .= '<br /><span class="label">' .Q($this->gettext('vacationaddresses')) . '</span><br />' - .'<input type="text" name="_action_addresses[]" id="action_addr'.$id.'" ' - .'value="' . (is_array($action['addresses']) ? Q(implode(', ', $action['addresses']), 'strict', false) : $action['addresses']) . '" size="50" ' + .'<input type="text" name="_action_addresses['.$id.']" id="action_addr'.$id.'" ' + .'value="' . (is_array($action['addresses']) ? Q(implode(', ', $action['addresses']), 'strict', false) : $action['addresses']) . '" size="35" ' . $this->error_class($id, 'action', 'addresses', 'action_addr') .' />'; $out .= '<br /><span class="label">' . Q($this->gettext('vacationdays')) . '</span><br />' - .'<input type="text" name="_action_days[]" id="action_days'.$id.'" ' + .'<input type="text" name="_action_days['.$id.']" id="action_days'.$id.'" ' .'value="' .Q($action['days'], 'strict', false) . '" size="2" ' . $this->error_class($id, 'action', 'days', 'action_days') .' />'; $out .= '</div>'; @@ -1111,22 +1516,21 @@ class managesieve extends rcube_plugin $this->rc->imap_connect(); $select = rcmail_mailbox_select(array( - 'realnames' => false, - 'maxlength' => 100, - 'id' => 'action_mailbox' . $id, - 'name' => '_action_mailbox[]', - 'style' => 'display:'.(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none') - )); + 'realnames' => false, + 'maxlength' => 100, + 'id' => 'action_mailbox' . $id, + 'name' => "_action_mailbox[$id]", + 'style' => 'display:'.(!isset($action) || $action['type']=='fileinto' ? 'inline' : 'none') + )); $out .= $select->show($mailbox); $out .= '</td>'; // add/del buttons $out .= '<td class="rowbuttons">'; - $out .= '<input type="button" id="actionadd' . $id .'" value="'. Q($this->gettext('add')). '" - onclick="rcmail.managesieve_actionadd(' . $id .')" class="button" /> '; - $out .= '<input type="button" id="actiondel' . $id .'" value="'. Q($this->gettext('del')). '" - onclick="rcmail.managesieve_actiondel(' . $id .')" class="button' . ($rows_num<2 ? ' disabled' : '') .'"' - . ($rows_num<2 ? ' disabled="disabled"' : '') .' />'; + $out .= '<a href="#" id="actionadd' . $id .'" title="'. Q($this->gettext('add')). '" + onclick="rcmail.managesieve_actionadd(' . $id .')" class="button add"></a>'; + $out .= '<a href="#" id="actiondel' . $id .'" title="'. Q($this->gettext('del')). '" + onclick="rcmail.managesieve_actiondel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>'; $out .= '</td>'; $out .= '</tr></table>'; @@ -1208,4 +1612,267 @@ class managesieve extends rcube_plugin return $mailbox; } + + /** + * List sieve scripts + * + * @return array Scripts list + */ + public function list_scripts() + { + if ($this->list !== null) { + return $this->list; + } + + $this->list = $this->sieve->get_scripts(); + + // Handle active script(s) and list of scripts according to Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + + // Skip protected names + foreach ((array)$this->list as $idx => $name) { + $_name = strtoupper($name); + if ($_name == 'MASTER') + $master_script = $name; + else if ($_name == 'MANAGEMENT') + $management_script = $name; + else if($_name == 'USER') + $user_script = $name; + else + continue; + + unset($this->list[$idx]); + } + + // get active script(s), read USER script + if ($user_script) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $filename_regex = '/'.preg_quote($extension, '/').'$/'; + $_SESSION['managesieve_user_script'] = $user_script; + + $this->sieve->load($user_script); + + foreach ($this->sieve->script->as_array() as $rules) { + foreach ($rules['actions'] as $action) { + if ($action['type'] == 'include' && empty($action['global'])) { + $name = preg_replace($filename_regex, '', $action['target']); + $this->active[] = $name; + } + } + } + } + // create USER script if it doesn't exist + else { + $content = "# USER Management Script\n" + ."#\n" + ."# This script includes the various active sieve scripts\n" + ."# it is AUTOMATICALLY GENERATED. DO NOT EDIT MANUALLY!\n" + ."#\n" + ."# For more information, see http://wiki.kolab.org/KEP:14#USER\n" + ."#\n"; + if ($this->sieve->save_script('USER', $content)) { + $_SESSION['managesieve_user_script'] = 'USER'; + if (empty($this->master_file)) + $this->sieve->activate('USER'); + } + } + } + else if (!empty($this->list)) { + // Get active script name + if ($active = $this->sieve->get_active()) { + $this->active = array($active); + } + } + + return $this->list; + } + + /** + * Removes sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function remove_script($name) + { + $result = $this->sieve->remove($name); + + // Kolab's KEP:14 + if ($result && $this->rc->config->get('managesieve_kolab_master')) { + $this->deactivate_script($name); + } + + return $result; + } + + /** + * Activates sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function activate_script($name) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $user_script = $_SESSION['managesieve_user_script']; + + // if the script is not active... + if ($user_script && ($key = array_search($name, $this->active)) === false) { + // ...rewrite USER file adding appropriate include command + if ($this->sieve->load($user_script)) { + $script = $this->sieve->script->as_array(); + $list = array(); + $regexp = '/' . preg_quote($extension, '/') . '$/'; + + // Create new include entry + $rule = array( + 'actions' => array( + 0 => array( + 'target' => $name.$extension, + 'type' => 'include', + 'personal' => true, + ))); + + // get all active scripts for sorting + foreach ($script as $rid => $rules) { + foreach ($rules['actions'] as $aid => $action) { + if ($action['type'] == 'include' && empty($action['global'])) { + $target = $extension ? preg_replace($regexp, '', $action['target']) : $action['target']; + $list[] = $target; + } + } + } + $list[] = $name; + + // Sort and find current script position + asort($list, SORT_LOCALE_STRING); + $list = array_values($list); + $index = array_search($name, $list); + + // add rule at the end of the script + if ($index === false || $index == count($list)-1) { + $this->sieve->script->add_rule($rule); + } + // add rule at index position + else { + $script2 = array(); + foreach ($script as $rid => $rules) { + if ($rid == $index) { + $script2[] = $rule; + } + $script2[] = $rules; + } + $this->sieve->script->content = $script2; + } + + $result = $this->sieve->save(); + if ($result) { + $this->active[] = $name; + } + } + } + } + else { + $result = $this->sieve->activate($name); + if ($result) + $this->active = array($name); + } + + return $result; + } + + /** + * Deactivates sieve script + * + * @param string $name Script name + * + * @return bool True on success, False on failure + */ + public function deactivate_script($name) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $extension = $this->rc->config->get('managesieve_filename_extension', '.sieve'); + $user_script = $_SESSION['managesieve_user_script']; + + // if the script is active... + if ($user_script && ($key = array_search($name, $this->active)) !== false) { + // ...rewrite USER file removing appropriate include command + if ($this->sieve->load($user_script)) { + $script = $this->sieve->script->as_array(); + $name = $name.$extension; + + foreach ($script as $rid => $rules) { + foreach ($rules['actions'] as $aid => $action) { + if ($action['type'] == 'include' && empty($action['global']) + && $action['target'] == $name + ) { + break 2; + } + } + } + + // Entry found + if ($rid < count($script)) { + $this->sieve->script->delete_rule($rid); + $result = $this->sieve->save(); + if ($result) { + unset($this->active[$key]); + } + } + } + } + } + else { + $result = $this->sieve->deactivate(); + if ($result) + $this->active = array(); + } + + return $result; + } + + /** + * Saves current script (adding some variables) + */ + public function save_script($name = null) + { + // Kolab's KEP:14 + if ($this->rc->config->get('managesieve_kolab_master')) { + $this->sieve->script->set_var('EDITOR', self::PROGNAME); + $this->sieve->script->set_var('EDITOR_VERSION', self::VERSION); + } + + return $this->sieve->save($name); + } + + /** + * Returns list of rules from the current script + * + * @return array List of rules + */ + public function list_rules() + { + $result = array(); + $i = 1; + + foreach ($this->script as $idx => $filter) { + if ($filter['type'] != 'if') { + continue; + } + $fname = $filter['name'] ? $filter['name'] : "#$i"; + $result[] = array( + 'id' => $idx, + 'name' => Q($fname), + 'class' => $filter['disabled'] ? 'disabled' : '', + ); + $i++; + } + + return $result; + } } diff --git a/plugins/managesieve/package.xml b/plugins/managesieve/package.xml new file mode 100644 index 0000000..56655d2 --- /dev/null +++ b/plugins/managesieve/package.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.0 + http://pear.php.net/dtd/package-2.0.xsd"> + <name>managesieve</name> + <channel>pear.roundcube.net</channel> + <summary>Sieve filters manager for Roundcube</summary> + <description> + Adds a possibility to manage Sieve scripts (incoming mail filters). + It's clickable interface which operates on text scripts and communicates + with server using managesieve protocol. Adds Filters tab in Settings. + </description> + <lead> + <name>Aleksander Machniak</name> + <user>alec</user> + <email>alec@alec.pl</email> + <active>yes</active> + </lead> + <date>2011-11-17</date> + <version> + <release>5.0</release> + <api>5.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes>-</notes> + <contents> + <dir baseinstalldir="/" name="/"> + <file name="managesieve.php" role="php"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="managesieve.js" role="data"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="localization/bg_BG.inc" role="data"></file> + <file name="localization/cs_CZ.inc" role="data"></file> + <file name="localization/de_CH.inc" role="data"></file> + <file name="localization/de_DE.inc" role="data"></file> + <file name="localization/el_GR.inc" role="data"></file> + <file name="localization/en_GB.inc" role="data"></file> + <file name="localization/en_US.inc" role="data"></file> + <file name="localization/es_AR.inc" role="data"></file> + <file name="localization/es_ES.inc" role="data"></file> + <file name="localization/et_EE.inc" role="data"></file> + <file name="localization/fi_FI.inc" role="data"></file> + <file name="localization/fr_FR.inc" role="data"></file> + <file name="localization/gl_ES.inc" role="data"></file> + <file name="localization/hr_HR.inc" role="data"></file> + <file name="localization/hu_HU.inc" role="data"></file> + <file name="localization/it_IT.inc" role="data"></file> + <file name="localization/ja_JP.inc" role="data"></file> + <file name="localization/lv_LV.inc" role="data"></file> + <file name="localization/nb_NO.inc" role="data"></file> + <file name="localization/nl_NL.inc" role="data"></file> + <file name="localization/pl_PL.inc" role="data"></file> + <file name="localization/pt_BR.inc" role="data"></file> + <file name="localization/pt_PT.inc" role="data"></file> + <file name="localization/ru_RU.inc" role="data"></file> + <file name="localization/sk_SK.inc" role="data"></file> + <file name="localization/sl_SI.inc" role="data"></file> + <file name="localization/sv_SE.inc" role="data"></file> + <file name="localization/uk_UA.inc" role="data"></file> + <file name="localization/zh_CN.inc" role="data"></file> + <file name="localization/zh_TW.inc" role="data"></file> + <file name="skins/default/managesieve.css" role="data"></file> + <file name="skins/default/managesieve_mail.css" role="data"></file> + <file name="skins/default/templates/filteredit.html" role="data"></file> + <file name="skins/default/templates/managesieve.html" role="data"></file> + <file name="skins/default/templates/setedit.html" role="data"></file> + <file name="skins/default/images/add.png" role="data"></file> + <file name="skins/default/images/del.png" role="data"></file> + <file name="skins/default/images/down_small.gif" role="data"></file> + <file name="skins/default/images/filter.png" role="data"></file> + <file name="skins/default/images/up_small.gif" role="data"></file> + <file name="managesieve.php" role="php"></file> + <file name="lib/rcube_sieve.php" role="php"></file> + <file name="lib/rcube_sieve_script.php" role="php"></file> + <file name="lib/Net/Sieve.php" role="php"></file> + <file name="config.inc.php.dist" role="data"></file> + </dir> + <!-- / --> + </contents> + <dependencies> + <required> + <php> + <min>5.2.1</min> + </php> + <pearinstaller> + <min>1.7.0</min> + </pearinstaller> + </required> + </dependencies> + <phprelease/> +</package> diff --git a/plugins/managesieve/skins/default/images/add.png b/plugins/managesieve/skins/default/images/add.png new file mode 100644 index 0000000000000000000000000000000000000000..97a6422fb0f0a685d6a2fa85053a2079f917cc22 GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^azHG?!2~2lPfAS&QjEnx?oJHr&dIz4aySb-B8wRq zxP?KOkzv*x37{Z*iKnkC`)w{BP7N+Lp}BcLp;ewPjv*GO-%c^)V^S1wwcmVi(uE6! z^5!jV7YdlamobSgFg(T@refx2I{8ffpFf@n$0W|I6lTzTdVS}$s6$(RExtczV#dmx zBN9c2E!iLJ)nB%1Ra0FDe`xU3iyOrxFY;M!yQp~Op16}uzoi(%xt)R6e>d{%z83Y| zO>^q;DM7)d?(z1P$-!64d{4iYluW+6?)Rp+^V$s(r;1*jta>D=zKC7W{@1*1Z;hC1 ZnRiTxG~zv1{|@MC22WQ%mvv4FO#o|<XIlUO literal 0 HcmV?d00001 diff --git a/plugins/managesieve/skins/default/images/del.png b/plugins/managesieve/skins/default/images/del.png new file mode 100644 index 0000000000000000000000000000000000000000..518905bc4b213d76ddf67d6fc3d36873707dcde0 GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^azHG?!2~2lPfAS&QjEnx?oJHr&dIz4aySb-B8wRq zxP?KOkzv*x37{Z*iKnkC`)w{BP7U+8s*CkNp-xX1#}JFtZ>QLD9Z=wDy}adm$;U9I zj`kJXvz^%MUnC^2EESlgX){T`-zBEU&_K<M;X+jXxzclrJl*oKmdcN`LJWdec2*jx zmZ^T(>L{n69ctpO?W|*Jcs?U<ap#hsUMp9<+xxz>cK@Qh>(_3r(koB>;<#8YzPOJ4 p*VT3M3oEU@?71Jz@tfldr$vI}q+XlVe}Rr-@O1TaS?83{1OOQoRmK1S literal 0 HcmV?d00001 diff --git a/plugins/managesieve/skins/default/images/down_small.gif b/plugins/managesieve/skins/default/images/down_small.gif new file mode 100644 index 0000000000000000000000000000000000000000..f865893f4711288f6ca37d9f2946a79e956f60bd GIT binary patch literal 106 zcmZ?wbhEHb<YZuDc+Ai6@ZrPHpFd}2W_EUV?%TKT=+UDK7A&}W^=fu@c5ZI&#EBED zs;Z73KfZSD+O)K^|Ns9h{$ycfVBlxaVE_V<84N7qA5K~_3+q|4s(9YK;LE#7W=e|4 KN|69T25SIYYb&(? literal 0 HcmV?d00001 diff --git a/plugins/managesieve/skins/default/images/filter.png b/plugins/managesieve/skins/default/images/filter.png new file mode 100644 index 0000000000000000000000000000000000000000..a79ba10831be7c20b07c28583848128865d60840 GIT binary patch literal 547 zcmV+;0^I$HP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz#Ysd#RCwB?QoT!pVGuuGKS3SLFLV%s zHVK6O02gy?4cZ!W3WTO0Xbpsx-oL;w#3dKC!Ohj7L5D<5(zHeJ`vdHLPp@xQ+E54g zKKDL%_q*TSbDG6sLH`jQKDk^D#}VrR>yF~vV%=8kXVy2xeqz06y$y%M9{}U=_`&6J zg}h!bS*=zPWiS}XY&HvfI2`&WlZg*@uh-jaHk*f?PUo0^_XWUwJ`Yu^RkBztWHcH@ zlF4LJX=*eYnog&r08p(~BfVZ9Qd`jJbhr?$a5a)7iAJLlaaEB7CN`UmFfWJ0L4iPk zDwWFT3>aNzkQ2MzPHwkbFhMI&kH<q!r&BNkAQ+U(Ws!qi37<?R6B!H!G0+ARP+lk8 zDiw=Gs@Ln+$WZ|x`FuXgAQz~D7QTa^wQM#^jYi{&V^5d&(rQqlP`K>(`_WdbMYGvV z1?hIXluD(j-EN<A%-N4U@caGh1wUzwkC#%Zln4fcf=x1+1RyBOtFbD;a@s3$$C|({ zXti2mR=ATlZX#D*J2X^>Zu0-e;EVj`U+%$LCx*x`1OMw^03LbzyXkaVU7C#mc(OGj l$K&xEPL6CEAmm+u0RS5U&=$coBHjQ1002ovPDHLkV1jFb>#qO+ literal 0 HcmV?d00001 diff --git a/plugins/managesieve/skins/default/images/up_small.gif b/plugins/managesieve/skins/default/images/up_small.gif new file mode 100644 index 0000000000000000000000000000000000000000..40deb891f9e1d45c083b719aa4ec07c50a00e462 GIT binary patch literal 106 zcmV-w0G0noNk%w1VF>^R0OJn;;o;%)^YdwGX^Dx6zP`T2#l@hYpw-pYYinz5ZEcZ} zk$QT1$H&L5t*vHeX8-^HA^8LW000jFEC2ui00{sF000CR@W~gZEyl{TP_w|`I0+#E M$~X#4rA-k4JB)xX9smFU literal 0 HcmV?d00001 diff --git a/plugins/managesieve/skins/default/managesieve.css b/plugins/managesieve/skins/default/managesieve.css index 675c5d0..60f6325 100644 --- a/plugins/managesieve/skins/default/managesieve.css +++ b/plugins/managesieve/skins/default/managesieve.css @@ -1,162 +1,98 @@ -/***** Roundcube|Filters styles *****/ - - -#filterslist +#filtersetslistbox { position: absolute; - left: 20px; - top: 120px; - bottom: 20px; + top: 0; + bottom: 0; + left: 0; + width: 195px; border: 1px solid #999999; - overflow: auto; + background-color: #F9F9F9; + overflow: hidden; /* css hack for IE */ - height: expression((parseInt(document.documentElement.clientHeight)-140)+'px'); + height: expression(parseInt(this.parentNode.offsetHeight)+'px'); } -#filters-table +#filtersscreen { - width: 100%; - table-layout: fixed; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 205px; /* css hack for IE */ - width: expression(document.getElementById('filterslist').clientWidth); + height: expression(parseInt(this.parentNode.offsetHeight)+'px'); } -#filters-table tbody td +#filterslistbox { - cursor: pointer; + position: absolute; + left: 0; + top: 0; + bottom: 0; + border: 1px solid #999999; + overflow: auto; + /* css hack for IE */ + height: expression(parseInt(this.parentNode.offsetHeight)+'px'); } -#filters-table tbody tr.disabled td +#filterslist, +#filtersetslist { - color: #999999; + width: 100%; + table-layout: fixed; } -#filtersbuttons +#filterslist tbody td, +#filtersetslist tbody td { - position: absolute; - left: 20px; - top: 85px; + cursor: default; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; } -#filtersetsbuttons +#filterslist tbody tr.disabled td, +#filtersetslist tbody tr.disabled td { - position: absolute; - left: 230px; - top: 85px; + color: #999999; } -#filtersbuttons a, -#filtersetsbuttons a +#filtersetslist tbody td { - display: block; - float: left; + font-weight: bold; } - -#filtersbuttons a.button, -#filtersbuttons a.buttonPas, -#filtersetsbuttons a.button, -#filtersetsbuttons a.buttonPas +/* +#filtersetslist tr.selected { - display: block; - float: left; - width: 32px; - height: 32px; - padding: 0; - margin-right: 3px; - overflow: hidden; - background: url(managesieve_toolbar.png) 0 0 no-repeat transparent; - opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */ + background-color: #929292; + border-bottom: 1px solid #898989; + color: #FFF; + font-weight: bold; } +*/ -#filtersbuttons a.buttonPas, -#filtersetsbuttons a.buttonPas +#filterslist tbody tr.filtermoveup td { - filter: alpha(opacity=35); - opacity: 0.35; -} - -#filtersbuttons a.add { - background-position: 0px 0px; -} - -#filtersbuttons a.addsel { - background-position: 0 -32px; -} - -#filtersbuttons a.del { - background-position: -32px 0px; -} - -#filtersbuttons a.delsel { - background-position: -32px -32px; -} - -#filtersbuttons a.up { - background-position: -64px 0px; -} - -#filtersbuttons a.upsel { - background-position: -64px -32px; -} - -#filtersbuttons a.down { - background-position: -96px 0px; -} - -#filtersbuttons a.downsel { - background-position: -96px -32px; -} - -#filtersetsbuttons a.setadd { - background-position: -128px 0px; -} - -#filtersetsbuttons a.setaddsel { - background-position: -128px -32px; -} - -#filtersetsbuttons a.setdel { - background-position: -160px 0px; -} - -#filtersetsbuttons a.setdelsel { - background-position: -160px -32px; -} - -#filtersetsbuttons a.setset { - background-position: -192px 0px; -} - -#filtersetsbuttons a.setsetsel { - background-position: -192px -32px; + border-top: 2px dotted #555; + padding-top: 0px; } -#filtersetsbuttons a.setget { - background-position: -224px 0px; -} - -#filtersetsbuttons a.setgetsel { - background-position: -224px -32px; -} - -#filtersetselect +#filterslist tbody tr.filtermovedown td { - position: absolute; - left: 375px; - top: 90px; + border-bottom: 2px dotted #555; + padding-bottom: 1px; } #filter-box { position: absolute; - top: 120px; - right: 20px; - bottom: 20px; + top: 0; + right: 0; + bottom: 0; border: 1px solid #999999; overflow: hidden; /* css hack for IE */ - width: expression((parseInt(document.documentElement.clientWidth)-40-parseInt(document.getElementById('filterslist').offsetWidth))+'px'); - height: expression((parseInt(document.documentElement.clientHeight)-140)+'px'); + width: expression((parseInt(this.parentNode.offsetWidth)-20-parseInt(document.getElementById('filterslistbox').offsetWidth))+'px'); + height: expression(parseInt(this.parentNode.offsetHeight)+'px'); } #filter-frame @@ -166,13 +102,15 @@ body.iframe { - min-width: 740px; - width: expression(Math.max(740, document.documentElement.clientWidth)+'px'); + min-width: 620px; + width: expression(Math.max(620, document.documentElement.clientWidth)+'px'); + background-color: #F2F2F2; } #filter-form { - min-width: 650px; + min-width: 550px; + width: expression(Math.max(550, document.documentElement.clientWidth)+'px'); white-space: nowrap; padding: 20px 10px 10px 10px; } @@ -208,7 +146,37 @@ div.rulerow:hover, div.actionrow:hover div.rulerow table, div.actionrow table { padding: 0px; - width: 100%; + min-width: 600px; + width: expression(Math.max(600, document.documentElement.clientWidth)+'px'); +} + +td +{ + vertical-align: top; +} + +td.advbutton +{ + width: 1%; +} + +td.advbutton a +{ + display: block; + padding-top: 14px; + height: 6px; + width: 12px; + text-decoration: none; +} + +td.advbutton a.show +{ + background: url(images/down_small.gif) center no-repeat; +} + +td.advbutton a.hide +{ + background: url(images/up_small.gif) center no-repeat; } td.rowbuttons @@ -222,13 +190,20 @@ td.rowactions { white-space: nowrap; width: 1%; + padding-top: 2px; } td.rowtargets { white-space: nowrap; width: 98%; - padding-left: 10px; + padding-left: 3px; + padding-top: 2px; +} + +td.rowtargets div.adv +{ + padding-top: 3px; } input.disabled, input.disabled:hover @@ -245,8 +220,15 @@ input.box, input.radio { border: 0; + margin-top: 0; } +select.operator_selector +{ + width: 200px; +} + +td.rowtargets span, span.label { color: #666666; @@ -259,7 +241,7 @@ span.label padding-top: 5px; width: 100%; } - + #footer .footerleft { padding-left: 2px; @@ -294,3 +276,47 @@ span.sieve.error { width: 200px; } + +a.button.add +{ + background: url(images/add.png) no-repeat; + width: 30px; + height: 20px; + margin-right: 4px; + display: inline-block; +} + +a.button.del +{ + background: url(images/del.png) no-repeat; + width: 30px; + height: 20px; + display: inline-block; +} + +a.button.disabled +{ + opacity: 0.35; + filter: alpha(opacity=35); + cursor: default; +} + +#filter-form select, +#filter-form input, +#filter-form textarea +{ + font-size: 11px; +} + +/* fixes for popup window */ + +body.iframe.mail +{ + margin: 0; + padding: 0; +} + +body.iframe.mail #filter-form +{ + padding: 10px 5px 5px 5px; +} diff --git a/plugins/managesieve/skins/default/managesieve_mail.css b/plugins/managesieve/skins/default/managesieve_mail.css new file mode 100644 index 0000000..7fefaed --- /dev/null +++ b/plugins/managesieve/skins/default/managesieve_mail.css @@ -0,0 +1,63 @@ +#messagemenu li a.filterlink { + background-image: url(images/filter.png); + background-position: 7px 0; +} + +#sievefilterform { + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: #F2F2F2; + border: 1px solid #999999; + padding: 0; + margin: 5px; +} + +#sievefilterform iframe { + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + min-height: 100%; /* Chrome 14 bug */ + background-color: #F2F2F2; + border: 0; + padding: 0; + margin: 0; +} + +#sievefilterform ul { + list-style: none; + padding: 0; + margin: 0; + margin-top: 5px; +} + +#sievefilterform fieldset { + margin: 5px; +} + +#sievefilterform ul li { + margin-bottom: 5px; + white-space: nowrap; +} + +#sievefilterform ul li input { + margin-right: 5px; +} + +#sievefilterform label { + font-weight: bold; +} + +#managesieve-tip +{ + width: 200px; + z-index: 100000; +} + +span.sieve.error +{ + color: red; +} diff --git a/plugins/managesieve/skins/default/managesieve_toolbar.png b/plugins/managesieve/skins/default/managesieve_toolbar.png deleted file mode 100644 index 473dbc8dfaaa8f3c9c68f95dfff3742a5c5a5f1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12093 zcmW-n1yoc|7r>X2?vRr1R!};mm+p{Q6lv-16r`oQySqDAT3A9@8tDdsg@xtg|DAVU z%sX@5+`0G8%$wi6ks4|WxLA}}0000Ns3@xi03f|Q0;Diry<BfhDtcdTNUmB6(tz4& z>cf}9t1rq5vViCRj{Kgoq?b3CPKt)E001`ee<u<kGn@S7CAu3>RStaxg&Knk|9dE1 z1^_?@0Lp&U@me{}@y<5Z&8W|FJ+G;$N~=68zAH}p=|<EDKtiUM0+4DDrpTdDQ_Gq0 z@$3i*!QeWpy_)kBXrmuLlHC8Cq=PeLA=3|#OVd#Wf6H<6Q7vn$JX$$(nZ8rtHtEsl z{Yi0nU3B2)z6M|QJr+OrNY!U6Nq2zQcfQGD2@@*yvwz@xDW3K~V-gS-!%6BKLr%DQ z`sUec1AKVj?T!5Y7DkVj9F^XK!=E>0@Y&<RqCc|0!NRLw-wjx#nTpUuZcX=}w+7J5 z!UFFt(jtNEK^j7nWp&*yO3jo0eSLweV3q55+`gu&h`{!<>!j_q%PLV;zY~GywOuN6 ze>$RA#xTVZENK+_-(f-XfoxJh4K@uTRR}uu`3-qeXNC=;VM`MBTSjG`Xkl^wKLIO% zpSEofOt5&#%i?h`F}b!#<6s1Uo<LZ?z(rge4J+6!`;wvb{u$*Sk_zh?pfy4&etu3- zD6AH53*rzTkIR8JP-i@;6!Z}Q(v-`po0C^oR@jxbUZms>Tp@b4_eCBx0HP(lmALc} zfnpgnH>WmDi*#+EO#vm?N;KG#li8#oEN_S3PD!%(mHd6%5(atnOmmF!qp#fPBMC8* z?8)DFA`yPa@d}eOh=qXYpPQISLdPq}qxq1&3vA{#>_Kbm2Ouo>p{+DnF_u|bO4tUi zn5i@O3*7(ga_vsw*<?4q9Pl*`fVDY+FQ>&*PG|v++cMFJS1xP*_Ue7hdpaGDc_p=c zl>gKUQWCCa9>=1k{G!3ba1BgImHpn|kb`MhWrOINpoO3i1WDzOKo4!No2(6St#bTt zgZN~3EsHhS(3JifR00k9|Eo8Hv2LcEERr%RDNbW`+JUAM#V6`<)(^}REedl}Eo!cg z$;>>8l#_VrXG&fKvSL?$pnhJgC^{>>to$Y*SqkHOA_rBTTJ4KO8>#`LM&#cjWj_^I zUwU+Y!Y&7CO=TP!hrRk`jK-v0dr;q$_+pwOSP>JFtGNbjj&|@rv)Fnjzk#-yugI8a z;L6ntNV&UnVA~6c(4@WP(@qJ*Pv4_O36M9$X^>^u^+CW%!MI~`zX)9jI~`&um(;G~ z#U<mJ%#Ol7b?4N2NP^2uG{7EC)aVK#hV_(x!{4EiIb}+|e_WMgEizGGM8<8D{Umbs z2v#Wa+ge5DxRLNU`4h*8-kBd>pslATZ*Q;4!7?QbZs*#3F~wGV2I^#cc3WU6O-X+< z*S86pf%31bYAM&5#zfyTpLwoJC>Mz^Wo_N)*VXimkfKxPoo<({@JGvtwJP3YKGFZk z-h0O1ji*2^|0h@D&o{W@>W6yD<8itYY}p>so<G;X#>rXK*(t&p7pe+rH`%la2=FT* zDKJ1MUD(x0)-SXZ(OWI7cUo_Uz2oKz<tF?zPTFw;!F~nHVAyxzhRQ3UA1ZzW4_F+) z#A+{Nr5|H2xS^vK2VQF<iY08^+;0Yt&dvf9U^MYoQpjG-a9V!UdV6eso5B&O(8_j+ z!$%6M>;|7dC%dURRIptc&-(rTEC5%9WN;NvuZJ<uZ`u2&#kyzDiuq!bi)U^>aKrMF z!w$DIq1wOA561t(2j_JsDfZcdUUX2BsLEg^)EIv%+G;L}Vxlpjq(#Y9)LH5y4g3{( zg~E&^<{(&_Qry2^)>!#&0v{C_pd751Z`FMANA@0p9C(We4c4lxtde4<29K%CEV{Ix z3q8Y_qaiK{+vuSKTzzF_3b8eSxux_UtN_>+^Fq)s=eKYpF`6Cd^Cg<;r)SpM$3O3@ zd#+djt!FS!{nZP4GH!#>n<bNDEhR&5>_H(|q{a_P|2xa%t?fdifNcN4&JcIIB_ccf z-3L2K+IC`}Ytqrn3)grhmLy~EJHtmrCN7L0NPZPRz&h?p4fIvVM$)I3rX*?aX})u# zD>=E7mA970cuF`vvIpo-f#>wh^O@)7#xS_W8J(v?D6+k_qdxKzG8=8I{xXSwOccj; zWC+_VW-g<HV|j08qLl?)3Bp0zL#vNp?=xAPzP!!tyU)UC%ff#?0H>Gc<e<;qfy>(A zV_-qkiz&w^?bAk!codTkd}od`kW!=;5xBM9KBCttjKN-9bB38oB`FYYeGwDr*Y4U> zdwk0W`j{HX=EKB`7%X|8?Y_92UOLw6@5rEIX@~!sElJSRex@?BbWeWT@TlV;#sAH5 z%~zn%Yq9Ncx{UgdrDbVKDY>?p*GiavA-ssqcZkO;?Z;z52lJb;{kavlu*FiwYKePe z#JOr)qumCXW!@0KG=};*7M*%PcUxL)+v87R@Kl+PJcT-9BKB}uBMOYTw@W4^b>5Cj zGIZYh&TEPuT(P&0$US@%G=@{ucEY)cBL4=t#!jG+vu?E7-@frq@;Ih@6FKy6<@CgU z<GVfd{z4p3R&6klovLv7r>|ziPT7bdQd(&&o~O!Uxtf9Kl1XX&pO!38Y!R&bd@J1h zFR-?79yI;B?%|bPT{mVt+utq8jj2FSw{9QkuB%@3R$G4tABY%>brBp+iwIhF-PfeS zxR_T3floj1;pDt{Mq_?$+`V#ITJ`gxI-<vWe>ysNQ|B_p?Ppx9+qdloAs^T?;i0&q z)jnZVqUYTDdfc9y(<7GE(9$C6j0-h5<;?TTyGISjbSJh+lRm$YHPJLzp~m#l-VuRO zGFPF7^u51dR%%Av8q=fe5E5y1_FgANw1_2?xSjTpfqXKYS0m&=sSI46WFk5(52m|g zSL!isUdjGe@hk)9E2YB5q$%F#?|J@rO8~!{Jv)QWFN71RycSEj_WM&J(Gy_=$2v5I z34So8foQ?NtcM4*bje;cTE6FSDzBr_I+Q3h{_&rEFf;(G|I;z+sE>~+sv4y_mk^mG zM1_A$*E4SlcPSt|^vzWFb5x4oQLV0+>rO4gHI@@oNUhhxg=t>8p{5|qbk!87P>u#^ zyxKaZ5Oh6EwD|ULSXPcs(}PgkLy9+j&MTt%CLAUDDN~rBwSAYWudp~jIXqkj@Spdj z@<;>+-p}5Iq1?X8C-|X8+Sl%bq}pZ7^{JPE6UEh`JvgH7o&*pbXOx)|j0Sr48ROr0 zSd5o^J}9a~Ueg}X&wxQS|79c|eP`jE?oJV(p~$|xBdc4xN2<LqpW>Y9C}($mGE}1Y z?JkZbq&*O?|4bhEJDOhV;E>;@A}uvQ9eKcZq`EU{f+0cCf{ws?oD=iUxqW4J8@vgB z);b0(xE@-C@kQ+iYp!qDS{B}Q(|M`H)jaWxQ@yJo=0ZdjM)8z;f6)*|e;5o92aP4h zgSb9wSt?`l)>@4S+W`*N>Jzr*z{K9Zg5s)E0%z+z_F}+xKN!IB-B?*5bmJZ=#(?m= z?+f#5#8>vTR|scmV87ozTfJ&@?E#^!4q+z;9lMyDyl6eQuirHwtk7W{nUd<(d4;t% zd&znv35rmX8S3?m0lcq*g%NCfGExLzUd4t0YS8nj8BogN=uj}BXQ<T`-Ot4-{X1() z>WW1Tx@CnA-aH*53w?F%qaT5|J=@fk%{Sj3>}T~IAHBEBvOI~Ycv7kGB`MYC+?*tM zcz=AhL@3pOrrM*>7IeYdZ)LJwzKE-4d6rq?#pI&u&?QvRW2DeT{jzMOU!^LX5Q(Y7 z!4nj`S~PdW7Xq&@837FZ8eVVU{7g;9uN0z1`-xAxDI?kaU2^@OyI!t4+30ayk*E7k zpg$EdTMRQsmx(NI_fM<y=O^(t`J%k1d#^-I?+aDPU&tNK$)n+x3TJS{;*;3U9&^T* zfLcK^wc9TgZ;QD#c#<><vBA!xIbkHitmgqw@kQ95=k{g=1^4Yy1$dVL_%SRfJ6m=R zv{nJu^t_Ud(b}UwgG-AdU>B!--GtT|mGCsB*|d60!?${-Ug;&^GPmejU@~JrlEn~O zS&x)m(&&w3Y|quW8hF>GWBBX6qdQZ%ggJL+Vc^Gpx-9w@5?U0F<4ShUI#7eN@AVJ` zq8!+-!j<DJ4tXA@%=2Q1E1O4pBhp38Xj)#xjJX&@O7yBc#4pLo{F47PRI>BCmBYj9 zY4Q87ws$8V!=#6OeJ~<?g&WO~vf^lV_h%2Rz!pK*n^~n}8*5GBRJBhy0M`j^{tG-0 z0rS_gjr%^&q?|}Z$9*juS#?C@(T<rcOB>Hy|9(0u84Aq}I5QKrQmx`?at>}h-}<Rc ze4V=6ivV;Wpm0uw?r=o2!TL-E?`Ozy<j(c3J?dVpH7ZMgnq{^ZlxF&Vn7#Y4-!5A` z1c&;@mJ8%geYfs=o|@&@+u``K29?OT1=Ep1{#;07zBXC>Udx`$__I~&6Y`<;AI#YO zXC`m&EDFyK;~|;RF?>5xYS1x5#)%9^q-;T$3NNO54VFq@v^fV({6KaGYpu1d?NluZ zg)r*R4p-ouj4^|tB==7(BCgDjTz{ff22b9H)V9(4Fo_Fj(z6+%E|h(A#+4<KC!c&g z<H1L4va-6pVMc8b^h`K88w6>E5Jm>s`6<7<-pVQ+kz9TLyqcNTb@nMu{KQosgp~TK zbowEpHH4r-mb%jMMH{q+&!<nM-t56|VVANYbval3z0YZO{8%hcOw`G{`5mN7#@Ayf zaL?77uI-zRmB8)t+#lqWE-?#4si9V{Fg8fYgE24A^UP!^*zo_l!rJfSbV!!mnqZH3 zN=mB9GL;Z0<v5X|@=ya>dWd?!@TQDi<(a6TY{2=WqsJQlpQJ5xOWwU^ZPeD&!NzaY z;L%nsR|0DAK<g<IFFP|UPmTCZ7A>25-t!a>nh+x^lB;DxWH#Et6OipY^wcud0H{0_ z&}~7GjvmW<lV^V0q2Y<=HPL?|ee9as7nCts_Z&Ml)4bp7OuVnFr+Hr{S<ve6k&~@o zUqgzIq|ofnp}JF~ciZLZR&V0r8{#R@E#O_kW}f;zMU8z8QxcF1vORVNVkAaR6tR9q zQxn9wk01^V*pdslKJJo06WFK1iW#|UUn3zQx#(CHyv}mp*nQHk9{xdU5kC{g=sIE7 zu~WOzfG~pdzIu>16Q%8QJzrI*-PxQgQ3i{H*f(zz%HLk|BRey`iy=(s1G&O4bh-cT zqMMpeWtT8cNC}MJItl7;c<fa4M;}_fwULmrlX+{@+IcaBae1li^RbkxuTh}5gq}M% zWxoCHV^S84&;y!TS*eX}qo3ohG*P6i?H`TO#F0#gO(M$h0;i6zK3?zMhtQRLT@Tsi z*8{=N<xJ}YlNE?Gwmdq*Cq>4a=jQ0j7EFfC6-@iP%5w%Q=Od1If&MP*Xnf{CkyP&? zU$=e61oR*$1h9Vg9uU}lDL*|gV7czeD{n;AFpl*hIW>eJd*L<x@0IC8T-;$hTZHL* zK@>j^4%qkaXp@<`%HDF`9Lw{Nq424XI$8>CtNEfNz9C#DjbY&^xB%!}4zDn&U)n@| ztpizjfotsTn={k99C{@>$o(;X9@yu$FGWvk=rT#_9DKei`kZk52PEhiur7V@L7=j8 zLa37?IgQZTd!@;noRRNyZ&iH^F8=9e%wSZ5MSfj;S#2Mp4CHs#5gja^w2LjZ)W5&T zhK->n&KlJyket)_IH&U5j5bJ=9oU&ww(;+fYF&xtmHa934(oebdwctX&h<VY9SmwP z#oIaoJ3Vft3N14)G`cW?B@@pa-?6#f{CokS#$z2FgCE}8KmqZlRQuSrZKK7pN#cCI z9+G82Vq>)5T_s_vk^+t>w|H~iD&hE>=cgsRE!^|1Erb=7f6?mF4s6O$E*?j5vprXh zAK_FOqdSuqKI+uh%5Tv73cDHL=S2$f@2+b&RvQ6%Z1US*EHz1YcS%XoP+@avz4OlS z(>5dRv50w`_U%FjtS8B>MR!5V6sgkdK#MVTuc6h^7srEop02!4ymAi0kdnt}QVJM} zke?a68!>D-2B^141bG7Q%H`==OM*<|6=-NiF;uca22tm;aO>rNs{jfNUiGOk-+<#d zq<6pPSH&3L8(G@IwAiC+P)VncyB9P@dWZ1zbGmT(3yPG#XUq=}ior(T`K=k<mqjb< z>7<N)5WCIXRY`U9R9<xu6c-myFO5u2Y;FCpSZ&BJi<#akr~Z#ki$e)ZK&D+>jf;$` z63}~{bAIqr)0HGqvJbZX=M!7T@Hu<Y*By)IZ|h-Ja*QL&+L-kh(?mWS=_6eGDweQ3 z|C+R?8l?)&HVz8j4d0uE?uLE)uo(qcF8S-Z-E1d0Tgj)>8v9|8Z_3J`G=eg+dzm0Q zM{x0ebYiAiktu{C)vfJ@Fmg1ZmPyaxYP?jH>r?lSP+T}Cgv>zo{YE2~bOPW0c-1|m z)3;-5WyT3?(zj#m{k}jk9io?`#zcg5w$j2Wf))6aVDWt8vESZ%q~D(qJFqOPeyapF zKU^<Q*S)N8NGvDy?HNPfOxmxlFRbz|Z?HBLPAJY!@grMf2Ggoktm$;?Q|?N4=!=NA zlWbf5o`?sd;!;#~Ob}9Q(GR9K(#}BLoZ`cuquRX8uvG>B)f=gp=$V%v(G?~Aw$1B4 z8-%0DQj$cTx@zi%^JALk(N{4V-tf<KC55G>;no6C)Xk`WQa_yPaYo>^5=8-7H`T@l z>gj`aggy<u%!7d!{YYs__+r@f^K_mJ#|iR9n(Ds3zV$V#by!ag-@<Lk?!ObXubuTK z5*0z%9j%Rf{k(U8tT`kzoDJ{rdI_Y*wAC&>--!Hcp&42zUf^vnyN?8G=Yb4nwwBrg zK9EN*dE|KSrOYNK{uUk3SBi8JI<bFyo3}^UDM}KZZ=7l??ld2D>f`1L1On@lwfY{f zCPrux7w9)?7fEBqvnwl~DDAOzHU`dn3H-S(qL->bcJ_Amhqqp0vtsv#^xZxt(8urC zuNU=obhutilQZB_p41e_2F)%*3}<irm$I+;w<kDfqEl0H(%n$pdbWVAeHy=8;E}_O zm$2Eg;62Tl{`Pxm3{BFc^#u@OWqYb^)g?GxkoOZTVIuc>JZnsT%Q%)vAU02EUC) zXjA+~;raIINg-aMfvJVYtnv&b6c@T9!~+pn)8`iPd3YUI)k1?SeDnyZ!C!0Ry!abk zli6u&q2jmWIVGvD<PKz?s@PPx71MFqcRVx9j=G+;hsI5D#k9RS(|8jX=Dj=ayZJ+r zT!h4zG>4Gl@JM8C)1~9~D}&NouNVUi`re0yy3R0ykyMKgoT2_!dmQuf+F$;CZEZ`| z*4At%XJ<TWEJ>z-HfRpUtI(|%+*eD%Z~1RE0Djs^X|CZ@`1sj`2|DeTT1>!jrFKO{ zMb%^f-7zm<ZqDK?*P8rLX|BC&tr~+Dc3f@PBux=;<T5Yn@_c%FdiF-tLnlJIfP$Hs zIY&8_%ciEhoX_<<Pzb@-<m%op>bNd;zS`j$EuiXZ@gaj+-jF_wpg`jnbbZ~F6fYv4 zU)42rM+ga^3h{9>k+e2kjFV-U1-Rks0g`rodrX~2DXd6%jasV*1yt>>_oftD9XDuP zsUwKhgbK{2GT#r(&1oHP4ur<`A#UoRAiqmFUyl3E+8v=dvPfC6xg*ZFVd}M3`@5C9 zF@DFu+}OCCe`8<S=H>_`7{U(NIXD{WTPU5vw)2U1yGj<8h$4jvp{=Ja=SkbQ`vcC@ z>`C-BC5&8Q1aqyY2qf^~Q9m)Y6XnB52bsyIx6ktytQ}o&X`wTwh}-6LM@hG@lA)Hl zsw4cgC6(2zR>kzfTJP9qTz3<ybUOCm27Sp#y|5^aE+$s{T$23M_qS`Z3M~{RmE?!D zKqY$#&JbVnj*tU;i9Vz`toFFn9x9FT8UBQr1e{xAnK3LSZXJhzRs=h{v6mFsWELHF znnOQGV}Q@^s#X_*AXqQtPab_0$JmS+DJl56HzQy#kjlROJwo_%15XJ_W+{8$hUB+j z{3%#wiVnl4(^skx>bK_~Y5=8BH#q3PUqu&E+81*8VQsx@iX6yTW74H(BSVDmJzqv! z3IuPx?t_iA>#PYp|GB8^L-<&b*Is@`FR+Jh>-Rk@gsDJ%BPFx%dTygZ*+d9l#E#@} z7>QKr2r;IbQOAD-d~d2Q4xauW#J-a=&-P!;NZPIm^d1U}_n*0j7iMRfj*HFS4o35; zuA-2y5&=1z-ut(Td>mE&WzzMNU6yXRzkJX_g=hSQfKnlj>-wf;xi$F+%uZK$E5{7B z??eJ8?CMmrX>qPn0v{{?gW+9b?FYP?IiFxc%@X1aCONOPpt7o;Ge2hreuF`B`+bLq z`L0N05b#*0eJ(fc!i?r-0Sjy*K!yDeB$K5J_){oYp)6nZI-WFeg%}3CMU81l#9Ds% zr<dOQGiyAP?)vpSzS~E56XmihmkV(evF!`i9;D4q_i5wa5&-p7<@TpTL#)X11FxE| z=qnX)?W%r#1BIr>DJ-CV@cMrz6tAVfTz+jOu&CTima=A``l<-XpszUD5aTh|!m`fH zvz;|yFd-A0dR^i2Ib+Vb;)1tHG+7#=wb28%SK&ha)q{uhxO5zuj9r=4EP#I=LfIL< z0aBzR{}om(GoA7r`qBt?FJ(nKP#y*m{j^`nkdfp-@Qyp?FoaZwY+db|b$G@j;9X9D zHIL#C6=?&yoJWsB8VJfSsqdsLnL8m-gxm>7GfLPj_DE&-=kEfUkW`dmC{WdDlY>$N zCTj<qu>hW;Fo6P1jRRJ448DR}n*A!xDj?>fJ-_z`13oi@ytb=rtJ9CA9o1_z#GrJ@ zK>uHo{(h3C&7?AYoF71R<J57|!PVq{Y`wO*Z!i9ff>^aOP;vdBs7;-gOV&^03mgau z=5cz(!dm*T^j@YT^nMU$cImjFkwwbi-#-u||5dKc?)^x-A+-Q;C}L?*=*5o2d@7k) zSx(snJmmnaM+s!+3a;i-JMvCn7m5G3P({e~StQTtzJfpEP+(}E;hl4N=3czfHU1^4 z>^On3vyXQloYy6eAe0E~eFauSE>&l%=9{h0s?4OrCY!esq)1l6v$Js#6wJ~2k9yZ$ z@ejWHLu4tPfZkdX&KTXoG{rr|Cj1L+Q2-0u^@>2HTIj$xg?Hg1SBeGQ>G>EqZS=Q5 zR{8h*ynq1eZ?x|SX(i>*W!$f<rGQtsGXA!@a<=F9^JlD#KCho@6+CE<$0+_Em(aI0 zP);8Uv4~)-LYXf!+5EVEuCb(DVS{LI>KpnFK%OM<r^nZQk3_~(O)Ko8^H(=#nH)k2 z1kHEWVE$*X{==e@7Bp4J3uspofnj4~CMU<Z8SZ#~FTMA^ObKbHC=k++b=G{F`P)ea zJ>F`x9Tv(B+Pj+!8=QCg`&&%5k`Fk}sQIo1x24vm9jE7+`kX$%wu}Z><}NNeZx`>Z z`;fk`YPy`9ML6Rj{0*yafq~M?uIy+AU1b#I=Q~|9sU~SzACu%%xbRu~PPq7{#)O1v zfWP>u0u)eQTfW=8Yh}4s9BI(seP2%Rvi@vwB{-9&HAm>-bnmvUha<BTIYOLFmi9K7 zz^$B_Nw=^wQ0N`d)z#JGdMt*>jhZU(BRz9)BGTeP&K}$kjXXSV=TEx{O_Xv}Qv?|d z%j={8tmiA18;;G>p6`Ewh|(VL?1G>7<>v<_N&zdm(zV#wFX2y}(9={vhv-!d`2+41 z>btStjlNXHSmc8W0y=)`6X$)2K*@#ox`rJZO51nvmdUZg+46BHN`3XbgC4CUJD)(i ziXh~j_u~kBx$DkeFSk9@RWBFNzqR-3tn=A}W5UiXyXA6psBPPM-RBB3xwPqVPPvH| zLi)|H4X>#!4gcdkZNW~?CVo2^bni?*VDNpF<8Vy}>nYOT34JZ1xZ7=rI7Y?J2jejF z&&iod_#5q8)mYg1oD^!LiR51~`EL&Sd7KR8=$kC3Xo`(VVr$^b^`{nb)b?of=_V!- zDqgS$c-8dtW!_3I?ba8Tk=K-Lkgs<;@$@*M7PNgNQ0K<Qw;gt@_~)yak4Kz!j{`}m zH=-pv$8^kmhj4X^b>?wrr(y;Q^=(pLASLVPWxS<q(|=naM=Z(XORsP!fzI=laLNZM zt4zs1#J^Uf`DA3JX)JX}v_PPEdr@lPxkP?mDfDljK53x^y_qQN>WW@*d8%$b`}G0L zLtf9^^}&)Yxk5dU*l;h7&#-l>vn*f)3ir5bzz;~=IU*xE!XrMyb2VO*mhjkOwK)}% zUH)Q<hBa!31m4cN6oTjZhc{;IqGCOrcpVI!d@Dc2m-w-<^Lg<^#FEFT^<G9pV&QRh zgFh#5Dx<0$o|0G0ajiCo@+<9J5vWj{QV)?EK4W2#p~h?}<?c^!M-J*-Zel-PlmBZS z=n_q>Z@@9a%o#GD?9-qs%3WNMX2IeOyWhA3#jnS1m<$V-`Tum)GyM@9A-Ep!eP7fk zx5vZ%UV%J-1s--U&6b?;bpsMu>^7<r<tO1GaYYbbTXY!0eY~h?`e{7oh;pMU5H=(T zy*-6bHqA&F30vINF)0bN9hzm3F*IbzRwwoL@|pUgY&nsu%Cn{0h~G9ae}B!I1dQJ} zUkV*CJ9E7NOjcBx%g-E##Z#YoLUq;j6xewrTas6_cvCYHYhroN^IN>hOd@SXh!@;g zsty|~4;v~mg%^fnMbtj|WA2;6AZcnMTaBSwN@*|Od<=LdANlBNLMPWM;eWQoTJmMT zcgb2}uK#4&l~0!z{qD^sF>MEB5PEKVTIO=f{QUfHpJJQ)n4SBG>9y7IeDN!masB>W zFl||3AvJv2$_Z)LZn6G)AOcX%_Ky+d!%iA!>@+~lPX?U~MsWobN5_uL2!LBVUaZo% zU8H>t0N^$JmkY2rsp}^1W8im0eYWC-4U%}?!#qV2a_BWDj=S4-7Z89-36dmu@p=R- z1joi?RMgfMY;|;%16tSGf+_l2;fwJ;^^By)zP>`4PVIj~^G5e?A>Pf{K`+jvWuiMV zG_$H8eJk+_RZ+hr1FKh1Lrpze&EoW=8Yj8NaER(|9ZhO?@~9eTvU?MGgY#}39vgKY z;3@w51F2uiHBMq{Vey>h?W1IqW80{66*ZncjG{{YC-t8ibL%6d5}ghL1_A4T8Z#Gm zwzk3-lW%m8>o%^5cKeU-y7?F+X<(=&yS4L=vayr0Ba{CKe{0bNN@;%jz?!bYvVZT_ z`;;MJ{a27+<aYr}LZwER`7`Kuk6EP<)YGx(R7x-prg+3C+SUiO0#T6x|IM?F><4v4 z5C&mhA{7@f5@UYReV@#M>3jQ5H0Mq1`9^$OW0b5f)od<}&!<o8xqqZqfB7le&pc)I z{qqa}O#N$w%?q#Iu6i17`EG<s2fc82r*9FxU(*4m0=uJRJP(r?bIzl$Lono)CtW(@ zJoxUCudlRpL^JW`mX{Oa3G?0PK?mzY@d^USJAYrma=~<t%-4JeR0^kLENuG8ita#Y z1D|n3<OrHc59J7Rm+;}gd45obh;EZQ$&z;A=?=P}SD@1~|Dvj+VCL3VZm_iGho+F) zB8Bv}E0m(fq*A%1Su8hwTdXUyK2xNOg{@9?0vsLfP3`DCJ;>^BB^-?+RwPoJeST4T z_n_Y+=FSh<4#oioXNP-TAlQ14tKV~08^GzBcX68om09k6d7~eRl!RZ<%Z!(tgD*L} zigrDVM=KvKe@U%2B54X?s69?sPOU#*(9iQ`$#~psH@*;qwc1~2siKGm-ufzX1~0We z3h!8smS*N1$1<M?#aR{#Aa$y)9!&_Mk~_~c_;~G?=Ly)4wJwHwQz4bWL^mZB(t;oF zr9JrrZP4JYEn0%%IBp7^Lf7HEfku$#CvEp<rH^wiKSWtvQ$4gzQjQ>*KiSylE-AP& zx+2zT2K?2TK|b*MEAsHS+ghp#6OzsTvL1HB3_{QTKVs6@Tx(7LaUvfU`^6+S(lG~D zlEO1P^XA=6{wAQRq?O3ymaFHfdKr?1OTORl<`r>S7G?j2g-n-pAf<_r77~$!q?)>5 zI!Zk9VILo1w6@8J#gRrQC=O$$r9pl#fgw8wkM~z^pnHN@h}id5wa8}jnzpY@t%}hP z&v;XMUOWdd+Y|2&yVgf8x_+tFtN&cIp|4SFJAC{>n$k=$Q7yz5;lkN!uKhfFMV@~v zvG~??*pA%F-zO-HIg*NuM?Y6yDzcI=wjUKX{`RemLb+r|oWBv3AzuiNtTAQFwPj<# z)5Gh<8lxqC-Mc)B5<%72Cr7wJD??N%dol@|LO!*I(xw5WV-K_Ub^aUGl*`1GulLTH z(yAKZM&f1T1R@Sjd?ls1KKeJ`_vX@tU2n(M*2E1zj+=A$Z+75t?2AWkX#Y5jFZkAe zShhrL9{~+~-~{ykn_1ea3+p$&K%-wS0r!*b2uL$tMOdp96omEL+K<G^Im7)9B2f=s zsjOn)O|-p<*y!^S?d1DY-w-&{vrtxtst{Dua2G2twW)|6rnDH?-0ga9{)Ycb3)%ca zbz%?2J#Vuj{5egN?<q7sPWHfQ??}7pymq5~tnIEL?tPID!%nq&o(~>T5rLCxFkw1C z(vgDgYS;M!cCW?ZH^8O~R=Bu7oli7Y!0`gI_lIkz9%r|g|8;;6Ny67Vf7KM*%HzD5 zpGg8~=#6xDAcJR}sUwr|<}`)oJ}PDS^ImJS%elKBVtV?u4hr9aR(gWO_jEROkb!^2 zHnS(ce<mPtJ-~G{gB6&uxb2dd@R(p&U=Lh`o`qbPF5%S^??eVE>{zXwDbQGII%AGF z_Mk;j5jqI+v}J{OQF|IusoAi<K6-%62&p0H`^o*FjY55A#Q(y58tkdS9)Aeeel!A% zPzpX{2y$Ba1+{Ig4{=fnKBD~o>Bz=Mw!!E2!UC(5dAC!z)&HBAtV;#q9V$Zair9WV z#Af}08-VvAdY(e9{@`#%Wyc_sh4%|PG&L6#JSX`%b%a0g%~4q<Uw2Y@0$)bj2Q84E zcq0x|k^t+M>ia>`eG~TuU3`$+tem*^0Q!OW(T+w@TovCmkaa|R(eo#f)3<@rnh){c zPT^Mc!+Rfxeoou-w#+<T2~$^BRE%XEb5smAR%d^f3H~kMM*myjdu`Rp#=E-l@ytwJ z(7kyB^i(ZQ1SdUXsqk2&v!H<L1+o_$Kk@eU1$9_V%nputDQl5_o*)}+3-A`-c-Xy3 z=2q$1=SHf6lG>~gfzaJ{?SjGE$DN}_@nVC1^lYn-`pu<71|xDOoSYUQLkdfqpU6;4 z2P;-r<X~*x`I|EE4pPkMo!2UA=ts+`%#jzg^0EYuT9M>`!=0L)rG9N%6m(R{VVRtQ z+>K2AOBD52DCiSeabsoTg2n60#Z(!T!MN3F&}<KZ8E3sCY5<Oq&x=l3TU(pslwr6g z8bmicm{OP2<)#^0j~(*)J{Cugxd5hk%C4YcolEz+Jb%Y#z8MptQXG<2YKxuIw!oL{ ztH4TF<|_x8O<scerK}1(N9^PpdhP_DWn}7s%WIs}>05H?AH5$j`<Z_GLX}UijXr(4 zx|RI4RoK>+rpP1>0@2P|CmV33K2gMjflNd%F&7ocaAUQ~`yz@UaV-owp7u>-&?xcM z>liV&^Bb>vJFD62y$%8QCklO4+V3qDyp;XA7@btxu@aQI&Sxkdd@dG?&euq*m*hPW zc!W6L6;nyBTPNgP&cp!gD}C{D{1X>$Zrg2KSjM$-LgsN&dowf6U*Qi7BrR!XY=S&~ zY;IBA%p|X0@7$0&U5>n_4S2i+UuR&vuZ8nokZxZ4T(<M>e&@!w5D!+_m#jO|$~<8? zIy$0!L1qeC5+8o!I{l~6btf|DyTFSX(+@uADw)(vF3CAPM$Wnl+PX+U3Z$S6@Ld{~ zAby9<N~V|B|05N9mpkjX`abw4G;}DD|5V!B@C5OH25WeFHfW8D>%JsJnSu)yX-a#V z!Wh>QA!Hvu8&PIz3AMh`s&A=y<=LEopL1d)+%)X9og%L1kTd*EcN1!AoA<oy`iq7A z$yJTq8`h%!nf%qPH3=Bl@l>Gk<AsefpxfgeD@ItqOQawo<4IG_EEU#4G7h-kt(9eH zkS*}?oyl!z`DwrN;SqLQmw#u5GJ4|B{hl2y&-#*3lA5V}Py1x8iCqaA9J5DJ5u0`{ z;!hd@h0>E1EeRY})Rx@N&j&nA_0U(3hN6nmP!dO$*4xxl9{cU=S|xpsMD;Kx#AOCD zsU|z@43om~1vCr|#|FYtT!Y2U(Y%PaMB`+{GRz9Za@txSQ(hLKFHfVYT*+m`>MZG^ zjx?RMx&j|Q+{O*k&SP@4zVSQ#-e7K4qR2$O>Mw%1_PuSIauI_GuaoW17TTl<<4b_@ z5;s0RQO>>DjploLv?+v1)9B;rW3q>X8tSrleMS&i#<w6I(hDoe^M2VcR%}<DV8k#v zuq!E%ikpPw_;O7P%}#|csi+xjj;<{!f^;s5B02+Wj(x;Tn35Axq;?VE`gyb|Zz>P~ zrKy2kmx5yvCH9a3y0Nb=zkbE*;L(?*O;4M;?9-7mTE8cZm33I5jcg}xUpM=cEXR;= zaeH%v#wcD}`RA-q3wnF6<y=X~$>!vK9IUbPGQjU9Gx*CKA*HJKF*R`!bvpk3Te+%P z60}RPMY+Q6cjp^zf;acV?$ov-ekn65lgY}d#-uks@mF{kK;7`0n;*3)Xr^tPsVezy z3O61Rr{X4#Jx6zNUx5EYrS3|pYF4&qh@)X@RaaNn{25QR=}c)nR1}-mfz#eznQ7a^ zp{<KoJ)o6%_4*TRI5RVoI4U|?olN=wXZ?=BYIwQTUOXEoO#wlkt1HAST=!M8@fXPM z7%<B+gm-@Vuf?IwlyB-6aX;e!IGuq9WAkdd?_%gCBG+qM$9`|}>!pp=x5tU~9&W%* zS&lBTGon#ses=5AZN|)+vjFAOlm35OcaC$(9s#HYv=#m@<aZSM2fH_0={m}BO?vh= zynee<d1g1xEO$>WaI$<=B??+#npJXtPT*+{NLN=EWNh3mX5#Msi>CgvbxFx|rQW$g zi>TzcJ=7+#wPQ(hPy@@e0(5BNKd7nX{t^U_X3{CH<DIuAA1y%G;LF_65T}6xI>3$9 z@4(Jthbucc`gvk^Prbboo-e@=XC@-{7OpBl|E|jj7B+U*#Q69MN^pMym^N^Al5s?s z9-)}})?eK@AD;8q)6I><tpmR=@a#lHU4TO2h)luAC$VH~MKUEV&9evM7xaR}9c5&O zR;>j-9p1sA$45tauaJX>h0Z0-$sbcvQV>y5QTYUeNz2AxtjUZS!U!4+s`JartUS2L zjJ_H!a<N+gIpi0mGfUq%QCmgZWOfDJHgxx2UadK_88lmK9-b^W*?oh4xI2X|`CV)d zNU$@z?oV@zAz(XJWTd1SIXOALxd9J{GLF6XrNSwGs*s;rN0G9F#|D>XVu$2$J6_Wu zju~H%GOv$H6nc8qZJZ=_B+_m|apsnT5riHNi%91$j@rX-HO)mN-F~%c7bz>Pt>zLB z)@QPZTAsq0o*$fKle7v?gv7VnS;CyMv)8^3>nuhE#tW*SQUnu|%}-s+6TL0|JUcs= zVvSHf_ZV%#u$`-+dqL^9Jd!Aa8mR%KmUE1U>3w#;>X$Y&uwR8T5Jes+vA2CDpL3?p z)2fuhAcVM!J3w1m!uX=2qOvD#`!z}W+p{*#Uyps&(pEa`tYs{5<1Fcx{vn|X`380l zBN*i2;Ls8me<J+TjGW$S3F!UE$Vv2L|MO)jbR(0GJiH)z?mzx-?^}$zExNFQGxR$} jOB$o#8<ghl3H({Z?n%(Sm$vF9w;ceKQ<JTgHVgS5H*^UE diff --git a/plugins/managesieve/skins/default/templates/filteredit.html b/plugins/managesieve/skins/default/templates/filteredit.html index 8b19935..6ecb03c 100644 --- a/plugins/managesieve/skins/default/templates/filteredit.html +++ b/plugins/managesieve/skins/default/templates/filteredit.html @@ -5,13 +5,16 @@ <roundcube:include file="/includes/links.html" /> <link rel="stylesheet" type="text/css" href="/this/managesieve.css" /> </head> -<body class="iframe"> +<body class="iframe<roundcube:exp expression="env:task != 'mail' ? '' : ' mail'" />"> +<roundcube:if condition="env:task != 'mail'" /> <div id="filter-title" class="boxtitle"><roundcube:label name="managesieve.filterdef" /></div> +<roundcube:endif /> <div id="filter-form" class="boxcontent"> <roundcube:object name="filterform" /> +<roundcube:if condition="env:task != 'mail'" /> <div id="footer"> <div class="footerleft"> <roundcube:button command="plugin.managesieve-save" type="input" class="button mainaction" label="save" /> @@ -21,10 +24,10 @@ <input type="checkbox" id="disabled" name="_disabled" value="1" /> </div> </div> +<roundcube:endif /> </form> </div> - </body> </html> diff --git a/plugins/managesieve/skins/default/templates/managesieve.html b/plugins/managesieve/skins/default/templates/managesieve.html index 94cd1f1..71eebe1 100644 --- a/plugins/managesieve/skins/default/templates/managesieve.html +++ b/plugins/managesieve/skins/default/templates/managesieve.html @@ -8,46 +8,79 @@ <script type="text/javascript" src="/splitter.js"></script> <style type="text/css"> -#filterslist { width: <roundcube:exp expression="!empty(cookie:sieveviewsplitter) ? cookie:sieveviewsplitter-5 : 210" />px; } +#filterslistbox { width: <roundcube:exp expression="!empty(cookie:sieveviewsplitter) ? cookie:sieveviewsplitter-5 : 210" />px; } #filter-box { left: <roundcube:exp expression="!empty(cookie:sieveviewsplitter) ? cookie:sieveviewsplitter+5 : 220" />px; <roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:sieveviewsplitter) ? cookie:sieveviewsplitter+5 : 220).')+\\'px\\');') : ''" /> } +#filtersetslistbox { width: <roundcube:exp expression="!empty(cookie:sieveviewsplitter2) ? cookie:sieveviewsplitter2-5 : 175" />px; } +#filtersscreen { left: <roundcube:exp expression="!empty(cookie:sieveviewsplitter2) ? cookie:sieveviewsplitter2+5 : 185" />px; +<roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:sieveviewsplitter2) ? cookie:sieveviewsplitter2+5 : 185).')+\\'px\\');') : ''" /> +} </style> </head> -<body> +<body onload="rcube_init_mail_ui()"> <roundcube:include file="/includes/taskbar.html" /> <roundcube:include file="/includes/header.html" /> <roundcube:include file="/includes/settingstabs.html" /> -<div id="filtersbuttons"> -<roundcube:button command="plugin.managesieve-add" type="link" class="buttonPas add" classSel="button addsel" classAct="button add" title="managesieve.filteradd" content=" " /> -<roundcube:button command="plugin.managesieve-del" type="link" class="buttonPas del" classSel="button delsel" classAct="button del" title="managesieve.filterdel" content=" " /> -<roundcube:button command="plugin.managesieve-up" type="link" class="buttonPas up" classSel="button upsel" classAct="button up" title="managesieve.moveup" content=" " /> -<roundcube:button command="plugin.managesieve-down" type="link" class="buttonPas down" classSel="button downsel" classAct="button down" title="managesieve.movedown" content=" " /> -</div> +<div id="mainscreen"> -<div id="filtersetsbuttons"> -<roundcube:button command="plugin.managesieve-setadd" type="link" class="buttonPas setadd" classSel="button setaddsel" classAct="button setadd" title="managesieve.filtersetadd" content=" " /> -<roundcube:button command="plugin.managesieve-setdel" type="link" class="buttonPas setdel" classSel="button setdelsel" classAct="button setdel" title="managesieve.filtersetdel" content=" " /> -<roundcube:button command="plugin.managesieve-setact" type="link" class="buttonPas setset" classSel="button setsetsel" classAct="button setset" content=" " /> -<roundcube:button command="plugin.managesieve-setget" type="link" class="buttonPas setget" classSel="button setgetsel" classAct="button setget" title="managesieve.filtersetget" content=" " /> +<div id="filtersetslistbox"> +<div id="filtersetslist-title" class="boxtitle"><roundcube:label name="managesieve.filtersets" /></div> +<div class="boxlistcontent"> + <roundcube:object name="filtersetslist" id="filtersetslist" class="records-table" cellspacing="0" summary="Filters list" type="list" noheader="true" /> +</div> +<div class="boxfooter"> + <roundcube:button command="plugin.managesieve-setadd" type="link" title="managesieve.filtersetadd" class="buttonPas addfilterset" classAct="button addfilterset" content=" " /> + <roundcube:button name="filtersetmenulink" id="filtersetmenulink" type="link" title="moreactions" class="button groupactions" onclick="rcmail_ui.show_popup('filtersetmenu', undefined, {above:1});return false" content=" " /> </div> -<div id="filtersetselect"> -<roundcube:label name="managesieve.filterset" />: -<roundcube:object name="filtersetslist" id="filtersets-select" /> </div> -<div id="filterslist"> -<roundcube:object name="filterslist" id="filters-table" class="records-table" cellspacing="0" summary="Filters list" /> +<div id="filtersscreen"> +<div id="filterslistbox"> +<div class="boxtitle"><roundcube:label name="managesieve.filters" /></div> +<div class="boxlistcontent"> + <roundcube:object name="filterslist" id="filterslist" class="records-table" cellspacing="0" summary="Filters list" noheader="true" /> +</div> +<div class="boxfooter"> + <roundcube:button command="plugin.managesieve-add" type="link" title="managesieve.filteradd" class="buttonPas addfilter" classAct="button addfilter" content=" " /> + <roundcube:button name="filtermenulink" id="filtermenulink" type="link" title="moreactions" class="button groupactions" onclick="rcmail_ui.show_popup('filtermenu', undefined, {above:1});return false" content=" " /> </div> +</div> + <script type="text/javascript"> - var sieveviewsplit = new rcube_splitter({id:'sieveviewsplitter', p1: 'filterslist', p2: 'filter-box', orientation: 'v', relative: true, start: 215}); + var sieveviewsplit2 = new rcube_splitter({id:'sieveviewsplitter2', p1: 'filtersetslistbox', p2: 'filtersscreen', orientation: 'v', relative: true, start: 200}); + rcmail.add_onload('sieveviewsplit2.init()'); + + var sieveviewsplit = new rcube_splitter({id:'sieveviewsplitter', p1: 'filterslistbox', p2: 'filter-box', orientation: 'v', relative: true, start: 215}); rcmail.add_onload('sieveviewsplit.init()'); </script> + <div id="filter-box"> -<roundcube:object name="filterframe" id="filter-frame" width="100%" height="100%" frameborder="0" src="/watermark.html" /> + <roundcube:object name="filterframe" id="filter-frame" width="100%" height="100%" frameborder="0" src="/watermark.html" /> +</div> + +</div> +</div> +</div> + +<div id="filtersetmenu" class="popupmenu"> + <ul> + <li><roundcube:button command="plugin.managesieve-setact" label="managesieve.enable" classAct="active" /></li> + <li><roundcube:button command="plugin.managesieve-setdel" label="delete" classAct="active" /></li> + <li class="separator_above"><roundcube:button command="plugin.managesieve-setget" label="download" classAct="active" /></li> + <roundcube:container name="filtersetoptions" id="filtersetmenu" /> + </ul> +</div> + +<div id="filtermenu" class="popupmenu"> + <ul> + <li><roundcube:button command="plugin.managesieve-act" label="managesieve.enable" classAct="active" /></li> + <li><roundcube:button command="plugin.managesieve-del" label="delete" classAct="active" /></li> + <roundcube:container name="filteroptions" id="filtermenu" /> + </ul> </div> </body> diff --git a/plugins/managesieve/tests/parser.phpt b/plugins/managesieve/tests/parser.phpt index d703534..aec0421 100644 --- a/plugins/managesieve/tests/parser.phpt +++ b/plugins/managesieve/tests/parser.phpt @@ -6,7 +6,7 @@ Main test of script parser include '../lib/rcube_sieve_script.php'; $txt = ' -require ["fileinto","vacation","reject","relational","comparator-i;ascii-numeric","imapflags"]; +require ["fileinto","reject","envelope"]; # rule:[spam] if anyof (header :contains "X-DSPAM-Result" "Spam") { @@ -14,28 +14,17 @@ if anyof (header :contains "X-DSPAM-Result" "Spam") stop; } # rule:[test1] -if anyof (header :contains ["From","To"] "test@domain.tld") +if anyof (header :comparator "i;ascii-casemap" :contains ["From","To"] "test@domain.tld") { discard; stop; } # rule:[test2] -if anyof (not header :contains ["Subject"] "[test]", header :contains "Subject" "[test2]") +if anyof (not header :comparator "i;octet" :contains ["Subject"] "[test]", header :contains "Subject" "[test2]") { fileinto "test"; stop; } -# rule:[test-vacation] -if anyof (header :contains "Subject" "vacation") -{ - vacation :days 1 text: -# test -test test /* test */ -test -. -; - stop; -} # rule:[comments] if anyof (true) /* comment * "comment" #comment */ { @@ -44,24 +33,40 @@ if anyof (true) /* comment } # rule:[reject] if size :over 5000K { - reject "Message over 5MB size limit. Please contact me before sending this."; + reject "Message over 5MB size limit. Please contact me before sending this."; +} +# rule:[false] +if false # size :over 5000K +{ + stop; /* rule disabled */ +} +# rule:[true] +if true +{ + stop; } -# rule:[redirect] -if header :value "ge" :comparator "i;ascii-numeric" - ["X-Spam-score"] ["14"] {redirect "test@test.tld";} -# rule:[imapflags] -if header :matches "Subject" "^Test$" { - setflag "\\\\Seen"; - addflag ["\\\\Answered","\\\\Deleted"]; +fileinto "Test"; +# rule:[address test] +if address :all :is "From" "nagios@domain.tld" +{ + fileinto "domain.tld"; + stop; +} +# rule:[envelope test] +if envelope :domain :is "From" "domain.tld" +{ + fileinto "domain.tld"; + stop; } '; $s = new rcube_sieve_script($txt); echo $s->as_text(); +// ------------------------------------------------------------------------------- ?> --EXPECT-- -require ["fileinto","vacation","reject","relational","comparator-i;ascii-numeric","imapflags"]; +require ["fileinto","reject","envelope"]; # rule:[spam] if header :contains "X-DSPAM-Result" "Spam" { @@ -75,22 +80,11 @@ if header :contains ["From","To"] "test@domain.tld" stop; } # rule:[test2] -if anyof (not header :contains "Subject" "[test]", header :contains "Subject" "[test2]") +if anyof (not header :comparator "i;octet" :contains "Subject" "[test]", header :contains "Subject" "[test2]") { fileinto "test"; stop; } -# rule:[test-vacation] -if header :contains "Subject" "vacation" -{ - vacation :days 1 text: -# test -test test /* test */ -test -. -; - stop; -} # rule:[comments] if true { @@ -101,14 +95,26 @@ if size :over 5000K { reject "Message over 5MB size limit. Please contact me before sending this."; } -# rule:[redirect] -if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14" +# rule:[false] +if false # size :over 5000K { - redirect "test@test.tld"; + stop; } -# rule:[imapflags] -if header :matches "Subject" "^Test$" +# rule:[true] +if true { - setflag "\\Seen"; - addflag ["\\Answered","\\Deleted"]; + stop; +} +fileinto "Test"; +# rule:[address test] +if address :all :is "From" "nagios@domain.tld" +{ + fileinto "domain.tld"; + stop; +} +# rule:[envelope test] +if envelope :domain :is "From" "domain.tld" +{ + fileinto "domain.tld"; + stop; } diff --git a/plugins/managesieve/tests/parser_body.phpt b/plugins/managesieve/tests/parser_body.phpt new file mode 100644 index 0000000..08ad549 --- /dev/null +++ b/plugins/managesieve/tests/parser_body.phpt @@ -0,0 +1,49 @@ +--TEST-- +Test of Sieve body extension (RFC5173) +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["body","fileinto"]; +if body :raw :contains "MAKE MONEY FAST" +{ + stop; +} +if body :content "text" :contains ["missile","coordinates"] +{ + fileinto "secrets"; +} +if body :content "audio/mp3" :contains "" +{ + fileinto "jukebox"; +} +if body :text :contains "project schedule" +{ + fileinto "project/schedule"; +} +'; + +$s = new rcube_sieve_script($txt); +echo $s->as_text(); + +?> +--EXPECT-- +require ["body","fileinto"]; +if body :raw :contains "MAKE MONEY FAST" +{ + stop; +} +if body :content "text" :contains ["missile","coordinates"] +{ + fileinto "secrets"; +} +if body :content "audio/mp3" :contains "" +{ + fileinto "jukebox"; +} +if body :text :contains "project schedule" +{ + fileinto "project/schedule"; +} diff --git a/plugins/managesieve/tests/parser_imapflags.phpt b/plugins/managesieve/tests/parser_imapflags.phpt new file mode 100644 index 0000000..a4bc465 --- /dev/null +++ b/plugins/managesieve/tests/parser_imapflags.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test of Sieve vacation extension (RFC5232) +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["imapflags"]; +# rule:[imapflags] +if header :matches "Subject" "^Test$" { + setflag "\\\\Seen"; + addflag ["\\\\Answered","\\\\Deleted"]; +} +'; + +$s = new rcube_sieve_script($txt, array('imapflags')); +echo $s->as_text(); + +?> +--EXPECT-- +require ["imapflags"]; +# rule:[imapflags] +if header :matches "Subject" "^Test$" +{ + setflag "\\Seen"; + addflag ["\\Answered","\\Deleted"]; +} diff --git a/plugins/managesieve/tests/parser_include.phpt b/plugins/managesieve/tests/parser_include.phpt new file mode 100644 index 0000000..addc0d4 --- /dev/null +++ b/plugins/managesieve/tests/parser_include.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test of Sieve include extension +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["include"]; + +include "script.sieve"; +# rule:[two] +if true +{ + include :optional "second.sieve"; +} +'; + +$s = new rcube_sieve_script($txt, array(), array('variables')); +echo $s->as_text(); + +?> +--EXPECT-- +require ["include"]; +include "script.sieve"; +# rule:[two] +if true +{ + include :optional "second.sieve"; +} diff --git a/plugins/managesieve/tests/parser_kep14.phpt b/plugins/managesieve/tests/parser_kep14.phpt new file mode 100644 index 0000000..dcdbd48 --- /dev/null +++ b/plugins/managesieve/tests/parser_kep14.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test of Kolab's KEP:14 implementation +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +# EDITOR Roundcube +# EDITOR_VERSION 123 +'; + +$s = new rcube_sieve_script($txt, array('body')); +echo $s->as_text(); + +?> +--EXPECT-- +# EDITOR Roundcube +# EDITOR_VERSION 123 diff --git a/plugins/managesieve/tests/parser_prefix.phpt b/plugins/managesieve/tests/parser_prefix.phpt new file mode 100644 index 0000000..c87e965 --- /dev/null +++ b/plugins/managesieve/tests/parser_prefix.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test of prefix comments handling +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +# this is a comment +# and the second line + +require ["variables"]; +set "b" "c"; +'; + +$s = new rcube_sieve_script($txt, array(), array('variables')); +echo $s->as_text(); + +?> +--EXPECT-- +# this is a comment +# and the second line + +require ["variables"]; +set "b" "c"; diff --git a/plugins/managesieve/tests/parser_relational.phpt b/plugins/managesieve/tests/parser_relational.phpt new file mode 100644 index 0000000..6b6f29f --- /dev/null +++ b/plugins/managesieve/tests/parser_relational.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test of Sieve relational extension (RFC5231) +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["relational","comparator-i;ascii-numeric"]; +# rule:[redirect] +if header :value "ge" :comparator "i;ascii-numeric" + ["X-Spam-score"] ["14"] {redirect "test@test.tld";} +'; + +$s = new rcube_sieve_script($txt); +echo $s->as_text(); + +?> +--EXPECT-- +require ["relational","comparator-i;ascii-numeric"]; +# rule:[redirect] +if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-score" "14" +{ + redirect "test@test.tld"; +} diff --git a/plugins/managesieve/tests/parser_vacation.phpt b/plugins/managesieve/tests/parser_vacation.phpt new file mode 100644 index 0000000..a603ff6 --- /dev/null +++ b/plugins/managesieve/tests/parser_vacation.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test of Sieve vacation extension (RFC5230) +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["vacation"]; +# rule:[test-vacation] +if anyof (header :contains "Subject" "vacation") +{ + vacation :days 1 text: +# test +test test /* test */ +test +. +; + stop; +} +'; + +$s = new rcube_sieve_script($txt); +echo $s->as_text(); + +?> +--EXPECT-- +require ["vacation"]; +# rule:[test-vacation] +if header :contains "Subject" "vacation" +{ + vacation :days 1 text: +# test +test test /* test */ +test +. +; + stop; +} diff --git a/plugins/managesieve/tests/parser_variables.phpt b/plugins/managesieve/tests/parser_variables.phpt new file mode 100644 index 0000000..cf1f8fc --- /dev/null +++ b/plugins/managesieve/tests/parser_variables.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test of Sieve variables extension +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["variables"]; +set "honorific" "Mr"; +set "vacation" text: +Dear ${HONORIFIC} ${last_name}, +I am out, please leave a message after the meep. +. +; +set :length "b" "${a}"; +set :lower "b" "${a}"; +set :upperfirst "b" "${a}"; +set :upperfirst :lower "b" "${a}"; +set :quotewildcard "b" "Rock*"; +'; + +$s = new rcube_sieve_script($txt, array(), array('variables')); +echo $s->as_text(); + +?> +--EXPECT-- +require ["variables"]; +set "honorific" "Mr"; +set "vacation" text: +Dear ${HONORIFIC} ${last_name}, +I am out, please leave a message after the meep. +. +; +set :length "b" "${a}"; +set :lower "b" "${a}"; +set :upperfirst "b" "${a}"; +set :upperfirst :lower "b" "${a}"; +set :quotewildcard "b" "Rock*"; diff --git a/plugins/managesieve/tests/parset_subaddress.phpt b/plugins/managesieve/tests/parset_subaddress.phpt new file mode 100644 index 0000000..6d4d03c --- /dev/null +++ b/plugins/managesieve/tests/parset_subaddress.phpt @@ -0,0 +1,38 @@ +--TEST-- +Test of Sieve subaddress extension (RFC5233) +--SKIPIF-- +--FILE-- +<?php +include '../lib/rcube_sieve_script.php'; + +$txt = ' +require ["envelope","subaddress","fileinto"]; +if envelope :user "To" "postmaster" +{ + fileinto "postmaster"; + stop; +} +if envelope :detail :is "To" "mta-filters" +{ + fileinto "mta-filters"; + stop; +} +'; + +$s = new rcube_sieve_script($txt); +echo $s->as_text(); + +// ------------------------------------------------------------------------------- +?> +--EXPECT-- +require ["envelope","subaddress","fileinto"]; +if envelope :user "To" "postmaster" +{ + fileinto "postmaster"; + stop; +} +if envelope :detail :is "To" "mta-filters" +{ + fileinto "mta-filters"; + stop; +} diff --git a/plugins/new_user_dialog/localization/bg_BG.inc b/plugins/new_user_dialog/localization/bg_BG.inc new file mode 100644 index 0000000..9dc0452 --- /dev/null +++ b/plugins/new_user_dialog/localization/bg_BG.inc @@ -0,0 +1,7 @@ +<?php + +$labels = array(); +$labels['identitydialogtitle'] = 'ÐÐ¾Ð»Ñ Ð¿Ð¾Ð¿ÑлнеÑе ÐаÑиÑе данни.'; +$labels['identitydialoghint'] = 'Това ÑÑобÑение Ñе поÑвÑва Ñамо пÑи пÑÑвоÑо влизане.'; + +?> \ No newline at end of file diff --git a/plugins/newmail_notifier/config.inc.php.dist b/plugins/newmail_notifier/config.inc.php.dist index 21b3d96..067fe19 100644 --- a/plugins/newmail_notifier/config.inc.php.dist +++ b/plugins/newmail_notifier/config.inc.php.dist @@ -6,4 +6,7 @@ $rcmail_config['newmail_notifier_basic'] = false; // Enables sound notification $rcmail_config['newmail_notifier_sound'] = false; +// Enables desktop notification +$rcmail_config['newmail_notifier_desktop'] = false; + ?> diff --git a/plugins/newmail_notifier/localization/de_CH.inc b/plugins/newmail_notifier/localization/de_CH.inc new file mode 100644 index 0000000..55cfd71 --- /dev/null +++ b/plugins/newmail_notifier/localization/de_CH.inc @@ -0,0 +1,13 @@ +<?php + +$labels['basic'] = 'Anzeige im Browser bei neuer Nachricht'; +$labels['sound'] = 'Akustische Meldung bei neuer Nachricht'; +$labels['desktop'] = 'Desktop-Benachrichtigung bei neuer Nachricht'; +$labels['test'] = 'Test'; +$labels['title'] = 'Neue E-Mail!'; +$labels['body'] = 'Sie haben eine neue Nachricht'; +$labels['testbody'] = 'Dies ist eine Testbenachrichtigung'; +$labels['desktopdisabled'] = 'Desktop-Benachrichtigungen sind deaktiviert.'; +$labels['desktopunsupported'] = 'Ihr Browser unterstützt keine Desktop-Benachrichtigungen.'; + +?> diff --git a/plugins/newmail_notifier/localization/de_DE.inc b/plugins/newmail_notifier/localization/de_DE.inc new file mode 100644 index 0000000..65381ca --- /dev/null +++ b/plugins/newmail_notifier/localization/de_DE.inc @@ -0,0 +1,13 @@ +<?php + +$labels['basic'] = 'Benachrichtigung im Browser bei neuer Nachricht'; +$labels['sound'] = 'Akustische Meldung bei neuer Nachricht'; +$labels['desktop'] = 'Desktop-Benachrichtigung bei neuer Nachricht'; +$labels['test'] = 'Test'; +$labels['title'] = 'Neue E-Mail!'; +$labels['body'] = 'Sie haben eine neue Nachricht'; +$labels['testbody'] = 'Dies ist eine Testbenachrichtigung'; +$labels['desktopdisabled'] = 'Desktop-Benachrichtigungen sind deaktiviert.'; +$labels['desktopunsupported'] = 'Ihr Browser unterstützt keine Desktop-Benachrichtigungen.'; + +?> diff --git a/plugins/newmail_notifier/localization/en_US.inc b/plugins/newmail_notifier/localization/en_US.inc index fbb5d9a..3017c43 100644 --- a/plugins/newmail_notifier/localization/en_US.inc +++ b/plugins/newmail_notifier/localization/en_US.inc @@ -1,6 +1,13 @@ <?php -$labels['basic'] = 'Display notifications on new message'; +$labels['basic'] = 'Display browser notifications on new message'; +$labels['desktop'] = 'Display desktop notifications on new message'; $labels['sound'] = 'Play the sound on new message'; +$labels['test'] = 'Test'; +$labels['title'] = 'New Email!'; +$labels['body'] = 'You\'ve received a new message.'; +$labels['testbody'] = 'This is a test notification.'; +$labels['desktopdisabled'] = 'Desktop notifications are disabled in your browser.'; +$labels['desktopunsupported'] = 'Your browser does not support desktop notifications.'; ?> diff --git a/plugins/newmail_notifier/localization/lv_LV.inc b/plugins/newmail_notifier/localization/lv_LV.inc new file mode 100644 index 0000000..bab30f5 --- /dev/null +++ b/plugins/newmail_notifier/localization/lv_LV.inc @@ -0,0 +1,13 @@ +<?php + +$labels['basic'] = 'AttÄlot paziÅojumu pie jaunas vÄstules saÅemÅ¡anas'; +$labels['desktop'] = 'AttÄlot darbvirsmas paziÅojumu pie jaunas vÄstules saÅemÅ¡anas'; +$labels['sound'] = 'AtskaÅot skaÅas signÄlu pie jaunas vÄstules saÅemÅ¡anas'; +$labels['test'] = 'Test'; +$labels['title'] = 'Jauns E-pasts!'; +$labels['body'] = 'JÅ«s esat saÅÄmis jaunu e-pastu.'; +$labels['testbody'] = 'Å is ir testa paziÅojums.'; +$labels['desktopdisabled'] = 'Darbvirsmas paziÅojumi ir atslÄgti JÅ«su pÄrlÅ«kprogrammÄ.'; +$labels['desktopunsupported'] = 'JÅ«su pÄrlÅ«kprogramma neatbalsta darbvirsmas paziÅojumus.'; + +?> diff --git a/plugins/newmail_notifier/localization/pl_PL.inc b/plugins/newmail_notifier/localization/pl_PL.inc index 5fe3790..d95e658 100644 --- a/plugins/newmail_notifier/localization/pl_PL.inc +++ b/plugins/newmail_notifier/localization/pl_PL.inc @@ -1,6 +1,13 @@ <?php -$labels['basic'] = 'WyÅwietlaj powiadomienia o nadejÅciu nowej wiadomoÅci'; +$labels['basic'] = 'WyÅwietlaj powiadomienia o nadejÅciu nowej wiadomoÅci w przeglÄ darce'; $labels['sound'] = 'Odtwarzaj dźwiÄk o nadejÅciu nowej wiadomoÅci'; +$labels['desktop'] = 'WyÅwietlaj powiadomienia o nadejÅciu nowej wiadomoÅci na pulpicie'; +$labels['test'] = 'Testuj powiadomienie'; +$labels['title'] = 'Nowa wiadomoÅÄ!'; +$labels['body'] = 'NadeszÅa nowa wiadomoÅÄ.'; +$labels['testbody'] = 'To jest testowe powiadomienie.'; +$labels['desktopdisabled'] = 'Powiadomienia na pulpicie zostaÅy zablokowane w twojej przeglÄ darce.'; +$labels['desktopunsupported'] = 'Twoja przeglÄ darka nie obsÅuguje powiadomieÅ na pulpicie.'; ?> diff --git a/plugins/newmail_notifier/localization/pt_BR.inc b/plugins/newmail_notifier/localization/pt_BR.inc new file mode 100644 index 0000000..66f8e93 --- /dev/null +++ b/plugins/newmail_notifier/localization/pt_BR.inc @@ -0,0 +1,13 @@ +<?php + +$labels['basic'] = 'Exibir notificação quando uma nova mensagem chegar'; +$labels['desktop'] = 'Exibir notificação no desktop quando uma nova mensagem chegar'; +$labels['sound'] = 'Alerta sonoro quando uma nova mensagem chegar'; +$labels['test'] = 'Testar'; +$labels['title'] = 'Novo Email!'; +$labels['body'] = 'Você recebeu uma nova mensagem.'; +$labels['testbody'] = 'Essa é uma notificação de teste.'; +$labels['desktopdisabled'] = 'As notificações no desktop estão desabilitadas no seu navegador.'; +$labels['desktopunsupported'] = 'Seu navegador não suporta notificações no desktop'; + +?> diff --git a/plugins/newmail_notifier/localization/ru_RU.inc b/plugins/newmail_notifier/localization/ru_RU.inc new file mode 100644 index 0000000..65abb74 --- /dev/null +++ b/plugins/newmail_notifier/localization/ru_RU.inc @@ -0,0 +1,21 @@ +<?php + +/* ++-----------------------------------------------------------------------+ +| language/ru_RU/labels.inc | +| | +| Language file of the RoundCube Webmail client | +| Copyright (C) 2008-2011, RoundQube Dev. - Switzerland | +| Licensed under the GNU GPL | +| | ++-----------------------------------------------------------------------+ +| Author: Doubrovine S. | ++-----------------------------------------------------------------------+ + +*/ + +$labels = array(); +$labels['basic'] = 'ÐизÑалÑное Ñведомление по пÑÐ¸Ñ Ð¾Ð´Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑообÑениÑ'; +$labels['sound'] = 'ÐвÑковое Ñведомление по пÑÐ¸Ñ Ð¾Ð´Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑообÑениÑ'; + +?> \ No newline at end of file diff --git a/plugins/newmail_notifier/mail.png b/plugins/newmail_notifier/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..79f3a53115512a2315cb69f0e345eb64a0b2c541 GIT binary patch literal 1408 zcmV-`1%LX9P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2ipl2 z3=tY@?hkMP00jU^L_t(o!|j(_ZyQAzhM(D!ch;x4X{k7bkOCDw#%{$aDToUskU)sT zZ>#tVsMq`gD#Q&XZKEDir#aM75|YMlY_AXT9JtunPMijA3S7V^eLJ%=-|qX)JM+!X z!vFSPH}Uy|Hx*^FKen2U^Zz7pl*!(2H5*@g>0Ivn%O8ArZsxNuIQjBxoSiP>`~D!% z9=I}Ex1)W}zaO+%%Y$3LvbMCy-CurrXYS{l*B!OD_hIRykHy5>myqc(HY@8G>mVE- z91r2R2;m`wixAGB1P6ow(Jzm}T1*0O4Oqj&+rP2#WEIDCIa?|^y>55b>2^A~PrmvF zKkzYD(`m)5JzhksJun)K!CJlV25U6dXt0S}qXuo(swB>+1MNwD;r1=oSC+6=A=8pi zzx|qSr;~F4f|SS0lM{*b*3ga{R2Iu<-NRZn1hWduK8RIGA8Jrfy#GwU-eckJTmo)- z$VgJU_5nf4g+xcNM&r7ISKgSw3p}hfw3-c`ESAw)4HV$WNc(E2!=pZMU%qpfjpb#G z(a1<roP7`9cd<qtAYe6EgXcNCIyH$Ocv!26>$^NDKf>r<0!Uv8Ju>Q~Z?wHUKR=W` zN-;h2E`G{8px%JMaFm`Wc<s$e{J_UrO>_4dtK~Ar^o9@iK^V%;zTACZyf@Fr>M|Bh z7=>J(xk`|7ux1!@NP&ayxegO=4V9?Zs;n-Qv3e-|U^<M#=pIIQF}j1%9Tw*1SXp>T zx6{P+;Ntt2@jZdjdswrVkl3FBFUc7N7_dp|U@e~KFnM;0<p*WD?Kah|O}d?3&YU{~ zBvWRsIg<Aax9_pGw7S39q$$pn2m)s?;!*R4Q=q`w{R}o(-9^yll{a$y_R~Dg-8ukq zeVy}HFC&CF^0I|H_gQ=VWFI`D^wCv<lzS}rkibC7Hb%EFx{b9Otu))~zcYFEb(Zdz zX*XMJuC5`loV#-I(2E}3eJ}u*nTV-#XV}@?;`FPhaa`wE0uF%c)#$`a>~+>ry=NHH z#ac!6={D`SiRyJJ&0Zl)hgb~js}&y3%@34YxO0!n;}t9hnGPw<UP1M`wBrWV?d_3_ zQHQd?12Cq2gjuh<N26B7S{NHYNf0`eu1zy{^A@eR&D!!R!Z83;9#<0C(~{z~X@byU zY&^?mC8l26A(IaYQo->G3^$RXZ*Od2j3UZ}gwn?vMG&|YXQz=-3aqBGxI$%d1*}F! zDT=ex1VOUNgwiL<gczfEy0P_KjFEj{=*{{r?N$>Z424tKLw!NYr8skmPzK4j!5YFS zMRDfR{(>9E7EWam!q9Fti5vCjPJuK0geGo`p}JKCEcp{TJkLGU50;b+D9%okk^xah zQo5GZN8>!tC4V9ZSayEj!5A|V)87XUSiQE3QVP%W$QAO(uHG;TDb5t}JeMF0j*ZI| z@-&_`QA$y-?J_n#c61H&O)150HOcoAFBNbc@fW8W`KRCjjw3knQUQQx)jCS4;|Wx^ zY8Yb(r6iqAzp&$1I-4ex5^D_At=jVmwBrtOBSr|p$<u`weg-^wx_}UZxDnH7b&e9K z?Ig@H`7C}ac;N*6R6r)5O_Y8*RKbxMseZVAgD5QtrKB*P|JzQ&h4DP0ltgLC57%!X zGg67~F61%V+-t|}fAm-`)AGLKIv2dS9wXE8!oTrT64&FY|9{Q?b^8N=$DF{xt9qOO O0000<MNUMnLSTZ#zoV)E literal 0 HcmV?d00001 diff --git a/plugins/newmail_notifier/newmail_notifier.js b/plugins/newmail_notifier/newmail_notifier.js index 6afd66a..16e3edd 100644 --- a/plugins/newmail_notifier/newmail_notifier.js +++ b/plugins/newmail_notifier/newmail_notifier.js @@ -1,7 +1,7 @@ /** * New Mail Notifier plugin script * - * @version 0.2 + * @version 0.3 * @author Aleksander Machniak <alec@alec.pl> */ @@ -22,6 +22,8 @@ function newmail_notifier_run(prop) newmail_notifier_basic(); if (prop.sound) newmail_notifier_sound(); + if (prop.desktop) + newmail_notifier_desktop(rcmail.gettext('body', 'newmail_notifier')); } // Stops notification @@ -37,11 +39,13 @@ function newmail_notifier_stop(prop) // Basic notification: window.focus and favicon change function newmail_notifier_basic() { - window.focus(); + var w = rcmail.is_framed() ? window.parent : window; + + w.focus(); // we cannot simply change a href attribute, we must to replace the link element (at least in FF) var link = $('<link rel="shortcut icon" href="plugins/newmail_notifier/favicon.ico"/>'), - oldlink = $('link[rel="shortcut icon"]'); + oldlink = $('link[rel="shortcut icon"]', w.document); rcmail.env.favicon_href = oldlink.attr('href'); link.replaceAll(oldlink); @@ -64,3 +68,53 @@ function newmail_notifier_sound() window.setTimeout("$('#sound').remove()", 5000); } } + +// Desktop notification (need Chrome or Firefox with a plugin) +function newmail_notifier_desktop(body) +{ + var dn = window.webkitNotifications; + + if (dn && !dn.checkPermission()) { + if (rcmail.newmail_popup) + rcmail.newmail_popup.cancel(); + var popup = window.webkitNotifications.createNotification('plugins/newmail_notifier/mail.png', + rcmail.gettext('title', 'newmail_notifier'), body); + popup.onclick = function() { + this.cancel(); + } + popup.show(); + setTimeout(function() { popup.cancel(); }, 10000); // close after 10 seconds + rcmail.newmail_popup = popup; + return true; + } + + return false; +} + +function newmail_notifier_test_desktop() +{ + var dn = window.webkitNotifications, + txt = rcmail.gettext('testbody', 'newmail_notifier'); + + if (dn) { + if (!dn.checkPermission()) + newmail_notifier_desktop(txt); + else + dn.requestPermission(function() { + if (!newmail_notifier_desktop(txt)) + rcmail.display_message(rcmail.gettext('desktopdisabled', 'newmail_notifier'), 'error'); + }); + } + else + rcmail.display_message(rcmail.gettext('desktopunsupported', 'newmail_notifier'), 'error'); +} + +function newmail_notifier_test_basic() +{ + newmail_notifier_basic(); +} + +function newmail_notifier_test_sound() +{ + newmail_notifier_sound(); +} diff --git a/plugins/newmail_notifier/newmail_notifier.php b/plugins/newmail_notifier/newmail_notifier.php index a72d728..01e2598 100644 --- a/plugins/newmail_notifier/newmail_notifier.php +++ b/plugins/newmail_notifier/newmail_notifier.php @@ -6,8 +6,10 @@ * Supports two methods of notification: * 1. Basic - focus browser window and change favicon * 2. Sound - play wav file + * 3. Desktop - display desktop notification (using webkitNotifications feature, + * supported by Chrome and Firefox with 'HTML5 Notifications' plugin) * - * @version 0.2 + * @version 0.3 * @author Aleksander Machniak <alec@alec.pl> * * @@ -32,6 +34,7 @@ class newmail_notifier extends rcube_plugin public $task = 'mail|settings'; private $rc; + private $notified; /** * Plugin initialization @@ -49,6 +52,8 @@ class newmail_notifier extends rcube_plugin $this->add_hook('new_messages', array($this, 'notify')); // add script when not in ajax and not in frame if (is_a($this->rc->output, 'rcube_template') && empty($_REQUEST['_framed'])) { + $this->add_texts('localization/'); + $this->rc->output->add_label('newmail_notifier.title', 'newmail_notifier.body'); $this->include_script('newmail_notifier.js'); } } @@ -69,27 +74,29 @@ class newmail_notifier extends rcube_plugin // Load localization and configuration $this->add_texts('localization/'); - // Check that configuration is not disabled - $dont_override = (array) $this->rc->config->get('dont_override', array()); - $basic_override = in_array('newmail_notifier_basic', $dont_override); - $sound_override = in_array('newmail_notifier_sound', $dont_override); - - if (!$basic_override) { - $field_id = '_newmail_notifier_basic'; - $input = new html_checkbox(array('name' => $field_id, 'id' => $field_id, 'value' => 1)); - $args['blocks']['new_message']['options']['newmail_notifier_basic'] = array( - 'title' => html::label($field_id, Q($this->gettext('basic'))), - 'content' => $input->show($this->rc->config->get('newmail_notifier_basic')), - ); + if (!empty($_REQUEST['_framed'])) { + $this->rc->output->add_label('newmail_notifier.title', 'newmail_notifier.testbody', + 'newmail_notifier.desktopunsupported', 'newmail_notifier.desktopenabled', 'newmail_notifier.desktopdisabled'); + $this->include_script('newmail_notifier.js'); } - if (!$sound_override) { - $field_id = '_newmail_notifier_sound'; - $input = new html_checkbox(array('name' => $field_id, 'id' => $field_id, 'value' => 1)); - $args['blocks']['new_message']['options']['newmail_notifier_sound'] = array( - 'title' => html::label($field_id, Q($this->gettext('sound'))), - 'content' => $input->show($this->rc->config->get('newmail_notifier_sound')), - ); + // Check that configuration is not disabled + $dont_override = (array) $this->rc->config->get('dont_override', array()); + + foreach (array('basic', 'desktop', 'sound') as $type) { + $key = 'newmail_notifier_' . $type; + if (!in_array($key, $dont_override)) { + $field_id = '_' . $key; + $input = new html_checkbox(array('name' => $field_id, 'id' => $field_id, 'value' => 1)); + $content = $input->show($this->rc->config->get($key)) + . ' ' . html::a(array('href' => '#', 'onclick' => 'newmail_notifier_test_'.$type.'()'), + $this->gettext('test')); + + $args['blocks']['new_message']['options'][$key] = array( + 'title' => html::label($field_id, Q($this->gettext($type))), + 'content' => $content + ); + } } return $args; @@ -108,17 +115,13 @@ class newmail_notifier extends rcube_plugin $this->load_config(); // Check that configuration is not disabled - $dont_override = (array) $this->rc->config->get('dont_override', array()); - $basic_override = in_array('newmail_notifier_basic', $dont_override); - $sound_override = in_array('newmail_notifier_sound', $dont_override); + $dont_override = (array) $this->rc->config->get('dont_override', array()); - if (!$basic_override) { - $key = 'newmail_notifier_basic'; - $args['prefs'][$key] = get_input_value('_'.$key, RCUBE_INPUT_POST) ? true : false; - } - if (!$sound_override) { - $key = 'newmail_notifier_sound'; - $args['prefs'][$key] = get_input_value('_'.$key, RCUBE_INPUT_POST) ? true : false; + foreach (array('basic', 'desktop', 'sound') as $type) { + $key = 'newmail_notifier_' . $type; + if (!in_array($key, $dont_override)) { + $args['prefs'][$key] = get_input_value('_'.$key, RCUBE_INPUT_POST) ? true : false; + } } return $args; @@ -129,15 +132,22 @@ class newmail_notifier extends rcube_plugin */ function notify($args) { + if ($this->notified || !empty($_GET['_refresh'])) { + return $args; + } + + $this->notified = true; + // Load configuration $this->load_config(); - $basic = $this->rc->config->get('newmail_notifier_basic'); - $sound = $this->rc->config->get('newmail_notifier_sound'); + $basic = $this->rc->config->get('newmail_notifier_basic'); + $sound = $this->rc->config->get('newmail_notifier_sound'); + $desktop = $this->rc->config->get('newmail_notifier_desktop'); - if ($basic || $sound) { + if ($basic || $sound || $desktop) { $this->rc->output->command('plugin.newmail_notifier', - array('basic' => $basic, 'sound' => $sound)); + array('basic' => $basic, 'sound' => $sound, 'desktop' => $desktop)); } return $args; diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist index 94af6d7..313e47f 100644 --- a/plugins/password/config.inc.php.dist +++ b/plugins/password/config.inc.php.dist @@ -47,6 +47,10 @@ $rcmail_config['password_db_dsn'] = ''; // Default: "SELECT update_passwd(%c, %u)" $rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)'; +// By default domains in variables are using unicode. +// Enable this option to use punycoded names +$rcmail_config['password_idn_ascii'] = false; + // Path for dovecotpw (if not in $PATH) // $rcmail_config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw'; diff --git a/plugins/password/drivers/ldap.php b/plugins/password/drivers/ldap.php index 3ea30a6..e6450e5 100644 --- a/plugins/password/drivers/ldap.php +++ b/plugins/password/drivers/ldap.php @@ -272,6 +272,7 @@ function hashPassword( $passwordClear, $encodageType ) case 'samba': if (function_exists('hash')) { $cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE')); + $cryptedPassword = strtoupper($cryptedPassword); } else { /* Your PHP install does not have the hash() function */ return false; diff --git a/plugins/password/drivers/ldap_simple.php b/plugins/password/drivers/ldap_simple.php index 482b7e5..2f51b75 100644 --- a/plugins/password/drivers/ldap_simple.php +++ b/plugins/password/drivers/ldap_simple.php @@ -238,6 +238,7 @@ function ldap_simple_hash_password($password_clear, $encodage_type) case 'samba': if (function_exists('hash')) { $crypted_password = hash('md4', rcube_charset_convert($password_clear, RCMAIL_CHARSET, 'UTF-16LE')); + $crypted_password = strtoupper($crypted_password); } else { /* Your PHP install does not have the hash() function */ return false; diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index 9ea33df..06a6b75 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -5,7 +5,7 @@ * * Driver for passwords stored in SQL database * - * @version 1.3 + * @version 1.4 * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> * */ @@ -37,16 +37,21 @@ function password_save($curpass, $passwd) // crypted password if (strpos($sql, '%c') !== FALSE) { $salt = ''; - if (CRYPT_MD5) { - $len = rand(3, CRYPT_SALT_LENGTH); + if (CRYPT_MD5) { + // Always use eight salt characters for MD5 (#1488136) + $len = 8; } else if (CRYPT_STD_DES) { $len = 2; } else { return PASSWORD_CRYPT_ERROR; } + + //Restrict the character set used as salt (#1488136) + $seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; for ($i = 0; $i < $len ; $i++) { - $salt .= chr(rand(ord('.'), ord('z'))); + $salt .= $seedchars[rand(0, 63)]; } + $sql = str_replace('%c', $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $sql); } @@ -61,7 +66,7 @@ function password_save($curpass, $passwd) $tmp_dir = $rcmail->config->get('temp_dir'); $tmpfile = tempnam($tmp_dir, 'roundcube-'); - $pipe = popen("'$dovecotpw' -s '$method' > '$tmpfile'", "w"); + $pipe = popen("$dovecotpw -s '$method' > '$tmpfile'", "w"); if (!$pipe) { unlink($tmpfile); return PASSWORD_CRYPT_ERROR; @@ -97,15 +102,15 @@ function password_save($curpass, $passwd) if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) $hash_algo = 'sha1'; - + $hash_passwd = hash($hash_algo, $passwd); $hash_curpass = hash($hash_algo, $curpass); - + if ($rcmail->config->get('password_hash_base64')) { $hash_passwd = base64_encode(pack('H*', $hash_passwd)); $hash_curpass = base64_encode(pack('H*', $hash_curpass)); } - + $sql = str_replace('%n', $db->quote($hash_passwd, 'text'), $sql); $sql = str_replace('%q', $db->quote($hash_curpass, 'text'), $sql); } @@ -125,11 +130,28 @@ function password_save($curpass, $passwd) } } + $local_part = $rcmail->user->get_username('local'); + $domain_part = $rcmail->user->get_username('domain'); + $username = $_SESSION['username']; + $host = $_SESSION['imap_host']; + + // convert domains to/from punnycode + if ($rcmail->config->get('password_idn_ascii')) { + $domain_part = rcube_idn_to_ascii($domain_part); + $username = rcube_idn_to_ascii($username); + $host = rcube_idn_to_ascii($host); + } + else { + $domain_part = rcube_idn_to_utf8($domain_part); + $username = rcube_idn_to_utf8($username); + $host = rcube_idn_to_utf8($host); + } + // at least we should always have the local part - $sql = str_replace('%l', $db->quote($rcmail->user->get_username('local'), 'text'), $sql); - $sql = str_replace('%d', $db->quote($rcmail->user->get_username('domain'), 'text'), $sql); - $sql = str_replace('%u', $db->quote($_SESSION['username'],'text'), $sql); - $sql = str_replace('%h', $db->quote($_SESSION['imap_host'],'text'), $sql); + $sql = str_replace('%l', $db->quote($local_part, 'text'), $sql); + $sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql); + $sql = str_replace('%u', $db->quote($username, 'text'), $sql); + $sql = str_replace('%h', $db->quote($host, 'text'), $sql); $res = $db->query($sql, $sql_vars); diff --git a/plugins/password/package.xml b/plugins/password/package.xml index a4f74c1..45688e1 100644 --- a/plugins/password/package.xml +++ b/plugins/password/package.xml @@ -15,10 +15,9 @@ <email>alec@alec.pl</email> <active>yes</active> </lead> - <date></date> - <time></time> + <date>2011-11-23</date> <version> - <release></release> + <release>2.4</release> <api>1.6</api> </version> <stability> @@ -27,9 +26,8 @@ </stability> <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> <notes> -- When old and new passwords are the same, do nothing, return success (#1487823) -- Fixed Samba password hashing in 'ldap' driver -- Added 'password_change' hook for plugin actions after successful password change +- Added option to use punycode or unicode for domain names (#1488103) +- Save Samba password hashes in capital letters (#1488197) </notes> <contents> <dir baseinstalldir="/" name="/"> @@ -53,21 +51,27 @@ <file name="localization/de_CH.inc" role="data"></file> <file name="localization/de_DE.inc" role="data"></file> <file name="localization/en_US.inc" role="data"></file> + <file name="localization/es_AR.inc" role="data"></file> <file name="localization/es_ES.inc" role="data"></file> <file name="localization/et_EE.inc" role="data"></file> <file name="localization/fi_FI.inc" role="data"></file> <file name="localization/fr_FR.inc" role="data"></file> <file name="localization/gl_ES.inc" role="data"></file> + <file name="localization/hr_HR.inc" role="data"></file> <file name="localization/hu_HU.inc" role="data"></file> <file name="localization/it_IT.inc" role="data"></file> + <file name="localization/ja_JA.inc" role="data"></file> <file name="localization/lt_LT.inc" role="data"></file> <file name="localization/lv_LV.inc" role="data"></file> <file name="localization/nl_NL.inc" role="data"></file> <file name="localization/pl_PL.inc" role="data"></file> <file name="localization/pt_BR.inc" role="data"></file> <file name="localization/pt_PT.inc" role="data"></file> + <file name="localization/ru_RU.inc" role="data"></file> + <file name="localization/sk_SK.inc" role="data"></file> <file name="localization/sl_SI.inc" role="data"></file> <file name="localization/sv_SE.inc" role="data"></file> + <file name="localization/tr_TR.inc" role="data"></file> <file name="localization/zh_TW.inc" role="data"></file> <file name="drivers/chgsaslpasswd.c" role="data"></file> @@ -263,5 +267,25 @@ - Virtualmin driver: Add option for setting username format (#1487781) </notes> </release> + <release> + <date>2011-10-26</date> + <time>12:00</time> + <version> + <release>2.3</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- When old and new passwords are the same, do nothing, return success (#1487823) +- Fixed Samba password hashing in 'ldap' driver +- Added 'password_change' hook for plugin actions after successful password change +- Fixed bug where 'doveadm pw' command was used as dovecotpw utility +- Improve generated crypt() passwords (#1488136) + </notes> + </release> </changelog> </package> diff --git a/plugins/password/password.php b/plugins/password/password.php index b1c7863..06e3448 100644 --- a/plugins/password/password.php +++ b/plugins/password/password.php @@ -223,7 +223,7 @@ class password extends rcube_plugin { $config = rcmail::get_instance()->config; $driver = $this->home.'/drivers/'.$config->get('password_driver', 'sql').'.php'; - + if (!is_readable($driver)) { raise_error(array( 'code' => 600, @@ -233,7 +233,7 @@ class password extends rcube_plugin ), true, false); return $this->gettext('internalerror'); } - + include($driver); if (!function_exists('password_save')) { @@ -270,5 +270,5 @@ class password extends rcube_plugin } return $reason; - } + } } diff --git a/plugins/userinfo/localization/fr_FR.inc b/plugins/userinfo/localization/fr_FR.inc new file mode 100644 index 0000000..ef7b8aa --- /dev/null +++ b/plugins/userinfo/localization/fr_FR.inc @@ -0,0 +1,9 @@ +<?php + +$labels = array(); +$labels['userinfo'] = 'Info utilisateur'; +$labels['created'] = 'Date de création'; +$labels['lastlogin'] = 'Dernière connexion'; +$labels['defaultidentity'] = 'Identité principale'; + +?> diff --git a/plugins/userinfo/localization/ro_RO.inc b/plugins/userinfo/localization/ro_RO.inc new file mode 100644 index 0000000..bf7a476 --- /dev/null +++ b/plugins/userinfo/localization/ro_RO.inc @@ -0,0 +1,9 @@ +<?php + +$labels = array(); +$labels['userinfo'] = 'Informatii utilisator'; +$labels['created'] = 'Data creatiei'; +$labels['lastlogin'] = 'Ultima conectare'; +$labels['defaultidentity'] = 'Identitate principala'; + +?> diff --git a/program/include/clisetup.php b/program/include/clisetup.php index 8d01bb1..ae90562 100644 --- a/program/include/clisetup.php +++ b/program/include/clisetup.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: clisetup.php 4678 2011-04-20 13:58:21Z alec $ + $Id: clisetup.php 5299 2011-10-03 09:25:33Z alec $ */ @@ -25,6 +25,8 @@ if (php_sapi_name() != 'cli') { require_once INSTALL_PATH . 'program/include/iniset.php'; +// Unset max. execution time limit, set to 120 seconds in iniset.php +@set_time_limit(0); /** * Parse commandline arguments into a hash array diff --git a/program/include/iniset.php b/program/include/iniset.php index 10ae11e..d8ead56 100755 --- a/program/include/iniset.php +++ b/program/include/iniset.php @@ -16,7 +16,7 @@ | Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: iniset.php 5292 2011-09-28 19:16:41Z thomasb $ + $Id: iniset.php 5582 2011-12-09 08:55:40Z thomasb $ */ @@ -37,7 +37,7 @@ foreach ($crit_opts as $optname => $optval) { } // application constants -define('RCMAIL_VERSION', '0.6'); +define('RCMAIL_VERSION', '0.7'); define('RCMAIL_CHARSET', 'UTF-8'); define('JS_OBJECT_NAME', 'rcmail'); define('RCMAIL_START', microtime(true)); diff --git a/program/include/main.inc b/program/include/main.inc index 30d9099..f929762 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: main.inc 5151 2011-08-31 12:49:44Z alec $ + $Id: main.inc 5591 2011-12-10 14:16:31Z thomasb $ */ @@ -97,9 +97,9 @@ function rcube_label($p, $domain=null) * * @see rcmail::text_exists() */ -function rcube_label_exists($name, $domain=null) +function rcube_label_exists($name, $domain=null, &$ref_domain = null) { - return rcmail::get_instance()->text_exists($name, $domain); + return rcmail::get_instance()->text_exists($name, $domain, $ref_domain); } @@ -169,11 +169,17 @@ function rcmail_cache_gc() // get target timestamp $ts = get_offset_time($rcmail->config->get('message_cache_lifetime', '30d'), -1); - $db->query("DELETE FROM ".get_table_name('messages')." - WHERE created < " . $db->fromunixtime($ts)); + $db->query("DELETE FROM ".get_table_name('cache_messages') + ." WHERE changed < " . $db->fromunixtime($ts)); - $db->query("DELETE FROM ".get_table_name('cache')." - WHERE created < " . $db->fromunixtime($ts)); + $db->query("DELETE FROM ".get_table_name('cache_index') + ." WHERE changed < " . $db->fromunixtime($ts)); + + $db->query("DELETE FROM ".get_table_name('cache_thread') + ." WHERE changed < " . $db->fromunixtime($ts)); + + $db->query("DELETE FROM ".get_table_name('cache') + ." WHERE created < " . $db->fromunixtime($ts)); } @@ -634,20 +640,23 @@ function JQ($str) function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL) { $value = NULL; - - if ($source==RCUBE_INPUT_GET && isset($_GET[$fname])) - $value = $_GET[$fname]; - else if ($source==RCUBE_INPUT_POST && isset($_POST[$fname])) - $value = $_POST[$fname]; - else if ($source==RCUBE_INPUT_GPC) - { + + if ($source == RCUBE_INPUT_GET) { + if (isset($_GET[$fname])) + $value = $_GET[$fname]; + } + else if ($source == RCUBE_INPUT_POST) { + if (isset($_POST[$fname])) + $value = $_POST[$fname]; + } + else if ($source == RCUBE_INPUT_GPC) { if (isset($_POST[$fname])) $value = $_POST[$fname]; else if (isset($_GET[$fname])) $value = $_GET[$fname]; else if (isset($_COOKIE[$fname])) $value = $_COOKIE[$fname]; - } + } return parse_input_value($value, $allow_html, $charset); } @@ -655,7 +664,7 @@ function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL) /** * Parse/validate input value. See get_input_value() * Performs stripslashes() and charset conversion if necessary - * + * * @param string Input value * @param boolean Allow HTML tags in field value * @param string Charset to convert into @@ -681,15 +690,21 @@ function parse_input_value($value, $allow_html=FALSE, $charset=NULL) else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) $value = stripslashes($value); - // remove HTML tags if not allowed + // remove HTML tags if not allowed if (!$allow_html) $value = strip_tags($value); - + + $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null; + + // remove invalid characters (#1488124) + if ($output_charset == 'UTF-8') + $value = rc_utf8_clean($value); + // convert to internal charset - if (is_object($OUTPUT) && $charset) - return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset); - else - return $value; + if ($charset && $output_charset) + $value = rcube_charset_convert($value, $output_charset, $charset); + + return $value; } /** @@ -699,15 +714,16 @@ function parse_input_value($value, $allow_html=FALSE, $charset=NULL) * @param int Source to get value from (GPC) * @return array Hash array with all request parameters */ -function request2param($mode = RCUBE_INPUT_GPC) +function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action') { $out = array(); $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST); foreach ($src as $key => $value) { $fname = $key[0] == '_' ? substr($key, 1) : $key; - $out[$fname] = get_input_value($key, $mode); + if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) + $out[$fname] = get_input_value($key, $mode); } - + return $out; } @@ -723,12 +739,14 @@ function asciiwords($str, $css_id = false, $replace_with = '') /** * Convert the given string into a valid HTML identifier - * Same functionality as done in app.js with this.identifier_expr - * + * Same functionality as done in app.js with rcube_webmail.html_identifier() */ -function html_identifier($str) +function html_identifier($str, $encode=false) { - return asciiwords($str, true, '_'); + if ($encode) + return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); + else + return asciiwords($str, true, '_'); } /** @@ -765,52 +783,48 @@ function strip_newlines($str) * @return string HTML table code */ function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col) - { +{ global $RCMAIL; - + $table = new html_table(/*array('cols' => count($a_show_cols))*/); - + // add table header if (!$attrib['noheader']) foreach ($a_show_cols as $col) $table->add_header($col, Q(rcube_label($col))); - + $c = 0; - if (!is_array($table_data)) + if (!is_array($table_data)) { $db = $RCMAIL->get_dbh(); while ($table_data && ($sql_arr = $db->fetch_assoc($table_data))) { - $zebra_class = $c % 2 ? 'even' : 'odd'; - $table->add_row(array('id' => 'rcmrow' . html_identifier($sql_arr[$id_col]), 'class' => $zebra_class)); + $table->add_row(array('id' => 'rcmrow' . html_identifier($sql_arr[$id_col]))); // format each col foreach ($a_show_cols as $col) $table->add($col, Q($sql_arr[$col])); - + $c++; } } - else - { + else { foreach ($table_data as $row_data) { - $zebra_class = $c % 2 ? 'even' : 'odd'; - if (!empty($row_data['class'])) - $zebra_class .= ' '.$row_data['class']; + $class = !empty($row_data['class']) ? $row_data['class'] : ''; - $table->add_row(array('id' => 'rcmrow' . html_identifier($row_data[$id_col]), 'class' => $zebra_class)); + $table->add_row(array('id' => 'rcmrow' . html_identifier($row_data[$id_col]), 'class' => $class)); // format each col foreach ($a_show_cols as $col) $table->add($col, Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col])); - + $c++; } } return $table->show($attrib); - } +} /** @@ -869,23 +883,37 @@ function rcmail_get_edit_field($col, $value, $attrib, $type='text') * @param string Container ID to use as prefix * @return string Modified CSS source */ -function rcmail_mod_css_styles($source, $container_id) +function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) { $last_pos = 0; $replacements = new rcube_string_replacer; // ignore the whole block if evil styles are detected - $stripped = preg_replace('/[^a-z\(:;]/', '', rcmail_xss_entity_decode($source)); - if (preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) + $source = rcmail_xss_entity_decode($source); + $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); + $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); + if (preg_match("/$evilexpr/i", $stripped)) return '/* evil! */'; - // remove css comments (sometimes used for some ugly hacks) - $source = preg_replace('!/\*(.+)\*/!Ums', '', $source); - // cut out all contents between { and } - while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) - { - $key = $replacements->add(substr($source, $pos+1, $pos2-($pos+1))); + while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { + $styles = substr($source, $pos+1, $pos2-($pos+1)); + + // check every line of a style block... + if ($allow_remote) { + $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); + foreach ($a_styles as $line) { + $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); + // ... and only allow strict url() values + if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { + $a_styles = array('/* evil! */'); + break; + } + } + $styles = join(";\n", $a_styles); + } + + $key = $replacements->add($styles); $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); $last_pos = $pos+2; } @@ -923,7 +951,7 @@ function rcmail_xss_entity_decode($content) { $out = html_entity_decode(html_entity_decode($content)); $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out); - $out = preg_replace('#/\*.*\*/#Um', '', $out); + $out = preg_replace('#/\*.*\*/#Ums', '', $out); return $out; } @@ -1015,15 +1043,15 @@ function rcube_strtotime($date) * Convert the given date to a human readable form * This uses the date formatting properties from config * - * @param mixed Date representation (string or timestamp) + * @param mixed Date representation (string or timestamp) * @param string Date format to use + * @param bool Enables date convertion according to user timezone + * * @return string Formatted date string */ -function format_date($date, $format=NULL) +function format_date($date, $format=NULL, $convert=true) { global $RCMAIL, $CONFIG; - - $ts = NULL; if (!empty($date)) $ts = rcube_strtotime($date); @@ -1031,31 +1059,37 @@ function format_date($date, $format=NULL) if (empty($ts)) return ''; - // get user's timezone - $tz = $RCMAIL->config->get_timezone(); - - // convert time to user's timezone - $timestamp = $ts - date('Z', $ts) + ($tz * 3600); + if ($convert) { + // get user's timezone offset + $tz = $RCMAIL->config->get_timezone(); - // get current timestamp in user's timezone - $now = time(); // local time - $now -= (int)date('Z'); // make GMT time - $now += ($tz * 3600); // user's time - $now_date = getdate($now); + // convert time to user's timezone + $timestamp = $ts - date('Z', $ts) + ($tz * 3600); - $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); - $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); + // get current timestamp in user's timezone + $now = time(); // local time + $now -= (int)date('Z'); // make GMT time + $now += ($tz * 3600); // user's time + } + else { + $now = time(); + $timestamp = $ts; + } // define date format depending on current time if (!$format) { + $now_date = getdate($now); + $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']); + $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']); + if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) { - $format = $CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i'; + $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i')); $today = true; } else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now) - $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i'; + $format = $RCMAIL->config->get('date_short', 'D H:i'); else - $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i'; + $format = $RCMAIL->config->get('date_long', 'Y-m-d H:i'); } // strftime() format @@ -1207,9 +1241,9 @@ function rcmail_mailbox_select($p = array()) $p['folder_name'] = '*'; if ($p['unsubscribed']) - $list = $RCMAIL->imap->list_unsubscribed('', $p['folder_name'], $p['folder_filter']); + $list = $RCMAIL->imap->list_unsubscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); else - $list = $RCMAIL->imap->list_mailboxes('', $p['folder_name'], $p['folder_filter']); + $list = $RCMAIL->imap->list_mailboxes('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']); $delimiter = $RCMAIL->imap->get_hierarchy_delimiter(); @@ -1223,7 +1257,7 @@ function rcmail_mailbox_select($p = array()) if ($p['noselection']) $select->add($p['noselection'], ''); - rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p['exceptions']); + rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); return $select; } @@ -1272,11 +1306,6 @@ function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') $path .= $prefix.$currentFolder; if (!isset($arrFolders[$currentFolder])) { - // Check \Noselect option (if options are in cache) - if (!$virtual && ($opts = $RCMAIL->imap->mailbox_options($path))) { - $virtual = in_array('\\Noselect', $opts); - } - $arrFolders[$currentFolder] = array( 'id' => $path, 'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'), @@ -1304,13 +1333,14 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at $realnames = (bool)$attrib['realnames']; $msgcounts = $RCMAIL->imap->get_cache('messagecount'); - $idx = 0; $out = ''; foreach ($arrFolders as $key => $folder) { - $zebra_class = (($nestLevel+1)*$idx) % 2 == 0 ? 'even' : 'odd'; - $title = null; + $title = null; + $folder_class = rcmail_folder_classname($folder['id']); + $collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false; + $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; - if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) { + if ($folder_class && !$realnames) { $foldername = rcube_label($folder_class); } else { @@ -1326,31 +1356,16 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at } // make folder name safe for ids and class names - $folder_id = html_identifier($folder['id']); + $folder_id = html_identifier($folder['id'], true); $classes = array('mailbox'); // set special class for Sent, Drafts, Trash and Junk - if ($folder['id'] == $CONFIG['sent_mbox']) - $classes[] = 'sent'; - else if ($folder['id'] == $CONFIG['drafts_mbox']) - $classes[] = 'drafts'; - else if ($folder['id'] == $CONFIG['trash_mbox']) - $classes[] = 'trash'; - else if ($folder['id'] == $CONFIG['junk_mbox']) - $classes[] = 'junk'; - else if ($folder['id'] == 'INBOX') - $classes[] = 'inbox'; - else - $classes[] = '_'.asciiwords($folder_class ? $folder_class : strtolower($folder['id']), true); - - $classes[] = $zebra_class; + if ($folder_class) + $classes[] = $folder_class; if ($folder['id'] == $mbox_name) $classes[] = 'selected'; - $collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false; - $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0; - if ($folder['virtual']) $classes[] = 'virtual'; else if ($unread) @@ -1384,7 +1399,6 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at } $out .= "</li>\n"; - $idx++; } return $out; @@ -1396,30 +1410,40 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at * @access private * @return string */ -function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $exceptions=array()) +function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array()) { + global $RCMAIL; + $out = ''; foreach ($arrFolders as $key => $folder) { - if (empty($exceptions) || !in_array($folder['id'], $exceptions)) { - if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) - $foldername = rcube_label($folder_class); - else { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength>1) - $foldername = abbreviate_string($foldername, $maxlength); - } - - $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); + // skip exceptions (and its subfolders) + if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { + continue; } - else if ($nestLevel) + + // skip folders in which it isn't possible to create subfolders + if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->imap->mailbox_attributes($folder['id'])) + && in_array('\\Noinferiors', $attrs) + ) { continue; + } + + if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) + $foldername = rcube_label($folder_class); + else { + $foldername = $folder['name']; + + // shorten the folder name to a given length + if ($maxlength && $maxlength>1) + $foldername = abbreviate_string($foldername, $maxlength); + } + + $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); if (!empty($folder['folders'])) $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, - $select, $realnames, $nestLevel+1, $exceptions); + $select, $realnames, $nestLevel+1, $opts); } return $out; @@ -1568,7 +1592,11 @@ function rcmail_display_server_error($fallback=null, $fallback_args=null) $RCMAIL->output->show_message('errorreadonly', 'error'); } else if ($err_code && ($err_str = $RCMAIL->imap->get_error_str())) { - $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); + // try to detect access rights problem and display appropriate message + if (stripos($err_str, 'Permission denied') !== false) + $RCMAIL->output->show_message('errornoperm', 'error'); + else + $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str)); } else if ($fallback) { $RCMAIL->output->show_message($fallback, 'error', $fallback_args); @@ -1591,7 +1619,7 @@ function rcube_html_editor($mode='') $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode)); if ($hook['abort']) - return; + return; $lang = strtolower($_SESSION['language']); @@ -1603,9 +1631,14 @@ function rcube_html_editor($mode='') $RCMAIL->output->include_script('tiny_mce/tiny_mce.js'); $RCMAIL->output->include_script('editor.js'); - $RCMAIL->output->add_script(sprintf("rcmail_editor_init('\$__skin_path', '%s', %d, '%s');", - JQ($lang), intval($CONFIG['enable_spellcheck']), $mode), - 'foot'); + $RCMAIL->output->add_script(sprintf("rcmail_editor_init(%s)", + json_encode(array( + 'mode' => $mode, + 'skin_path' => '$__skin_path', + 'lang' => $lang, + 'spellcheck' => intval($CONFIG['enable_spellcheck']), + 'spelldict' => intval($CONFIG['spellcheck_dictionary']), + ))), 'foot'); } @@ -2369,5 +2402,5 @@ function rcube_autocomplete_init() $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15)); $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length')); - $RCMAIL->output->add_label('autocompletechars'); + $RCMAIL->output->add_label('autocompletechars', 'autocompletemore'); } diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 5323b64..aa3bade 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -6,6 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -15,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcmail.php 5235 2011-09-19 06:43:57Z alec $ + $Id: rcmail.php 5527 2011-12-02 09:58:03Z alec $ */ @@ -452,8 +453,7 @@ class rcmail } // add to the 'books' array for shutdown function - if (!isset($this->address_books[$id])) - $this->address_books[$id] = $contacts; + $this->address_books[$id] = $contacts; return $contacts; } @@ -482,7 +482,8 @@ class rcmail 'name' => rcube_label('personaladrbook'), 'groups' => $this->address_books['0']->groups, 'readonly' => $this->address_books['0']->readonly, - 'autocomplete' => in_array('sql', $autocomplete) + 'autocomplete' => in_array('sql', $autocomplete), + 'undelete' => $this->address_books['0']->undelete && $this->config->get('undo_timeout'), ); } @@ -592,7 +593,6 @@ class rcmail return; $this->imap = new rcube_imap(); - $this->imap->debug_level = $this->config->get('debug_level'); $this->imap->skip_deleted = $this->config->get('skip_deleted'); // enable caching of imap data @@ -614,7 +614,7 @@ class rcmail // Setting root and delimiter before establishing the connection // can save time detecting them using NAMESPACE and LIST $options = array( - 'auth_method' => $this->config->get('imap_auth_type', 'check'), + 'auth_type' => $this->config->get('imap_auth_type', 'check'), 'auth_cid' => $this->config->get('imap_auth_cid'), 'auth_pw' => $this->config->get('imap_auth_pw'), 'debug' => (bool) $this->config->get('imap_debug', 0), @@ -677,18 +677,21 @@ class rcmail if (session_id()) return; + $sess_name = $this->config->get('session_name'); + $sess_domain = $this->config->get('session_domain'); + $lifetime = $this->config->get('session_lifetime', 0) * 60; + // set session domain - if ($domain = $this->config->get('session_domain')) { - ini_set('session.cookie_domain', $domain); + if ($sess_domain) { + ini_set('session.cookie_domain', $sess_domain); } // set session garbage collecting time according to session_lifetime - $lifetime = $this->config->get('session_lifetime', 0) * 60; if ($lifetime) { ini_set('session.gc_maxlifetime', $lifetime * 2); } ini_set('session.cookie_secure', rcube_https_check()); - ini_set('session.name', 'roundcube_sessid'); + 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'); @@ -728,7 +731,7 @@ class rcmail $keep_alive = max(60, $keep_alive); $this->session->set_keep_alive($keep_alive); } - + $this->session->set_secret($this->config->get('des_key') . $_SERVER['HTTP_USER_AGENT']); $this->session->set_ip_check($this->config->get('ip_check')); } @@ -838,16 +841,8 @@ class rcmail if (!$imap_login) return false; - $this->set_imap_prop(); - // user already registered -> update user's record if (is_object($user)) { - // fix some old settings according to namespace prefix - $this->fix_namespace_settings($user); - - // create default folders on first login - if (!$user->data['last_login'] && $config['create_default_folders']) - $this->imap->create_default_folders(); // update last login timestamp $user->touch(); } @@ -855,13 +850,6 @@ class rcmail else if ($config['auto_create_user']) { if ($created = rcube_user::create($username, $host)) { $user = $created; - - // fix default settings according to namespace prefix - $this->fix_namespace_settings($user); - - // create default folders on first login - if ($config['create_default_folders']) - $this->imap->create_default_folders(); } else { raise_error(array( @@ -881,9 +869,19 @@ class rcmail // login succeeded if (is_object($user) && $user->ID) { + // Configure environment $this->set_user($user); + $this->set_imap_prop(); $this->session_configure(); + // fix some old settings according to namespace prefix + $this->fix_namespace_settings($user); + + // create default folders on first login + if ($config['create_default_folders'] && (!empty($created) || empty($user->data['last_login']))) { + $this->imap->create_default_folders(); + } + // set session vars $_SESSION['user_id'] = $user->ID; $_SESSION['username'] = $user->data['username']; @@ -892,9 +890,11 @@ class rcmail $_SESSION['imap_ssl'] = $imap_ssl; $_SESSION['password'] = $this->encrypt($pass); $_SESSION['login_time'] = mktime(); - + if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_') $_SESSION['timezone'] = floatval($_REQUEST['_timezone']); + if (isset($_REQUEST['_dstactive']) && $_REQUEST['_dstactive'] != '_default_') + $_SESSION['dst_active'] = intval($_REQUEST['_dstactive']); // force reloading complete list of subscribed mailboxes $this->imap->clear_cache('mailboxes', true); @@ -973,7 +973,9 @@ class rcmail /** * Get localized text in the desired language * - * @param mixed Named parameters array or label name + * @param mixed $attrib Named parameters array or label name + * @param string $domain Label domain (plugin) name + * * @return string Localized text */ public function gettext($attrib, $domain=null) @@ -988,7 +990,7 @@ class rcmail $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1; $name = $attrib['name'] ? $attrib['name'] : ''; - + // attrib contain text values: use them from now if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) $this->texts[$name] = $setval; @@ -1044,19 +1046,40 @@ class rcmail /** - * Check if the given text lable exists + * Check if the given text label exists + * + * @param string $name Label name + * @param string $domain Label domain (plugin) name or '*' for all domains + * @param string $ref_domain Sets domain name if label is found * - * @param string Label name * @return boolean True if text exists (either in the current language or in en_US) */ - public function text_exists($name, $domain=null) + public function text_exists($name, $domain = null, &$ref_domain = null) { // load localization files if not done yet if (empty($this->texts)) $this->load_language(); - // check for text with domain first - return ($domain && isset($this->texts[$domain.'.'.$name])) || isset($this->texts[$name]); + if (isset($this->texts[$name])) { + $ref_domain = ''; + return true; + } + + // any of loaded domains (plugins) + if ($domain == '*') { + foreach ($this->plugins->loaded_plugins() as $domain) + if (isset($this->texts[$domain.'.'.$name])) { + $ref_domain = $domain; + return true; + } + } + // specified domain + else if ($domain) { + $ref_domain = $domain; + return isset($this->texts[$domain.'.'.$name]); + } + + return false; } /** @@ -1204,7 +1227,6 @@ class rcmail // before closing the database connection, write session data if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { - $this->session->cleanup(); session_write_close(); } @@ -1246,7 +1268,7 @@ class rcmail { $sess_id = $_COOKIE[ini_get('session.name')]; if (!$sess_id) $sess_id = session_id(); - $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->task . $this->config->get('des_key') . $sess_id))); + $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->user->ID . $this->config->get('des_key') . $sess_id))); return $plugin['value']; } @@ -1540,7 +1562,7 @@ class rcmail // use strtr behaviour of going through source string once $cmd = strtr($cmd, $replacements); - + return (string)shell_exec($cmd); } @@ -1576,7 +1598,7 @@ class rcmail } } } - + /** * Returns current action filename * @@ -1606,8 +1628,8 @@ class rcmail if (!$prefix_len) return; - $prefs = $user->get_prefs(); - if (empty($prefs) || $prefs['namespace_fixed']) + $prefs = $this->config->all(); + if (!empty($prefs['namespace_fixed'])) return; // Build namespace prefix regexp diff --git a/program/include/rcmail.php.orig b/program/include/rcmail.php.orig new file mode 100644 index 0000000..7d0da0a --- /dev/null +++ b/program/include/rcmail.php.orig @@ -0,0 +1,1716 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/rcmail.php | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Application class providing core functions and holding | + | instances of all 'global' objects like db- and imap-connections | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id: rcmail.php 5527 2011-12-02 09:58:03Z alec $ + +*/ + + +/** + * Application class of Roundcube Webmail + * implemented as singleton + * + * @package Core + */ +class rcmail +{ + /** + * Main tasks. + * + * @var array + */ + static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy'); + + /** + * Singleton instace of rcmail + * + * @var rcmail + */ + static private $instance; + + /** + * Stores instance of rcube_config. + * + * @var rcube_config + */ + public $config; + + /** + * Stores rcube_user instance. + * + * @var rcube_user + */ + public $user; + + /** + * Instace of database class. + * + * @var rcube_mdb2 + */ + public $db; + + /** + * Instace of Memcache class. + * + * @var rcube_mdb2 + */ + public $memcache; + + /** + * Instace of rcube_session class. + * + * @var rcube_session + */ + public $session; + + /** + * Instance of rcube_smtp class. + * + * @var rcube_smtp + */ + public $smtp; + + /** + * Instance of rcube_imap class. + * + * @var rcube_imap + */ + public $imap; + + /** + * Instance of rcube_template class. + * + * @var rcube_template + */ + public $output; + + /** + * Instance of rcube_plugin_api. + * + * @var rcube_plugin_api + */ + public $plugins; + + /** + * Current task. + * + * @var string + */ + public $task; + + /** + * Current action. + * + * @var string + */ + public $action = ''; + public $comm_path = './'; + + private $texts; + private $address_books = array(); + private $caches = array(); + private $action_map = array(); + private $shutdown_functions = array(); + + + /** + * This implements the 'singleton' design pattern + * + * @return rcmail The one and only instance + */ + static function get_instance() + { + if (!self::$instance) { + self::$instance = new rcmail(); + self::$instance->startup(); // init AFTER object was linked with self::$instance + } + + return self::$instance; + } + + + /** + * Private constructor + */ + private function __construct() + { + // load configuration + $this->config = new rcube_config(); + + register_shutdown_function(array($this, 'shutdown')); + } + + + /** + * Initial startup function + * to register session, create database and imap connections + * + * @todo Remove global vars $DB, $USER + */ + private function startup() + { + // initialize syslog + if ($this->config->get('log_driver') == 'syslog') { + $syslog_id = $this->config->get('syslog_id', 'roundcube'); + $syslog_facility = $this->config->get('syslog_facility', LOG_USER); + openlog($syslog_id, LOG_ODELAY, $syslog_facility); + } + + // connect to database + $GLOBALS['DB'] = $this->get_dbh(); + + // start session + $this->session_init(); + + // create user object + $this->set_user(new rcube_user($_SESSION['user_id'])); + + // configure session (after user config merge!) + $this->session_configure(); + + // set task and action properties + $this->set_task(get_input_value('_task', RCUBE_INPUT_GPC)); + $this->action = asciiwords(get_input_value('_action', RCUBE_INPUT_GPC)); + + // reset some session parameters when changing task + if ($this->task != 'utils') { + if ($this->session && $_SESSION['task'] != $this->task) + $this->session->remove('page'); + // set current task to session + $_SESSION['task'] = $this->task; + } + + // init output class + if (!empty($_REQUEST['_remote'])) + $GLOBALS['OUTPUT'] = $this->json_init(); + else + $GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed'])); + + // create plugin API and load plugins + $this->plugins = rcube_plugin_api::get_instance(); + + // init plugins + $this->plugins->init(); + } + + + /** + * Setter for application task + * + * @param string Task to set + */ + public function set_task($task) + { + $task = asciiwords($task); + + if ($this->user && $this->user->ID) + $task = !$task ? 'mail' : $task; + else + $task = 'login'; + + $this->task = $task; + $this->comm_path = $this->url(array('task' => $this->task)); + + if ($this->output) + $this->output->set_env('task', $this->task); + } + + + /** + * Setter for system user object + * + * @param rcube_user Current user instance + */ + public function set_user($user) + { + if (is_object($user)) { + $this->user = $user; + $GLOBALS['USER'] = $this->user; + + // overwrite config with user preferences + $this->config->set_user_prefs((array)$this->user->get_prefs()); + } + + $_SESSION['language'] = $this->user->language = $this->language_prop($this->config->get('language', $_SESSION['language'])); + + // set localization + setlocale(LC_ALL, $_SESSION['language'] . '.utf8', 'en_US.utf8'); + + // workaround for http://bugs.php.net/bug.php?id=18556 + if (in_array($_SESSION['language'], array('tr_TR', 'ku', 'az_AZ'))) + setlocale(LC_CTYPE, 'en_US' . '.utf8'); + } + + + /** + * Check the given string and return a valid language code + * + * @param string Language code + * @return string Valid language code + */ + private function language_prop($lang) + { + static $rcube_languages, $rcube_language_aliases; + + // user HTTP_ACCEPT_LANGUAGE if no language is specified + if (empty($lang) || $lang == 'auto') { + $accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + $lang = str_replace('-', '_', $accept_langs[0]); + } + + if (empty($rcube_languages)) { + @include(INSTALL_PATH . 'program/localization/index.inc'); + } + + // check if we have an alias for that language + if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) { + $lang = $rcube_language_aliases[$lang]; + } + // try the first two chars + else if (!isset($rcube_languages[$lang])) { + $short = substr($lang, 0, 2); + + // check if we have an alias for the short language code + if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) { + $lang = $rcube_language_aliases[$short]; + } + // expand 'nn' to 'nn_NN' + else if (!isset($rcube_languages[$short])) { + $lang = $short.'_'.strtoupper($short); + } + } + + if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) { + $lang = 'en_US'; + } + + return $lang; + } + + + /** + * Get the current database connection + * + * @return rcube_mdb2 Database connection object + */ + public function get_dbh() + { + if (!$this->db) { + $config_all = $this->config->all(); + + $this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']); + $this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql'; + $this->db->set_debug((bool)$config_all['sql_debug']); + } + + return $this->db; + } + + + /** + * Get global handle for memcache access + * + * @return object Memcache + */ + public function get_memcache() + { + if (!isset($this->memcache)) { + // no memcache support in PHP + if (!class_exists('Memcache')) { + $this->memcache = false; + return false; + } + + $this->memcache = new Memcache; + $this->mc_available = 0; + + // add alll configured hosts to pool + $pconnect = $this->config->get('memcache_pconnect', true); + foreach ($this->config->get('memcache_hosts', array()) as $host) { + list($host, $port) = explode(':', $host); + if (!$port) $port = 11211; + $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); + } + + // test connection and failover (will result in $this->mc_available == 0 on complete failure) + $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist + + if (!$this->mc_available) + $this->memcache = false; + } + + return $this->memcache; + } + + /** + * Callback for memcache failure + */ + public function memcache_failure($host, $port) + { + static $seen = array(); + + // only report once + if (!$seen["$host:$port"]++) { + $this->mc_available--; + raise_error(array('code' => 604, 'type' => 'db', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => "Memcache failure on host $host:$port"), + true, false); + } + } + + + /** + * Initialize and get cache object + * + * @param string $name Cache identifier + * @param string $type Cache type ('db', 'apc' or 'memcache') + * @param int $ttl Expiration time for cache items in seconds + * @param bool $packed Enables/disables data serialization + * + * @return rcube_cache Cache object + */ + public function get_cache($name, $type='db', $ttl=0, $packed=true) + { + if (!isset($this->caches[$name])) { + $this->caches[$name] = new rcube_cache($type, $_SESSION['user_id'], $name, $ttl, $packed); + } + + return $this->caches[$name]; + } + + + /** + * Return instance of the internal address book class + * + * @param string Address book identifier + * @param boolean True if the address book needs to be writeable + * + * @return rcube_contacts Address book object + */ + public function get_address_book($id, $writeable = false) + { + $contacts = null; + $ldap_config = (array)$this->config->get('ldap_public'); + $abook_type = strtolower($this->config->get('address_book_type')); + + // 'sql' is the alias for '0' used by autocomplete + if ($id == 'sql') + $id = '0'; + + // use existing instance + if (isset($this->address_books[$id]) && is_object($this->address_books[$id]) + && is_a($this->address_books[$id], 'rcube_addressbook') + && (!$writeable || !$this->address_books[$id]->readonly) + ) { + $contacts = $this->address_books[$id]; + } + else if ($id && $ldap_config[$id]) { + $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); + } + else if ($id === '0') { + $contacts = new rcube_contacts($this->db, $this->user->ID); + } + else { + $plugin = $this->plugins->exec_hook('addressbook_get', array('id' => $id, 'writeable' => $writeable)); + + // plugin returned instance of a rcube_addressbook + if ($plugin['instance'] instanceof rcube_addressbook) { + $contacts = $plugin['instance']; + } + // get first source from the list + else if (!$id) { + $source = reset($this->get_address_sources($writeable)); + if (!empty($source)) { + $contacts = $this->get_address_book($source['id']); + if ($contacts) + $id = $source['id']; + } + } + } + + if (!$contacts) { + raise_error(array( + 'code' => 700, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Addressbook source ($id) not found!"), + true, true); + } + + // add to the 'books' array for shutdown function + $this->address_books[$id] = $contacts; + + return $contacts; + } + + + /** + * Return address books list + * + * @param boolean True if the address book needs to be writeable + * + * @return array Address books array + */ + public function get_address_sources($writeable = false) + { + $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(); + + // We are using the DB address book + if ($abook_type != 'ldap') { + if (!isset($this->address_books['0'])) + $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID); + $list['0'] = array( + 'id' => '0', + 'name' => rcube_label('personaladrbook'), + 'groups' => $this->address_books['0']->groups, + 'readonly' => $this->address_books['0']->readonly, + 'autocomplete' => in_array('sql', $autocomplete), + 'undelete' => $this->address_books['0']->undelete && $this->config->get('undo_timeout'), + ); + } + + if ($ldap_config) { + $ldap_config = (array) $ldap_config; + foreach ($ldap_config as $id => $prop) + $list[$id] = array( + 'id' => $id, + 'name' => $prop['name'], + 'groups' => is_array($prop['groups']), + 'readonly' => !$prop['writable'], + 'hidden' => $prop['hidden'], + 'autocomplete' => in_array($id, $autocomplete) + ); + } + + $plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list)); + $list = $plugin['sources']; + + foreach ($list as $idx => $item) { + // register source for shutdown function + if (!is_object($this->address_books[$item['id']])) + $this->address_books[$item['id']] = $item; + // remove from list if not writeable as requested + if ($writeable && $item['readonly']) + unset($list[$idx]); + } + + return $list; + } + + + /** + * Init output object for GUI and add common scripts. + * This will instantiate a rcmail_template object and set + * environment vars according to the current session and configuration + * + * @param boolean True if this request is loaded in a (i)frame + * @return rcube_template Reference to HTML output object + */ + public function load_gui($framed = false) + { + // init output page + if (!($this->output instanceof rcube_template)) + $this->output = new rcube_template($this->task, $framed); + + // set keep-alive/check-recent interval + if ($this->session && ($keep_alive = $this->session->get_keep_alive())) { + $this->output->set_env('keep_alive', $keep_alive); + } + + if ($framed) { + $this->comm_path .= '&_framed=1'; + $this->output->set_env('framed', true); + } + + $this->output->set_env('task', $this->task); + $this->output->set_env('action', $this->action); + $this->output->set_env('comm_path', $this->comm_path); + $this->output->set_charset(RCMAIL_CHARSET); + + // add some basic labels to client + $this->output->add_label('loading', 'servererror'); + + return $this->output; + } + + + /** + * Create an output object for JSON responses + * + * @return rcube_json_output Reference to JSON output object + */ + public function json_init() + { + if (!($this->output instanceof rcube_json_output)) + $this->output = new rcube_json_output($this->task); + + return $this->output; + } + + + /** + * Create SMTP object and connect to server + * + * @param boolean True if connection should be established + */ + public function smtp_init($connect = false) + { + $this->smtp = new rcube_smtp(); + + if ($connect) + $this->smtp->connect(); + } + + + /** + * Create global IMAP object and connect to server + * + * @param boolean True if connection should be established + * @todo Remove global $IMAP + */ + public function imap_init($connect = false) + { + // already initialized + if (is_object($this->imap)) + return; + + $this->imap = new rcube_imap(); + $this->imap->skip_deleted = $this->config->get('skip_deleted'); + + // enable caching of imap data + $imap_cache = $this->config->get('imap_cache'); + $messages_cache = $this->config->get('messages_cache'); + // for backward compatybility + if ($imap_cache === null && $messages_cache === null && $this->config->get('enable_caching')) { + $imap_cache = 'db'; + $messages_cache = true; + } + if ($imap_cache) + $this->imap->set_caching($imap_cache); + if ($messages_cache) + $this->imap->set_messages_caching(true); + + // set pagesize from config + $this->imap->set_pagesize($this->config->get('pagesize', 50)); + + // Setting root and delimiter before establishing the connection + // can save time detecting them using NAMESPACE and LIST + $options = array( + 'auth_type' => $this->config->get('imap_auth_type', 'check'), + 'auth_cid' => $this->config->get('imap_auth_cid'), + 'auth_pw' => $this->config->get('imap_auth_pw'), + 'debug' => (bool) $this->config->get('imap_debug', 0), + 'force_caps' => (bool) $this->config->get('imap_force_caps'), + 'timeout' => (int) $this->config->get('imap_timeout', 0), + ); + + $this->imap->set_options($options); + + // set global object for backward compatibility + $GLOBALS['IMAP'] = $this->imap; + + $hook = $this->plugins->exec_hook('imap_init', array('fetch_headers' => $this->imap->fetch_add_headers)); + if ($hook['fetch_headers']) + $this->imap->fetch_add_headers = $hook['fetch_headers']; + + // support this parameter for backward compatibility but log warning + if ($connect) { + $this->imap_connect(); + raise_error(array( + 'code' => 800, 'type' => 'imap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "rcube::imap_init(true) is deprecated, use rcube::imap_connect() instead"), + true, false); + } + } + + + /** + * Connect to IMAP server with stored session data + * + * @return bool True on success, false on error + */ + public function imap_connect() + { + if (!$this->imap) + $this->imap_init(); + + if ($_SESSION['imap_host'] && !$this->imap->conn->connected()) { + if (!$this->imap->connect($_SESSION['imap_host'], $_SESSION['username'], $this->decrypt($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl'])) { + if ($this->output) + $this->output->show_message($this->imap->get_error_code() == -1 ? 'imaperror' : 'sessionerror', 'error'); + } + else { + $this->set_imap_prop(); + return $this->imap->conn; + } + } + + return false; + } + + + /** + * Create session object and start the session. + */ + public function session_init() + { + // session started (Installer?) + if (session_id()) + return; + + $sess_name = $this->config->get('session_name'); + $sess_domain = $this->config->get('session_domain'); + $lifetime = $this->config->get('session_lifetime', 0) * 60; + + // set session domain + if ($sess_domain) { + ini_set('session.cookie_domain', $sess_domain); + } + // set session garbage collecting time according to session_lifetime + if ($lifetime) { + ini_set('session.gc_maxlifetime', $lifetime * 2); + } + + ini_set('session.cookie_secure', rcube_https_check()); + 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'); + + // use database for storing session data + $this->session = new rcube_session($this->get_dbh(), $this->config); + + $this->session->register_gc_handler('rcmail_temp_gc'); + if ($this->config->get('enable_caching')) + $this->session->register_gc_handler('rcmail_cache_gc'); + + // start PHP session (if not in CLI mode) + if ($_SERVER['REMOTE_ADDR']) + session_start(); + + // set initial session vars + if (!$_SESSION['user_id']) + $_SESSION['temp'] = true; + } + + + /** + * Configure session object internals + */ + public function session_configure() + { + if (!$this->session) + return; + + $lifetime = $this->config->get('session_lifetime', 0) * 60; + + // set keep-alive/check-recent interval + if ($keep_alive = $this->config->get('keep_alive')) { + // be sure that it's less than session lifetime + if ($lifetime) + $keep_alive = min($keep_alive, $lifetime - 30); + $keep_alive = max(60, $keep_alive); + $this->session->set_keep_alive($keep_alive); + } + + $this->session->set_secret($this->config->get('des_key') . $_SERVER['HTTP_USER_AGENT']); + $this->session->set_ip_check($this->config->get('ip_check')); + } + + + /** + * Perfom login to the IMAP server and to the webmail service. + * This will also create a new user entry if auto_create_user is configured. + * + * @param string IMAP user name + * @param string IMAP password + * @param string IMAP host + * @return boolean True on success, False on failure + */ + function login($username, $pass, $host=NULL) + { + $user = NULL; + $config = $this->config->all(); + + if (!$host) + $host = $config['default_host']; + + // Validate that selected host is in the list of configured hosts + if (is_array($config['default_host'])) { + $allowed = false; + foreach ($config['default_host'] as $key => $host_allowed) { + if (!is_numeric($key)) + $host_allowed = $key; + if ($host == $host_allowed) { + $allowed = true; + break; + } + } + if (!$allowed) + return false; + } + else if (!empty($config['default_host']) && $host != rcube_parse_host($config['default_host'])) + return false; + + // parse $host URL + $a_host = parse_url($host); + if ($a_host['host']) { + $host = $a_host['host']; + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; + if (!empty($a_host['port'])) + $imap_port = $a_host['port']; + else if ($imap_ssl && $imap_ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) + $imap_port = 993; + } + + $imap_port = $imap_port ? $imap_port : $config['default_port']; + + /* 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_parse_host($config['username_domain'][$host], $host); + else if (is_string($config['username_domain'])) + $username .= '@'.rcube_parse_host($config['username_domain'], $host); + } + + // Convert username to lowercase. If IMAP backend + // is case-insensitive we need to store always the same username (#1487113) + if ($config['login_lc']) { + $username = mb_strtolower($username); + } + + // try to resolve email address from virtuser table + if (strpos($username, '@') && ($virtuser = rcube_user::email2user($username))) { + $username = $virtuser; + } + + // Here we need IDNA ASCII + // Only rcube_contacts class is using domain names in Unicode + $host = rcube_idn_to_ascii($host); + if (strpos($username, '@')) { + // lowercase domain name + list($local, $domain) = explode('@', $username); + $username = $local . '@' . mb_strtolower($domain); + $username = rcube_idn_to_ascii($username); + } + + // user already registered -> overwrite username + if ($user = rcube_user::query($username, $host)) + $username = $user->data['username']; + + if (!$this->imap) + $this->imap_init(); + + // try IMAP login + if (!($imap_login = $this->imap->connect($host, $username, $pass, $imap_port, $imap_ssl))) { + // try with lowercase + $username_lc = mb_strtolower($username); + if ($username_lc != $username) { + // try to find user record again -> overwrite username + if (!$user && ($user = rcube_user::query($username_lc, $host))) + $username_lc = $user->data['username']; + + if ($imap_login = $this->imap->connect($host, $username_lc, $pass, $imap_port, $imap_ssl)) + $username = $username_lc; + } + } + + // exit if IMAP login failed + if (!$imap_login) + return false; + + // user already registered -> update user's record + if (is_object($user)) { + // update last login timestamp + $user->touch(); + } + // create new system user + else if ($config['auto_create_user']) { + if ($created = rcube_user::create($username, $host)) { + $user = $created; + } + else { + raise_error(array( + 'code' => 620, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Failed to create a user record. Maybe aborted by a plugin?" + ), true, false); + } + } + else { + raise_error(array( + 'code' => 621, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Access denied for new user $username. 'auto_create_user' is disabled" + ), true, false); + } + + // login succeeded + if (is_object($user) && $user->ID) { + // Configure environment + $this->set_user($user); + $this->set_imap_prop(); + $this->session_configure(); + + // fix some old settings according to namespace prefix + $this->fix_namespace_settings($user); + + // create default folders on first login + if ($config['create_default_folders'] && (!empty($created) || empty($user->data['last_login']))) { + $this->imap->create_default_folders(); + } + + // set session vars + $_SESSION['user_id'] = $user->ID; + $_SESSION['username'] = $user->data['username']; + $_SESSION['imap_host'] = $host; + $_SESSION['imap_port'] = $imap_port; + $_SESSION['imap_ssl'] = $imap_ssl; + $_SESSION['password'] = $this->encrypt($pass); + $_SESSION['login_time'] = mktime(); + + if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_') + $_SESSION['timezone'] = floatval($_REQUEST['_timezone']); + if (isset($_REQUEST['_dstactive']) && $_REQUEST['_dstactive'] != '_default_') + $_SESSION['dst_active'] = intval($_REQUEST['_dstactive']); + + // force reloading complete list of subscribed mailboxes + $this->imap->clear_cache('mailboxes', true); + + return true; + } + + return false; + } + + + /** + * Set root dir and last stored mailbox + * This must be done AFTER connecting to the server! + */ + public function set_imap_prop() + { + $this->imap->set_charset($this->config->get('default_charset', RCMAIL_CHARSET)); + + if ($default_folders = $this->config->get('default_imap_folders')) { + $this->imap->set_default_mailboxes($default_folders); + } + if (isset($_SESSION['mbox'])) { + $this->imap->set_mailbox($_SESSION['mbox']); + } + if (isset($_SESSION['page'])) { + $this->imap->set_page($_SESSION['page']); + } + } + + + /** + * Auto-select IMAP host based on the posted login information + * + * @return string Selected IMAP host + */ + public function autoselect_host() + { + $default_host = $this->config->get('default_host'); + $host = null; + + if (is_array($default_host)) { + $post_host = get_input_value('_host', RCUBE_INPUT_POST); + + // direct match in default_host array + if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { + $host = $post_host; + } + + // try to select host by mail domain + list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST)); + if (!empty($domain)) { + foreach ($default_host as $imap_host => $mail_domains) { + if (is_array($mail_domains) && in_array($domain, $mail_domains)) { + $host = $imap_host; + break; + } + } + } + + // take the first entry if $host is still an array + if (empty($host)) { + $host = array_shift($default_host); + } + } + else if (empty($default_host)) { + $host = get_input_value('_host', RCUBE_INPUT_POST); + } + else + $host = rcube_parse_host($default_host); + + return $host; + } + + + /** + * Get localized text in the desired language + * + * @param mixed $attrib Named parameters array or label name + * @param string $domain Label domain (plugin) name + * + * @return string Localized text + */ + public function gettext($attrib, $domain=null) + { + // load localization files if not done yet + if (empty($this->texts)) + $this->load_language(); + + // extract attributes + if (is_string($attrib)) + $attrib = array('name' => $attrib); + + $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1; + $name = $attrib['name'] ? $attrib['name'] : ''; + + // attrib contain text values: use them from now + if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) + $this->texts[$name] = $setval; + + // check for text with domain + if ($domain && ($text_item = $this->texts[$domain.'.'.$name])) + ; + // text does not exist + else if (!($text_item = $this->texts[$name])) { + return "[$name]"; + } + + // make text item array + $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item); + + // decide which text to use + if ($nr == 1) { + $text = $a_text_item['single']; + } + else if ($nr > 0) { + $text = $a_text_item['multiple']; + } + else if ($nr == 0) { + if ($a_text_item['none']) + $text = $a_text_item['none']; + else if ($a_text_item['single']) + $text = $a_text_item['single']; + else if ($a_text_item['multiple']) + $text = $a_text_item['multiple']; + } + + // default text is single + if ($text == '') { + $text = $a_text_item['single']; + } + + // replace vars in text + if (is_array($attrib['vars'])) { + foreach ($attrib['vars'] as $var_key => $var_value) + $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text); + } + + // format output + if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst']) + return ucfirst($text); + else if ($attrib['uppercase']) + return mb_strtoupper($text); + else if ($attrib['lowercase']) + return mb_strtolower($text); + + return $text; + } + + + /** + * Check if the given text label exists + * + * @param string $name Label name + * @param string $domain Label domain (plugin) name or '*' for all domains + * @param string $ref_domain Sets domain name if label is found + * + * @return boolean True if text exists (either in the current language or in en_US) + */ + public function text_exists($name, $domain = null, &$ref_domain = null) + { + // load localization files if not done yet + if (empty($this->texts)) + $this->load_language(); + + if (isset($this->texts[$name])) { + $ref_domain = ''; + return true; + } + + // any of loaded domains (plugins) + if ($domain == '*') { + foreach ($this->plugins->loaded_plugins() as $domain) + if (isset($this->texts[$domain.'.'.$name])) { + $ref_domain = $domain; + return true; + } + } + // specified domain + else if ($domain) { + $ref_domain = $domain; + return isset($this->texts[$domain.'.'.$name]); + } + + return false; + } + + /** + * Load a localization package + * + * @param string Language ID + */ + public function load_language($lang = null, $add = array()) + { + $lang = $this->language_prop(($lang ? $lang : $_SESSION['language'])); + + // load localized texts + if (empty($this->texts) || $lang != $_SESSION['language']) { + $this->texts = array(); + + // handle empty lines after closing PHP tag in localization files + ob_start(); + + // get english labels (these should be complete) + @include(INSTALL_PATH . 'program/localization/en_US/labels.inc'); + @include(INSTALL_PATH . 'program/localization/en_US/messages.inc'); + + if (is_array($labels)) + $this->texts = $labels; + if (is_array($messages)) + $this->texts = array_merge($this->texts, $messages); + + // include user language files + if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) { + include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc'); + include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc'); + + if (is_array($labels)) + $this->texts = array_merge($this->texts, $labels); + if (is_array($messages)) + $this->texts = array_merge($this->texts, $messages); + } + + ob_end_clean(); + + $_SESSION['language'] = $lang; + } + + // append additional texts (from plugin) + if (is_array($add) && !empty($add)) + $this->texts += $add; + } + + + /** + * Read directory program/localization and return a list of available languages + * + * @return array List of available localizations + */ + public function list_languages() + { + static $sa_languages = array(); + + if (!sizeof($sa_languages)) { + @include(INSTALL_PATH . 'program/localization/index.inc'); + + if ($dh = @opendir(INSTALL_PATH . 'program/localization')) { + while (($name = readdir($dh)) !== false) { + if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) + continue; + + if ($label = $rcube_languages[$name]) + $sa_languages[$name] = $label; + } + closedir($dh); + } + } + + return $sa_languages; + } + + + /** + * Destroy session data and remove cookie + */ + public function kill_session() + { + $this->plugins->exec_hook('session_destroy'); + + $this->session->kill(); + $_SESSION = array('language' => $this->user->language, 'temp' => true); + $this->user->reset(); + } + + + /** + * Do server side actions on logout + */ + public function logout_actions() + { + $config = $this->config->all(); + + // on logout action we're not connected to imap server + if (($config['logout_purge'] && !empty($config['trash_mbox'])) || $config['logout_expunge']) { + if (!$this->session->check_auth()) + return; + + $this->imap_connect(); + } + + if ($config['logout_purge'] && !empty($config['trash_mbox'])) { + $this->imap->clear_mailbox($config['trash_mbox']); + } + + if ($config['logout_expunge']) { + $this->imap->expunge('INBOX'); + } + + // Try to save unsaved user preferences + if (!empty($_SESSION['preferences'])) { + $this->user->save_prefs(unserialize($_SESSION['preferences'])); + } + } + + + /** + * Function to be executed in script shutdown + * Registered with register_shutdown_function() + */ + public function shutdown() + { + foreach ($this->shutdown_functions as $function) + call_user_func($function); + + if (is_object($this->smtp)) + $this->smtp->disconnect(); + + foreach ($this->address_books as $book) { + if (is_object($book) && is_a($book, 'rcube_addressbook')) + $book->close(); + } + + foreach ($this->caches as $cache) { + if (is_object($cache)) + $cache->close(); + } + + if (is_object($this->imap)) + $this->imap->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')) + $mem = show_bytes(memory_get_usage()); + if (function_exists('memory_get_peak_usage')) + $mem .= '/'.show_bytes(memory_get_peak_usage()); + + $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : ''); + if (defined('RCMAIL_START')) + rcube_print_time(RCMAIL_START, $log); + else + console($log); + } + } + + + /** + * Registers shutdown function to be executed on shutdown. + * The functions will be executed before destroying any + * objects like smtp, imap, session, etc. + * + * @param callback Function callback + */ + public function add_shutdown_function($function) + { + $this->shutdown_functions[] = $function; + } + + + /** + * Generate a unique token to be used in a form request + * + * @return string The request token + */ + public function get_request_token() + { + $sess_id = $_COOKIE[ini_get('session.name')]; + if (!$sess_id) $sess_id = session_id(); + $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->user->ID . $this->config->get('des_key') . $sess_id))); + return $plugin['value']; + } + + + /** + * Check if the current request contains a valid token + * + * @param int Request method + * @return boolean True if request token is valid false if not + */ + public function check_request($mode = RCUBE_INPUT_POST) + { + $token = get_input_value('_token', $mode); + $sess_id = $_COOKIE[ini_get('session.name')]; + return !empty($sess_id) && $token == $this->get_request_token(); + } + + + /** + * 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); + } + + + /** + * Encrypt using 3DES + * + * @param string $clear clear text input + * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key' + * @param boolean $base64 whether or not to base64_encode() the result before returning + * + * @return string encrypted text + */ + public function encrypt($clear, $key = 'des_key', $base64 = true) + { + if (!$clear) + return ''; + /*- + * Add a single canary byte to the end of the clear text, which + * will help find out how much of padding will need to be removed + * upon decryption; see http://php.net/mcrypt_generic#68082 + */ + $clear = pack("a*H2", $clear, "80"); + + if (function_exists('mcrypt_module_open') && + ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) + { + $iv = $this->create_iv(mcrypt_enc_get_iv_size($td)); + mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); + $cipher = $iv . mcrypt_generic($td, $clear); + mcrypt_generic_deinit($td); + mcrypt_module_close($td); + } + else { + @include_once 'des.inc'; + + if (function_exists('des')) { + $des_iv_size = 8; + $iv = $this->create_iv($des_iv_size); + $cipher = $iv . des($this->config->get_crypto_key($key), $clear, 1, 1, $iv); + } + else { + raise_error(array( + 'code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not perform encryption; make sure Mcrypt is installed or lib/des.inc is available" + ), true, true); + } + } + + return $base64 ? base64_encode($cipher) : $cipher; + } + + /** + * Decrypt 3DES-encrypted string + * + * @param string $cipher encrypted text + * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key' + * @param boolean $base64 whether or not input is base64-encoded + * + * @return string decrypted text + */ + public function decrypt($cipher, $key = 'des_key', $base64 = true) + { + if (!$cipher) + return ''; + + $cipher = $base64 ? base64_decode($cipher) : $cipher; + + if (function_exists('mcrypt_module_open') && + ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) + { + $iv_size = mcrypt_enc_get_iv_size($td); + $iv = substr($cipher, 0, $iv_size); + + // session corruption? (#1485970) + if (strlen($iv) < $iv_size) + return ''; + + $cipher = substr($cipher, $iv_size); + mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); + $clear = mdecrypt_generic($td, $cipher); + mcrypt_generic_deinit($td); + mcrypt_module_close($td); + } + else { + @include_once 'des.inc'; + + if (function_exists('des')) { + $des_iv_size = 8; + $iv = substr($cipher, 0, $des_iv_size); + $cipher = substr($cipher, $des_iv_size); + $clear = des($this->config->get_crypto_key($key), $cipher, 0, 1, $iv); + } + else { + raise_error(array( + 'code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not perform decryption; make sure Mcrypt is installed or lib/des.inc is available" + ), true, true); + } + } + + /*- + * Trim PHP's padding and the canary byte; see note in + * rcmail::encrypt() and http://php.net/mcrypt_generic#68082 + */ + $clear = substr(rtrim($clear, "\0"), 0, -1); + + return $clear; + } + + /** + * Generates encryption initialization vector (IV) + * + * @param int Vector size + * @return string Vector string + */ + private function create_iv($size) + { + // mcrypt_create_iv() can be slow when system lacks entrophy + // we'll generate IV vector manually + $iv = ''; + for ($i = 0; $i < $size; $i++) + $iv .= chr(mt_rand(0, 255)); + return $iv; + } + + /** + * Build a valid URL to this instance of Roundcube + * + * @param mixed Either a string with the action or url parameters as key-value pairs + * @return string Valid application URL + */ + public function url($p) + { + if (!is_array($p)) + $p = array('_action' => @func_get_arg(0)); + + $task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task); + $p['_task'] = $task; + unset($p['task']); + + $url = './'; + $delm = '?'; + foreach (array_reverse($p) as $key => $val) { + if ($val !== '') { + $par = $key[0] == '_' ? $key : '_'.$key; + $url .= $delm.urlencode($par).'='.urlencode($val); + $delm = '&'; + } + } + return $url; + } + + + /** + * Use imagemagick or GD lib to read image properties + * + * @param string Absolute file path + * @return mixed Hash array with image props like type, width, height or False on error + */ + public static function imageprops($filepath) + { + $rcmail = rcmail::get_instance(); + if ($cmd = $rcmail->config->get('im_identify_path', false)) { + list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath)))); + if ($size) + list($width, $height) = explode('x', $size); + } + else if (function_exists('getimagesize')) { + $imsize = @getimagesize($filepath); + $width = $imsize[0]; + $height = $imsize[1]; + $type = preg_replace('!image/!', '', $imsize['mime']); + } + + return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false; + } + + + /** + * Convert an image to a given size and type using imagemagick (ensures input is an image) + * + * @param $p['in'] Input filename (mandatory) + * @param $p['out'] Output filename (mandatory) + * @param $p['size'] Width x height of resulting image, e.g. "160x60" + * @param $p['type'] Output file type, e.g. "jpg" + * @param $p['-opts'] Custom command line options to ImageMagick convert + * @return Success of convert as true/false + */ + public static function imageconvert($p) + { + $result = false; + $rcmail = rcmail::get_instance(); + $convert = $rcmail->config->get('im_convert_path', false); + $identify = $rcmail->config->get('im_identify_path', false); + + // imagemagick is required for this + if (!$convert) + return false; + + if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false)))) + list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps + + $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps")); + $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75); + $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts']; + + if (in_array($type, explode(',', $p['types']))) # Valid type? + $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ""; + + return $result; + } + + + /** + * Construct shell command, execute it and return output as string. + * Keywords {keyword} are replaced with arguments + * + * @param $cmd Format string with {keywords} to be replaced + * @param $values (zero, one or more arrays can be passed) + * @return output of command. shell errors not detectable + */ + public static function exec(/* $cmd, $values1 = array(), ... */) + { + $args = func_get_args(); + $cmd = array_shift($args); + $values = $replacements = array(); + + // merge values into one array + foreach ($args as $arg) + $values += (array)$arg; + + preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER); + foreach ($matches as $tags) { + list(, $tag, $option, $key) = $tags; + $parts = array(); + + if ($option) { + foreach ((array)$values["-$key"] as $key => $value) { + if ($value === true || $value === false || $value === null) + $parts[] = $value ? $key : ""; + else foreach ((array)$value as $val) + $parts[] = "$key " . escapeshellarg($val); + } + } + else { + foreach ((array)$values[$key] as $value) + $parts[] = escapeshellarg($value); + } + + $replacements[$tag] = join(" ", $parts); + } + + // use strtr behaviour of going through source string once + $cmd = strtr($cmd, $replacements); + + return (string)shell_exec($cmd); + } + + + /** + * Helper method to set a cookie with the current path and host settings + * + * @param string Cookie name + * @param string Cookie value + * @param string Expiration time + */ + public static function setcookie($name, $value, $exp = 0) + { + if (headers_sent()) + return; + + $cookie = session_get_cookie_params(); + + setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'], + rcube_https_check(), true); + } + + /** + * Registers action aliases for current task + * + * @param array $map Alias-to-filename hash array + */ + public function register_action_map($map) + { + if (is_array($map)) { + foreach ($map as $idx => $val) { + $this->action_map[$idx] = $val; + } + } + } + + /** + * Returns current action filename + * + * @param array $map Alias-to-filename hash array + */ + public function get_action_file() + { + if (!empty($this->action_map[$this->action])) { + return $this->action_map[$this->action]; + } + + return strtr($this->action, '-', '_') . '.inc'; + } + + /** + * Fixes some user preferences according to namespace handling change. + * Old Roundcube versions were using folder names with removed namespace prefix. + * Now we need to add the prefix on servers where personal namespace has prefix. + * + * @param rcube_user $user User object + */ + private function fix_namespace_settings($user) + { + $prefix = $this->imap->get_namespace('prefix'); + $prefix_len = strlen($prefix); + + if (!$prefix_len) + return; + + $prefs = $this->config->all(); + if (!empty($prefs['namespace_fixed'])) + return; + + // Build namespace prefix regexp + $ns = $this->imap->get_namespace(); + $regexp = array(); + + foreach ($ns as $entry) { + if (!empty($entry)) { + foreach ($entry as $item) { + if (strlen($item[0])) { + $regexp[] = preg_quote($item[0], '/'); + } + } + } + } + $regexp = '/^('. implode('|', $regexp).')/'; + + // Fix preferences + $opts = array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox', 'archive_mbox'); + foreach ($opts as $opt) { + if ($value = $prefs[$opt]) { + if ($value != 'INBOX' && !preg_match($regexp, $value)) { + $prefs[$opt] = $prefix.$value; + } + } + } + + if (!empty($prefs['default_imap_folders'])) { + foreach ($prefs['default_imap_folders'] as $idx => $name) { + if ($name != 'INBOX' && !preg_match($regexp, $name)) { + $prefs['default_imap_folders'][$idx] = $prefix.$name; + } + } + } + + if (!empty($prefs['search_mods'])) { + $folders = array(); + foreach ($prefs['search_mods'] as $idx => $value) { + if ($idx != 'INBOX' && $idx != '*' && !preg_match($regexp, $idx)) { + $idx = $prefix.$idx; + } + $folders[$idx] = $value; + } + $prefs['search_mods'] = $folders; + } + + if (!empty($prefs['message_threading'])) { + $folders = array(); + foreach ($prefs['message_threading'] as $idx => $value) { + if ($idx != 'INBOX' && !preg_match($regexp, $idx)) { + $idx = $prefix.$idx; + } + $folders[$prefix.$idx] = $value; + } + $prefs['message_threading'] = $folders; + } + + if (!empty($prefs['collapsed_folders'])) { + $folders = explode('&&', $prefs['collapsed_folders']); + $count = count($folders); + $folders_str = ''; + + if ($count) { + $folders[0] = substr($folders[0], 1); + $folders[$count-1] = substr($folders[$count-1], 0, -1); + } + + foreach ($folders as $value) { + if ($value != 'INBOX' && !preg_match($regexp, $value)) { + $value = $prefix.$value; + } + $folders_str .= '&'.$value.'&'; + } + $prefs['collapsed_folders'] = $folders_str; + } + + $prefs['namespace_fixed'] = true; + + // save updated preferences and reset imap settings (default folders) + $user->save_prefs($prefs); + $this->set_imap_prop(); + } + +} diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php index fc8c441..b9a3acb 100644 --- a/program/include/rcube_addressbook.php +++ b/program/include/rcube_addressbook.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_addressbook.php 4965 2011-07-25 11:48:50Z alec $ + $Id: rcube_addressbook.php 5415 2011-11-11 15:04:45Z alec $ */ @@ -30,7 +30,7 @@ abstract class rcube_addressbook /** constants for error reporting **/ const ERROR_READ_ONLY = 1; const ERROR_NO_CONNECTION = 2; - const ERROR_INCOMPLETE = 3; + const ERROR_VALIDATE = 3; const ERROR_SAVING = 4; const ERROR_SEARCH = 5; @@ -38,6 +38,7 @@ abstract class rcube_addressbook public $primary_key; public $groups = false; public $readonly = true; + public $searchonly = false; public $undelete = false; public $ready = false; public $group_id = null; @@ -95,12 +96,16 @@ abstract class rcube_addressbook * * @param array List of fields to search in * @param string Search value + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) * @param boolean True if results are requested, False if count only * @param boolean True to skip the count query (select only) * @param array List of fields that cannot be empty * @return object rcube_result_set List of contact records and 'count' value */ - abstract function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()); + abstract function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()); /** * Count number of available contacts in database @@ -181,15 +186,16 @@ abstract class rcube_addressbook * If input isn't valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save + * @param boolean Attempt to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // check validity of email addresses foreach ($this->get_col_values('email', $save_data, true) as $email) { if (strlen($email)) { if (!check_email(rcube_idn_to_ascii($email))) { - $this->set_error('warning', rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email)))); + $this->set_error(self::ERROR_VALIDATE, rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email)))); return false; } } @@ -293,6 +299,18 @@ abstract class rcube_addressbook return array(); } + /** + * Get group properties such as name and email address(es) + * + * @param string Group identifier + * @return array Group properties as hash array + */ + function get_group($group_id) + { + /* empty for address books don't supporting groups */ + return null; + } + /** * Create a contact group with the given name * @@ -385,7 +403,7 @@ abstract class rcube_addressbook { $out = array(); foreach ($data as $c => $values) { - if (strpos($c, $col) === 0) { + if ($c === $col || strpos($c, $col.':') === 0) { if ($flat) { $out = array_merge($out, (array)$values); } diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php index 10b214c..1727586 100644 --- a/program/include/rcube_browser.php +++ b/program/include/rcube_browser.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_browser.php 4971 2011-07-27 06:37:17Z alec $ + $Id: rcube_browser.php 5499 2011-11-28 09:03:27Z alec $ */ @@ -33,19 +33,19 @@ class rcube_browser $HTTP_USER_AGENT = strtolower($_SERVER['HTTP_USER_AGENT']); $this->ver = 0; - $this->win = strstr($HTTP_USER_AGENT, 'win'); - $this->mac = strstr($HTTP_USER_AGENT, 'mac'); - $this->linux = strstr($HTTP_USER_AGENT, 'linux'); - $this->unix = strstr($HTTP_USER_AGENT, 'unix'); + $this->win = strpos($HTTP_USER_AGENT, 'win') != false; + $this->mac = strpos($HTTP_USER_AGENT, 'mac') != false; + $this->linux = strpos($HTTP_USER_AGENT, 'linux') != false; + $this->unix = strpos($HTTP_USER_AGENT, 'unix') != false; - $this->opera = strstr($HTTP_USER_AGENT, 'opera'); - $this->ns4 = strstr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie'); - $this->ns = ($this->ns4 || strstr($HTTP_USER_AGENT, 'netscape')); - $this->ie = !$this->opera && stristr($HTTP_USER_AGENT, 'compatible; msie'); - $this->mz = !$this->ie && strstr($HTTP_USER_AGENT, 'mozilla/5'); - $this->chrome = strstr($HTTP_USER_AGENT, 'chrome'); - $this->khtml = strstr($HTTP_USER_AGENT, 'khtml'); - $this->safari = !$this->chrome && ($this->khtml || strstr($HTTP_USER_AGENT, 'safari')); + $this->opera = strpos($HTTP_USER_AGENT, 'opera') !== false; + $this->ns4 = strpos($HTTP_USER_AGENT, 'mozilla/4') !== false && strpos($HTTP_USER_AGENT, 'msie') === false; + $this->ns = ($this->ns4 || strpos($HTTP_USER_AGENT, 'netscape') !== false); + $this->ie = !$this->opera && strpos($HTTP_USER_AGENT, 'compatible; msie') !== false; + $this->mz = !$this->ie && strpos($HTTP_USER_AGENT, 'mozilla/5') !== false; + $this->chrome = strpos($HTTP_USER_AGENT, 'chrome') !== false; + $this->khtml = strpos($HTTP_USER_AGENT, 'khtml') !== false; + $this->safari = !$this->chrome && ($this->khtml || strpos($HTTP_USER_AGENT, 'safari') !== false); if ($this->ns || $this->chrome) { $test = preg_match('/(mozilla|chrome)\/([0-9.]+)/', $HTTP_USER_AGENT, $regs); diff --git a/program/include/rcube_cache.php b/program/include/rcube_cache.php index 7224ee6..cc472ae 100644 --- a/program/include/rcube_cache.php +++ b/program/include/rcube_cache.php @@ -17,7 +17,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: rcube_cache.php 4909 2011-07-05 17:09:25Z alec $ + $Id: rcube_cache.php 5305 2011-10-03 18:04:14Z alec $ */ @@ -28,7 +28,7 @@ * @package Cache * @author Thomas Bruederli <roundcube@gmail.com> * @author Aleksander Machniak <alec@alec.pl> - * @version 1.0 + * @version 1.1 */ class rcube_cache { @@ -187,6 +187,24 @@ class rcube_cache } + /** + * Remove cache records older than ttl + */ + function expunge() + { + if ($this->type == 'db' && $this->db) { + $this->db->query( + "DELETE FROM ".get_table_name('cache'). + " WHERE user_id = ?". + " AND cache_key LIKE ?". + " AND " . $this->db->unixtimestamp('created')." < ?", + $this->userid, + $this->prefix.'.%', + time() - $this->ttl); + } + } + + /** * Writes the cache back to the DB. */ @@ -227,26 +245,30 @@ class rcube_cache return null; } - if ($this->type == 'memcache') { - $data = $this->db->get($this->ckey($key)); - } - else if ($this->type == 'apc') { - $data = apc_fetch($this->ckey($key)); - } + if ($this->type != 'db') { + if ($this->type == 'memcache') { + $data = $this->db->get($this->ckey($key)); + } + else if ($this->type == 'apc') { + $data = apc_fetch($this->ckey($key)); + } - if ($data) { - $md5sum = md5($data); - $data = $this->packed ? unserialize($data) : $data; + if ($data) { + $md5sum = md5($data); + $data = $this->packed ? unserialize($data) : $data; - if ($nostore) { - return $data; - } + if ($nostore) { + return $data; + } - $this->cache_sums[$key] = $md5sum; - $this->cache[$key] = $data; + $this->cache_sums[$key] = $md5sum; + $this->cache[$key] = $data; + } + else { + $this->cache[$key] = null; + } } - - if ($this->type == 'db') { + else { $sql_result = $this->db->limitquery( "SELECT cache_id, data, cache_key". " FROM ".get_table_name('cache'). @@ -272,6 +294,9 @@ class rcube_cache $this->cache_sums[$key] = $md5sum; $this->cache_keys[$key] = $sql_arr['cache_id']; } + else { + $this->cache[$key] = null; + } } return $this->cache[$key]; diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php index 7d46df0..ceada11 100644 --- a/program/include/rcube_config.php +++ b/program/include/rcube_config.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_config.php 5151 2011-08-31 12:49:44Z alec $ + $Id: rcube_config.php 5499 2011-11-28 09:03:27Z alec $ */ @@ -91,6 +91,15 @@ 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['dst_active'] = intval(date('I')); + $this->prop['_timezone_value'] = date('Z') / 3600 - $this->prop['dst_active']; + } + else if ($this->prop['dst_active'] === null) { + $this->prop['dst_active'] = intval(date('I')); + } + // export config data $GLOBALS['CONFIG'] = &$this->prop; } @@ -152,6 +161,9 @@ class rcube_config { $result = isset($this->prop[$name]) ? $this->prop[$name] : $def; $rcmail = rcmail::get_instance(); + + if ($name == 'timezone' && isset($this->prop['_timezone_value'])) + $result = $this->prop['_timezone_value']; if (is_object($rcmail->plugins)) { $plugin = $rcmail->plugins->exec_hook('config_get', array( @@ -207,6 +219,14 @@ 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']) ? $_SESSION['timezone'] : $this->prop['_timezone_value']; + $this->prop['dst_active'] = $this->userprefs['dst_active'] = isset($_SESSION['dst_active']) ? $_SESSION['dst_active'] : $this->prop['dst_active']; + } + else if (isset($this->prop['_timezone_value'])) + unset($this->prop['_timezone_value']); } @@ -221,17 +241,13 @@ class rcube_config } /** - * Special getter for user's timezone + * Special getter for user's timezone offset including DST + * + * @return float Timezone offset (in hours) */ public function get_timezone() { - $tz = $this->get('timezone'); - if ($tz == 'auto') - $tz = isset($_SESSION['timezone']) ? $_SESSION['timezone'] : date('Z') / 3600; - else - $tz = intval($tz) + intval($this->get('dst_active')); - - return $tz; + return floatval($this->get('timezone')) + intval($this->get('dst_active')); } /** diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php index af07b32..a288315 100644 --- a/program/include/rcube_contacts.php +++ b/program/include/rcube_contacts.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_contacts.php 5011 2011-08-03 09:32:45Z alec $ + $Id: rcube_contacts.php 5415 2011-11-11 15:04:45Z alec $ */ @@ -41,7 +41,6 @@ class rcube_contacts extends rcube_addressbook private $user_id = 0; private $filter = null; private $result = null; - private $name; private $cache; private $table_cols = array('name', 'email', 'firstname', 'surname'); private $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'nickname', @@ -50,6 +49,7 @@ class rcube_contacts extends rcube_addressbook // public properties public $primary_key = 'contact_id'; + public $name; public $readonly = false; public $groups = true; public $undelete = true; @@ -163,6 +163,29 @@ class rcube_contacts extends rcube_addressbook } + /** + * Get group properties such as name and email address(es) + * + * @param string Group identifier + * @return array Group properties as hash array + */ + function get_group($group_id) + { + $sql_result = $this->db->query( + "SELECT * FROM ".get_table_name($this->db_groups). + " WHERE del<>1". + " AND contactgroup_id=?". + " AND user_id=?", + $group_id, $this->user_id); + + if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { + $sql_arr['ID'] = $sql_arr['contactgroup_id']; + return $sql_arr; + } + + return null; + } + /** * List the current set of contact records * @@ -245,14 +268,17 @@ class rcube_contacts extends rcube_addressbook * * @param mixed $fields The field name of array of field names to search in * @param mixed $value Search value (or array of values when $fields is array) - * @param boolean $strict True for strict (=), False for partial (LIKE) matching + * @param int $mode Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) * @param boolean $select True if results are requested, False if count only * @param boolean $nocount True to skip the count query (select only) * @param array $required List of fields that cannot be empty * * @return object rcube_result_set Contact records and 'count' value */ - function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) + function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()) { if (!is_array($fields)) $fields = array($fields); @@ -260,6 +286,7 @@ class rcube_contacts extends rcube_addressbook $required = array($required); $where = $and_where = array(); + $mode = intval($mode); foreach ($fields as $idx => $col) { // direct ID search @@ -272,26 +299,56 @@ class rcube_contacts extends rcube_addressbook // fulltext search in all fields else if ($col == '*') { $words = array(); - foreach (explode(" ", self::normalize_string($value)) as $word) - $words[] = $this->db->ilike('words', '%'.$word.'%'); + foreach (explode(" ", self::normalize_string($value)) as $word) { + switch ($mode) { + case 1: // strict + $words[] = '(' . $this->db->ilike('words', $word.' %') + . ' OR ' . $this->db->ilike('words', '% '.$word.' %') + . ' OR ' . $this->db->ilike('words', '% '.$word) . ')'; + break; + case 2: // prefix + $words[] = '(' . $this->db->ilike('words', $word.'%') + . ' OR ' . $this->db->ilike('words', '% '.$word.'%') . ')'; + break; + default: // partial + $words[] = $this->db->ilike('words', '%'.$word.'%'); + } + } $where[] = '(' . join(' AND ', $words) . ')'; } else { $val = is_array($value) ? $value[$idx] : $value; // table column if (in_array($col, $this->table_cols)) { - if ($strict) { + switch ($mode) { + case 1: // strict $where[] = $this->db->quoteIdentifier($col).' = '.$this->db->quote($val); - } - else { + break; + case 2: // prefix + $where[] = $this->db->ilike($col, $val.'%'); + break; + default: // partial $where[] = $this->db->ilike($col, '%'.$val.'%'); } } // vCard field else { if (in_array($col, $this->fulltext_cols)) { - foreach (explode(" ", self::normalize_string($val)) as $word) - $words[] = $this->db->ilike('words', '%'.$word.'%'); + foreach (explode(" ", self::normalize_string($val)) as $word) { + switch ($mode) { + case 1: // strict + $words[] = '(' . $this->db->ilike('words', $word.' %') + . ' OR ' . $this->db->ilike('words', '% '.$word.' %') + . ' OR ' . $this->db->ilike('words', '% '.$word) . ')'; + break; + case 2: // prefix + $words[] = '(' . $this->db->ilike('words', $word.'%') + . ' OR ' . $this->db->ilike('words', ' '.$word.'%') . ')'; + break; + default: // partial + $words[] = $this->db->ilike('words', '%'.$word.'%'); + } + } $where[] = '(' . join(' AND ', $words) . ')'; } if (is_array($value)) @@ -339,13 +396,24 @@ class rcube_contacts extends rcube_addressbook $search = $post_search[$colname]; foreach ((array)$row[$col] as $value) { // composite field, e.g. address - if (is_array($value)) { - $value = implode($value); - } - $value = mb_strtolower($value); - if (($strict && $value == $search) || (!$strict && strpos($value, $search) !== false)) { - $found[$colname] = true; - break; + foreach ((array)$value as $val) { + $val = mb_strtolower($val); + switch ($mode) { + case 1: + $got = ($val == $search); + break; + case 2: + $got = ($search == substr($val, 0, strlen($search))); + break; + default: + $got = (strpos($val, $search) !== false); + break; + } + + if ($got) { + $found[$colname] = true; + break 2; + } } } } @@ -500,16 +568,17 @@ class rcube_contacts extends rcube_addressbook * If input not valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save + * @param boolean Try to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // validate e-mail addresses - $valid = parent::validate($save_data); + $valid = parent::validate($save_data, $autofix); // require at least one e-mail address (syntax check is already done) if ($valid && !array_filter($this->get_col_values('email', $save_data, true))) { - $this->set_error('warning', 'noemailwarning'); + $this->set_error(self::ERROR_VALIDATE, 'noemailwarning'); $valid = false; } @@ -773,8 +842,9 @@ class rcube_contacts extends rcube_addressbook $sql_result = $this->db->query( "UPDATE ".get_table_name($this->db_groups). " SET del=1, changed=".$this->db->now(). - " WHERE contactgroup_id=?", - $gid + " WHERE contactgroup_id=?". + " AND user_id=?", + $gid, $this->user_id ); $this->cache = null; @@ -798,8 +868,9 @@ class rcube_contacts extends rcube_addressbook $sql_result = $this->db->query( "UPDATE ".get_table_name($this->db_groups). " SET name=?, changed=".$this->db->now(). - " WHERE contactgroup_id=?", - $name, $gid + " WHERE contactgroup_id=?". + " AND user_id=?", + $name, $gid, $this->user_id ); return $this->db->affected_rows() ? $name : false; diff --git a/program/include/rcube_html_page.php b/program/include/rcube_html_page.php index f57f6a6..77b7ff2 100644 --- a/program/include/rcube_html_page.php +++ b/program/include/rcube_html_page.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_html_page.php 5151 2011-08-31 12:49:44Z alec $ + $Id: rcube_html_page.php 5135 2011-08-26 09:22:53Z alec $ */ diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 48627d8..b48adcf 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -5,7 +5,8 @@ | program/include/rcube_imap.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -16,7 +17,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: rcube_imap.php 5281 2011-09-27 07:29:49Z alec $ + $Id: rcube_imap.php 5601 2011-12-14 09:08:54Z alec $ */ @@ -31,7 +32,6 @@ */ class rcube_imap { - public $debug_level = 1; public $skip_deleted = false; public $page_size = 10; public $list_page = 1; @@ -47,11 +47,11 @@ class rcube_imap public $conn; /** - * Instance of rcube_mdb2 + * Instance of rcube_imap_cache * - * @var rcube_mdb2 + * @var rcube_imap_cache */ - private $db; + private $mcache; /** * Instance of rcube_cache @@ -59,6 +59,14 @@ class rcube_imap * @var rcube_cache */ private $cache; + + /** + * Internal (in-memory) cache + * + * @var array + */ + private $icache = array(); + private $mailbox = 'INBOX'; private $delimiter = NULL; private $namespace = NULL; @@ -67,8 +75,6 @@ class rcube_imap private $default_charset = 'ISO-8859-1'; private $struct_charset = NULL; private $default_folders = array('INBOX'); - private $messages_caching = false; - private $icache = array(); private $uid_id_map = array(); private $msg_headers = array(); public $search_set = NULL; @@ -77,10 +83,10 @@ class rcube_imap private $search_sort_field = ''; private $search_threads = false; private $search_sorted = false; - private $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size'); private $options = array('auth_method' => 'check'); private $host, $user, $pass, $port, $ssl; private $caching = false; + private $messages_caching = false; /** * All (additional) headers used (in any way) by Roundcube @@ -96,7 +102,6 @@ class rcube_imap 'MESSAGE-ID', 'CONTENT-TRANSFER-ENCODING', 'REFERENCES', - 'X-PRIORITY', 'X-DRAFT-INFO', 'MAIL-FOLLOWUP-TO', 'MAIL-REPLY-TO', @@ -170,12 +175,13 @@ class rcube_imap $attempt = 0; do { $data = rcmail::get_instance()->plugins->exec_hook('imap_connect', - array('host' => $host, 'user' => $user, 'attempt' => ++$attempt)); + array_merge($this->options, array('host' => $host, 'user' => $user, + 'attempt' => ++$attempt))); if (!empty($data['pass'])) $pass = $data['pass']; - $this->conn->connect($data['host'], $data['user'], $pass, $this->options); + $this->conn->connect($data['host'], $data['user'], $pass, $data); } while(!$this->conn->connected() && $data['retry']); $this->host = $data['host']; @@ -214,6 +220,8 @@ class rcube_imap function close() { $this->conn->closeConnection(); + if ($this->mcache) + $this->mcache->close(); } @@ -308,6 +316,19 @@ class rcube_imap } + /** + * Activate/deactivate debug mode + * + * @param boolean $dbg True if IMAP conversation should be logged + * @access public + */ + function set_debug($dbg = true) + { + $this->options['debug'] = $dbg; + $this->conn->setDebug($dbg, array($this, 'debug_handler')); + } + + /** * Set default message charset * @@ -457,7 +478,7 @@ class rcube_imap */ function get_mailbox_name() { - return $this->conn->connected() ? $this->mailbox : ''; + return $this->mailbox; } @@ -689,7 +710,7 @@ class rcube_imap if ($status) { $this->set_folder_stats($mailbox, 'cnt', $res['msgcount']); - $this->set_folder_stats($mailbox, 'maxuid', $res['maxuid'] ? $this->_id2uid($res['maxuid'], $mailbox) : 0); + $this->set_folder_stats($mailbox, 'maxuid', $res['maxuid'] ? $this->id2uid($res['maxuid'], $mailbox) : 0); } } // RECENT count is fetched a bit different @@ -722,9 +743,9 @@ class rcube_imap $count = is_array($index) ? $index['COUNT'] : 0; if ($mode == 'ALL') { - if ($need_uid && $this->messages_caching) { - // Save messages index for check_cache_status() - $this->icache['all_undeleted_idx'] = $index['ALL']; + if ($this->messages_caching) { + // Save additional info required by cache status check + $this->icache['undeleted_idx'] = array($mailbox, $index['ALL'], $index['COUNT']); } if ($status) { $this->set_folder_stats($mailbox, 'cnt', $count); @@ -739,7 +760,7 @@ class rcube_imap $count = $this->conn->countMessages($mailbox); if ($status) { $this->set_folder_stats($mailbox,'cnt', $count); - $this->set_folder_stats($mailbox, 'maxuid', $count ? $this->_id2uid($count, $mailbox) : 0); + $this->set_folder_stats($mailbox, 'maxuid', $count ? $this->id2uid($count, $mailbox) : 0); } } } @@ -774,7 +795,7 @@ class rcube_imap 'maxuid' => $dcount ? max(array_keys($this->icache['threads']['depth'])) : 0, ); } - else if (is_array($result = $this->_fetch_threads($mailbox))) { + else if (is_array($result = $this->fetch_threads($mailbox))) { $dcount = count($result[1]); $result = array( 'count' => count($result[0]), @@ -805,7 +826,7 @@ class rcube_imap $mailbox = $this->mailbox; } - return $this->_list_headers($mailbox, $page, $sort_field, $sort_order, false, $slice); + return $this->_list_headers($mailbox, $page, $sort_field, $sort_order, $slice); } @@ -817,11 +838,11 @@ class rcube_imap * @param string $sort_field Header field to sort by * @param string $sort_order Sort order [ASC|DESC] * @param int $slice Number of slice items to extract from result array + * * @return array Indexed array with message header objects - * @access private * @see rcube_imap::list_headers */ - private function _list_headers($mailbox='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $recursive=false, $slice=0) + private function _list_headers($mailbox='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) { if (!strlen($mailbox)) return array(); @@ -831,41 +852,39 @@ class rcube_imap return $this->_list_header_set($mailbox, $page, $sort_field, $sort_order, $slice); if ($this->threading) - return $this->_list_thread_headers($mailbox, $page, $sort_field, $sort_order, $recursive, $slice); + return $this->_list_thread_headers($mailbox, $page, $sort_field, $sort_order, $slice); $this->_set_sort_order($sort_field, $sort_order); - $page = $page ? $page : $this->list_page; - $cache_key = $mailbox.'.msg'; - - if ($this->messages_caching) { - // cache is OK, we can get messages from local cache - // (assume cache is in sync when in recursive mode) - if ($recursive || $this->check_cache_status($mailbox, $cache_key)>0) { - $start_msg = ($page-1) * $this->page_size; - $a_msg_headers = $this->get_message_cache($cache_key, $start_msg, - $start_msg+$this->page_size, $this->sort_field, $this->sort_order); - $result = array_values($a_msg_headers); - if ($slice) - $result = array_slice($result, -$slice, $slice); - return $result; - } - // cache is incomplete, sync it (all messages in the folder) - else if (!$recursive) { - $this->sync_header_index($mailbox); - return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, true, $slice); - } - } + $page = $page ? $page : $this->list_page; - // retrieve headers from IMAP - $a_msg_headers = array(); + // Use messages cache + if ($mcache = $this->get_mcache_engine()) { + $msg_index = $mcache->get_index($mailbox, $this->sort_field, $this->sort_order); + + if (empty($msg_index)) + return array(); + + $from = ($page-1) * $this->page_size; + $to = $from + $this->page_size; + $msg_index = array_values($msg_index); // UIDs + $is_uid = true; + $sorted = true; + + if ($from || $to) + $msg_index = array_slice($msg_index, $from, $to - $from); + if ($slice) + $msg_index = array_slice($msg_index, -$slice, $slice); + + $a_msg_headers = $mcache->get_messages($mailbox, $msg_index); + } + // retrieve headers from IMAP // use message index sort as default sorting (for better performance) - if (!$this->sort_field) { + else if (!$this->sort_field) { if ($this->skip_deleted) { // @TODO: this could be cached if ($msg_index = $this->_search_index($mailbox, 'ALL UNDELETED')) { - $max = max($msg_index); list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end-$begin); } @@ -882,30 +901,32 @@ class rcube_imap // fetch reqested headers from server if ($msg_index) - $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key); + $a_msg_headers = $this->fetch_headers($mailbox, $msg_index); } // use SORT command else if ($this->get_capability('SORT') && // Courier-IMAP provides SORT capability but allows to disable it by admin (#1486959) - ($msg_index = $this->conn->sort($mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) !== false + ($msg_index = $this->conn->sort($mailbox, $this->sort_field, + $this->skip_deleted ? 'UNDELETED' : '', true)) !== false ) { if (!empty($msg_index)) { list($begin, $end) = $this->_get_message_range(count($msg_index), $page); - $max = max($msg_index); $msg_index = array_slice($msg_index, $begin, $end-$begin); + $is_uid = true; if ($slice) $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice); // fetch reqested headers from server - $this->_fetch_headers($mailbox, join(',', $msg_index), $a_msg_headers, $cache_key); + $a_msg_headers = $this->fetch_headers($mailbox, $msg_index, true); } } // fetch specified header for all messages and sort - else if ($a_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { - asort($a_index); // ASC - $msg_index = array_keys($a_index); - $max = max($msg_index); + else if ($msg_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", + $this->sort_field, $this->skip_deleted) + ) { + asort($msg_index); // ASC + $msg_index = array_keys($msg_index); list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end-$begin); @@ -913,26 +934,19 @@ class rcube_imap $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice); // fetch reqested headers from server - $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key); + $a_msg_headers = $this->fetch_headers($mailbox, $msg_index); } - // delete cached messages with a higher index than $max+1 - // Changed $max to $max+1 to fix this bug : #1484295 - $this->clear_message_cache($cache_key, $max + 1); - - // kick child process to sync cache - // ... - // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) return array(); // use this class for message sorting $sorter = new rcube_header_sorter(); - $sorter->set_sequence_numbers($msg_index); + $sorter->set_index($msg_index, $is_uid); $sorter->sort_headers($a_msg_headers); - if ($this->sort_order == 'DESC') + if ($this->sort_order == 'DESC' && !$sorted) $a_msg_headers = array_reverse($a_msg_headers); return array_values($a_msg_headers); @@ -946,27 +960,28 @@ class rcube_imap * @param int $page Current page to list * @param string $sort_field Header field to sort by * @param string $sort_order Sort order [ASC|DESC] - * @param boolean $recursive True if called recursively * @param int $slice Number of slice items to extract from result array + * * @return array Indexed array with message header objects - * @access private * @see rcube_imap::list_headers */ - private function _list_thread_headers($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $recursive=false, $slice=0) + private function _list_thread_headers($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) { $this->_set_sort_order($sort_field, $sort_order); - $page = $page ? $page : $this->list_page; -// $cache_key = $mailbox.'.msg'; -// $cache_status = $this->check_cache_status($mailbox, $cache_key); + $page = $page ? $page : $this->list_page; + $mcache = $this->get_mcache_engine(); - // get all threads (default sort order) - list ($thread_tree, $msg_depth, $has_children) = $this->_fetch_threads($mailbox); + // get all threads (not sorted) + if ($mcache) + list ($thread_tree, $msg_depth, $has_children) = $mcache->get_thread($mailbox); + else + list ($thread_tree, $msg_depth, $has_children) = $this->fetch_threads($mailbox); if (empty($thread_tree)) return array(); - $msg_index = $this->_sort_threads($mailbox, $thread_tree); + $msg_index = $this->sort_threads($mailbox, $thread_tree); return $this->_fetch_thread_headers($mailbox, $thread_tree, $msg_depth, $has_children, $msg_index, $page, $slice); @@ -974,14 +989,20 @@ class rcube_imap /** - * Private method for fetching threads data + * Method for fetching threads data + * + * @param string $mailbox Folder name + * @param bool $force Use IMAP server, no cache * - * @param string $mailbox Mailbox/folder name * @return array Array with thread data - * @access private */ - private function _fetch_threads($mailbox) + function fetch_threads($mailbox, $force = false) { + 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($mailbox); + } + if (empty($this->icache['threads'])) { // get all threads $result = $this->conn->thread($mailbox, $this->threading, @@ -1012,12 +1033,12 @@ class rcube_imap * @param array $msg_index Messages index * @param int $page List page number * @param int $slice Number of threads to slice + * * @return array Messages headers * @access private */ private function _fetch_thread_headers($mailbox, $thread_tree, $msg_depth, $has_children, $msg_index, $page, $slice=0) { - $cache_key = $mailbox.'.msg'; // now get IDs for current page list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $msg_index = array_slice($msg_index, $begin, $end-$begin); @@ -1038,7 +1059,7 @@ class rcube_imap } // fetch reqested headers from server - $this->_fetch_headers($mailbox, $all_ids, $a_msg_headers, $cache_key); + $a_msg_headers = $this->fetch_headers($mailbox, $all_ids); // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) @@ -1046,7 +1067,7 @@ class rcube_imap // use this class for message sorting $sorter = new rcube_header_sorter(); - $sorter->set_sequence_numbers($all_ids); + $sorter->set_index($all_ids); $sorter->sort_headers($a_msg_headers); // Set depth, has_children and unread_children fields in headers @@ -1077,7 +1098,7 @@ class rcube_imap if (!empty($parents)) { $headers[$idx]->parent_uid = end($parents); - if (!$header->seen) + if (empty($header->flags['SEEN'])) $headers[$parents[0]]->unread_children++; } array_push($parents, $header->uid); @@ -1135,11 +1156,11 @@ class rcube_imap $msgs = array_slice($msgs, -$slice, $slice); // fetch headers - $this->_fetch_headers($mailbox, join(',',$msgs), $a_msg_headers, NULL); + $a_msg_headers = $this->fetch_headers($mailbox, $msgs); // I didn't found in RFC that FETCH always returns messages sorted by index $sorter = new rcube_header_sorter(); - $sorter->set_sequence_numbers($msgs); + $sorter->set_index($msgs); $sorter->sort_headers($a_msg_headers); return array_values($a_msg_headers); @@ -1165,10 +1186,10 @@ class rcube_imap $msgs = array_slice($msgs, -$slice, $slice); // fetch headers - $this->_fetch_headers($mailbox, join(',',$msgs), $a_msg_headers, NULL); + $a_msg_headers = $this->fetch_headers($mailbox, $msgs); $sorter = new rcube_header_sorter(); - $sorter->set_sequence_numbers($msgs); + $sorter->set_index($msgs); $sorter->sort_headers($a_msg_headers); return array_values($a_msg_headers); @@ -1184,21 +1205,22 @@ class rcube_imap if ($slice) $msgs = array_slice($msgs, -$slice, $slice); // ...and fetch headers - $this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL); + $a_msg_headers = $this->fetch_headers($mailbox, $msgs); + // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) return array(); $sorter = new rcube_header_sorter(); - $sorter->set_sequence_numbers($msgs); + $sorter->set_index($msgs); $sorter->sort_headers($a_msg_headers); return array_values($a_msg_headers); } else { // for small result set we can fetch all messages headers - $this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL); + $a_msg_headers = $this->fetch_headers($mailbox, $msgs); // return empty array if no messages found if (!is_array($a_msg_headers) || empty($a_msg_headers)) @@ -1256,7 +1278,7 @@ class rcube_imap $this->_set_sort_order($sort_field, $sort_order); - $msg_index = $this->_sort_threads($mailbox, $thread_tree, array_keys($msg_depth)); + $msg_index = $this->sort_threads($mailbox, $thread_tree, array_keys($msg_depth)); return $this->_fetch_thread_headers($mailbox, $thread_tree, $msg_depth, $has_children, $msg_index, $page, $slice=0); @@ -1297,64 +1319,37 @@ class rcube_imap /** - * Fetches message headers (used for loop) + * Fetches messages headers + * + * @param string $mailbox Mailbox name + * @param array $msgs Messages sequence numbers + * @param bool $is_uid Enable if $msgs numbers are UIDs + * @param bool $force Disables cache use * - * @param string $mailbox Mailbox name - * @param string $msgs Message index to fetch - * @param array $a_msg_headers Reference to message headers array - * @param string $cache_key Cache index key - * @return int Messages count + * @return array Messages headers indexed by UID * @access private */ - private function _fetch_headers($mailbox, $msgs, &$a_msg_headers, $cache_key) + function fetch_headers($mailbox, $msgs, $is_uid = false, $force = false) { - // fetch reqested headers from server - $a_header_index = $this->conn->fetchHeaders( - $mailbox, $msgs, false, false, $this->get_fetch_headers()); - - if (empty($a_header_index)) - return 0; + if (empty($msgs)) + return array(); - foreach ($a_header_index as $i => $headers) { - $a_msg_headers[$headers->uid] = $headers; + if (!$force && ($mcache = $this->get_mcache_engine())) { + return $mcache->get_messages($mailbox, $msgs, $is_uid); } - // Update cache - if ($this->messages_caching && $cache_key) { - // cache is incomplete? - $cache_index = $this->get_message_cache_index($cache_key); - - foreach ($a_header_index as $headers) { - // message in cache - if ($cache_index[$headers->id] == $headers->uid) { - unset($cache_index[$headers->id]); - continue; - } - // wrong UID at this position - if ($cache_index[$headers->id]) { - $for_remove[] = $cache_index[$headers->id]; - unset($cache_index[$headers->id]); - } - // message UID in cache but at wrong position - if (is_int($key = array_search($headers->uid, $cache_index))) { - $for_remove[] = $cache_index[$key]; - unset($cache_index[$key]); - } - - $for_create[] = $headers->uid; - } + // fetch reqested headers from server + $index = $this->conn->fetchHeaders( + $mailbox, $msgs, $is_uid, false, $this->get_fetch_headers()); - if ($for_remove) - $this->remove_message_cache($cache_key, $for_remove); + if (empty($index)) + return array(); - // add messages to cache - foreach ((array)$for_create as $uid) { - $headers = $a_msg_headers[$uid]; - $this->add_message_cache($cache_key, $headers->id, $headers, NULL, true); - } + foreach ($index as $headers) { + $a_msg_headers[$headers->uid] = $headers; } - return count($a_msg_headers); + return $a_msg_headers; } @@ -1378,6 +1373,11 @@ class rcube_imap $this->_messagecount($mailbox, 'ALL', true); $result = 0; + + if (empty($old)) { + return $result; + } + $new = $this->get_folder_stats($mailbox); // got new messages @@ -1471,7 +1471,7 @@ class rcube_imap } else { $a_index = $this->conn->fetchHeaderIndex($mailbox, - join(',', $this->search_set), $this->sort_field, $this->skip_deleted); + join(',', $this->search_set), $this->sort_field, $this->skip_deleted); if (is_array($a_index)) { if ($this->sort_order=="ASC") @@ -1492,53 +1492,65 @@ class rcube_imap return $this->icache[$key]; // check local cache - $cache_key = $mailbox.'.msg'; - $cache_status = $this->check_cache_status($mailbox, $cache_key); - - // cache is OK - if ($cache_status>0) { - $a_index = $this->get_message_cache_index($cache_key, - $this->sort_field, $this->sort_order); - return array_keys($a_index); + if ($mcache = $this->get_mcache_engine()) { + $a_index = $mcache->get_index($mailbox, $this->sort_field, $this->sort_order); + $this->icache[$key] = array_keys($a_index); + } + // fetch from IMAP server + else { + $this->icache[$key] = $this->message_index_direct( + $mailbox, $this->sort_field, $this->sort_order); } + return $this->icache[$key]; + } + + + /** + * Return sorted array of message IDs (not UIDs) directly from IMAP server. + * Doesn't use cache and ignores current search settings. + * + * @param string $mailbox Mailbox to get index from + * @param string $sort_field Sort column + * @param string $sort_order Sort order [ASC, DESC] + * + * @return array Indexed array with message IDs + */ + function message_index_direct($mailbox, $sort_field = null, $sort_order = null) + { // use message index sort as default sorting - if (!$this->sort_field) { + if (!$sort_field) { if ($this->skip_deleted) { $a_index = $this->conn->search($mailbox, 'ALL UNDELETED'); // I didn't found that SEARCH should return sorted IDs if (is_array($a_index)) sort($a_index); - } else if ($max = $this->_messagecount($mailbox)) { + } else if ($max = $this->_messagecount($mailbox, 'ALL', true, false)) { $a_index = range(1, $max); } - if ($a_index !== false && $this->sort_order == 'DESC') + if ($a_index !== false && $sort_order == 'DESC') $a_index = array_reverse($a_index); - - $this->icache[$key] = $a_index; } // fetch complete message index else if ($this->get_capability('SORT') && ($a_index = $this->conn->sort($mailbox, - $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) !== false + $sort_field, $this->skip_deleted ? 'UNDELETED' : '')) !== false ) { - if ($this->sort_order == 'DESC') + if ($sort_order == 'DESC') $a_index = array_reverse($a_index); - - $this->icache[$key] = $a_index; } else if ($a_index = $this->conn->fetchHeaderIndex( - $mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { - if ($this->sort_order=="ASC") + $mailbox, "1:*", $sort_field, $skip_deleted)) { + if ($sort_order=="ASC") asort($a_index); - else if ($this->sort_order=="DESC") + else if ($sort_order=="DESC") arsort($a_index); - $this->icache[$key] = array_keys($a_index); + $a_index = array_keys($a_index); } - return $this->icache[$key] !== false ? $this->icache[$key] : array(); + return $a_index !== false ? $a_index : array(); } @@ -1570,19 +1582,9 @@ class rcube_imap // have stored it in RAM if (isset($this->icache[$key])) return $this->icache[$key]; -/* - // check local cache - $cache_key = $mailbox.'.msg'; - $cache_status = $this->check_cache_status($mailbox, $cache_key); - // cache is OK - if ($cache_status>0) { - $a_index = $this->get_message_cache_index($cache_key, $this->sort_field, $this->sort_order); - return array_keys($a_index); - } -*/ // get all threads (default sort order) - list ($thread_tree) = $this->_fetch_threads($mailbox); + list ($thread_tree) = $this->fetch_threads($mailbox); $this->icache[$key] = $this->_flatten_threads($mailbox, $thread_tree); @@ -1594,7 +1596,7 @@ class rcube_imap * Return array of threaded messages (all, not only roots) * * @param string $mailbox Mailbox to get index from - * @param array $thread_tree Threaded messages array (see _fetch_threads()) + * @param array $thread_tree Threaded messages array (see fetch_threads()) * @param array $ids Message IDs if we know what we need (e.g. search result) * for better performance * @return array Indexed array with message IDs @@ -1606,7 +1608,7 @@ class rcube_imap if (empty($thread_tree)) return array(); - $msg_index = $this->_sort_threads($mailbox, $thread_tree, $ids); + $msg_index = $this->sort_threads($mailbox, $thread_tree, $ids); if ($this->sort_order == 'DESC') $msg_index = array_reverse($msg_index); @@ -1625,99 +1627,6 @@ class rcube_imap } - /** - * @param string $mailbox Mailbox name - * @access private - */ - private function sync_header_index($mailbox) - { - $cache_key = $mailbox.'.msg'; - $cache_index = $this->get_message_cache_index($cache_key); - $chunk_size = 1000; - - // cache is empty, get all messages - if (is_array($cache_index) && empty($cache_index)) { - $max = $this->_messagecount($mailbox); - // syncing a big folder maybe slow - @set_time_limit(0); - $start = 1; - $end = min($chunk_size, $max); - while (true) { - // do this in loop to save memory (1000 msgs ~= 10 MB) - if ($headers = $this->conn->fetchHeaders($mailbox, - "$start:$end", false, false, $this->get_fetch_headers()) - ) { - foreach ($headers as $header) { - $this->add_message_cache($cache_key, $header->id, $header, NULL, true); - } - } - if ($end - $start < $chunk_size - 1) - break; - - $end = min($end+$chunk_size, $max); - $start += $chunk_size; - } - return; - } - - // fetch complete message index - if (isset($this->icache['folder_index'])) - $a_message_index = &$this->icache['folder_index']; - else - $a_message_index = $this->conn->fetchHeaderIndex($mailbox, "1:*", 'UID', $this->skip_deleted); - - if ($a_message_index === false || $cache_index === null) - return; - - // compare cache index with real index - foreach ($a_message_index as $id => $uid) { - // message in cache at correct position - if ($cache_index[$id] == $uid) { - unset($cache_index[$id]); - continue; - } - - // other message at this position - if (isset($cache_index[$id])) { - $for_remove[] = $cache_index[$id]; - unset($cache_index[$id]); - } - - // message in cache but at wrong position - if (is_int($key = array_search($uid, $cache_index))) { - $for_remove[] = $uid; - unset($cache_index[$key]); - } - - $for_update[] = $id; - } - - // remove messages at wrong positions and those deleted that are still in cache_index - if (!empty($for_remove)) - $cache_index = array_merge($cache_index, $for_remove); - - if (!empty($cache_index)) - $this->remove_message_cache($cache_key, $cache_index); - - // fetch complete headers and add to cache - if (!empty($for_update)) { - // syncing a big folder maybe slow - @set_time_limit(0); - // To save memory do this in chunks - $for_update = array_chunk($for_update, $chunk_size); - foreach ($for_update as $uids) { - if ($headers = $this->conn->fetchHeaders($mailbox, - $uids, false, false, $this->get_fetch_headers()) - ) { - foreach ($headers as $header) { - $this->add_message_cache($cache_key, $header->id, $header, NULL, true); - } - } - } - } - } - - /** * Invoke search request to IMAP server * @@ -1727,6 +1636,7 @@ class rcube_imap * @param string $sort_field Header field to sort by * @return array search results as list of message IDs * @access public + * @todo: Search criteria should be provided in non-IMAP format, eg. array */ function search($mailbox='', $str=NULL, $charset=NULL, $sort_field=NULL) { @@ -1753,8 +1663,8 @@ class rcube_imap * @param string $criteria Search criteria * @param string $charset Charset * @param string $sort_field Sorting field + * * @return array search results as list of message ids - * @access private * @see rcube_imap::search() */ private function _search_index($mailbox, $criteria='ALL', $charset=NULL, $sort_field=NULL) @@ -1776,9 +1686,9 @@ class rcube_imap if ($a_messages !== false) { list ($thread_tree, $msg_depth, $has_children) = $a_messages; $a_messages = array( - 'tree' => $thread_tree, - 'depth' => $msg_depth, - 'children' => $has_children + 'tree' => $thread_tree, + 'depth'=> $msg_depth, + 'children' => $has_children ); } @@ -1790,7 +1700,7 @@ class rcube_imap $a_messages = $this->conn->sort($mailbox, $sort_field, $criteria, false, $charset); // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8, - // but I've seen that Courier doesn't support UTF-8) + // but I've seen Courier with disabled UTF-8 support) if ($a_messages === false && $charset && $charset != 'US-ASCII') $a_messages = $this->conn->sort($mailbox, $sort_field, $this->convert_criteria($criteria, $charset), false, 'US-ASCII'); @@ -1802,7 +1712,7 @@ class rcube_imap } if ($orig_criteria == 'ALL') { - $max = $this->_messagecount($mailbox); + $max = $this->_messagecount($mailbox, 'ALL', true, false); $a_messages = $max ? range(1, $max) : array(); } else { @@ -1832,8 +1742,8 @@ class rcube_imap * @param string $mailbox Mailbox name to search in * @param string $str Search string * @param boolean $ret_uid True if UIDs should be returned + * * @return array Search results as list of message IDs or UIDs - * @access public */ function search_once($mailbox='', $str=NULL, $ret_uid=false) { @@ -1866,9 +1776,9 @@ class rcube_imap $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n $string = substr($str, $string_offset - 1, $m[0]); $string = rcube_charset_convert($string, $charset, $dest_charset); - if (!$string) + if ($string === false) continue; - $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string); + $res .= substr($str, $last, $m[1] - $last - 1) . rcube_imap_generic::escape($string); $last = $m[0] + $string_offset - 1; } if ($last < strlen($str)) @@ -1887,43 +1797,53 @@ class rcube_imap * @param string $mailbox Mailbox name * @param array $thread_tree Unsorted thread tree (rcube_imap_generic::thread() result) * @param array $ids Message IDs if we know what we need (e.g. search result) + * * @return array Sorted roots IDs - * @access private */ - private function _sort_threads($mailbox, $thread_tree, $ids=NULL) + function sort_threads($mailbox, $thread_tree, $ids = null) { - // THREAD=ORDEREDSUBJECT: sorting by sent date of root message - // THREAD=REFERENCES: sorting by sent date of root message - // THREAD=REFS: sorting by the most recent date in each thread + // THREAD=ORDEREDSUBJECT: sorting by sent date of root message + // THREAD=REFERENCES: sorting by sent date of root message + // THREAD=REFS: sorting by the most recent date in each thread + // default sorting if (!$this->sort_field || ($this->sort_field == 'date' && $this->threading == 'REFS')) { return array_keys((array)$thread_tree); - } - // here we'll implement REFS sorting, for performance reason - else { // ($sort_field == 'date' && $this->threading != 'REFS') + } + // here we'll implement REFS sorting + else { + if ($mcache = $this->get_mcache_engine()) { + $a_index = $mcache->get_index($mailbox, $this->sort_field, 'ASC'); + if (is_array($a_index)) { + $a_index = array_keys($a_index); + // now we must remove IDs that doesn't exist in $ids + if (!empty($ids)) + $a_index = array_intersect($a_index, $ids); + } + } // use SORT command - if ($this->get_capability('SORT') && + else if ($this->get_capability('SORT') && ($a_index = $this->conn->sort($mailbox, $this->sort_field, - !empty($ids) ? $ids : ($this->skip_deleted ? 'UNDELETED' : ''))) !== false + !empty($ids) ? $ids : ($this->skip_deleted ? 'UNDELETED' : ''))) !== false ) { - // return unsorted tree if we've got no index data - if (!$a_index) - return array_keys((array)$thread_tree); + // do nothing } else { // fetch specified headers for all messages and sort them $a_index = $this->conn->fetchHeaderIndex($mailbox, !empty($ids) ? $ids : "1:*", - $this->sort_field, $this->skip_deleted); + $this->sort_field, $this->skip_deleted); - // return unsorted tree if we've got no index data - if (!$a_index) - return array_keys((array)$thread_tree); - - asort($a_index); // ASC - $a_index = array_values($a_index); + // return unsorted tree if we've got no index data + if (!empty($a_index)) { + asort($a_index); // ASC + $a_index = array_values($a_index); + } } - return $this->_sort_thread_refs($thread_tree, $a_index); + if (empty($a_index)) + return array_keys((array)$thread_tree); + + return $this->_sort_thread_refs($thread_tree, $a_index); } } @@ -1931,10 +1851,10 @@ class rcube_imap /** * THREAD=REFS sorting implementation * - * @param array $tree Thread tree array (message identifiers as keys) - * @param array $index Array of sorted message identifiers + * @param array $tree Thread tree array (message identifiers as keys) + * @param array $index Array of sorted message identifiers + * * @return array Array of sorted roots messages - * @access private */ private function _sort_thread_refs($tree, $index) { @@ -1983,7 +1903,7 @@ class rcube_imap { if (!empty($this->search_string)) $this->search_set = $this->search('', $this->search_string, $this->search_charset, - $this->search_sort_field, $this->search_threads, $this->search_sorted); + $this->search_sort_field, $this->search_threads, $this->search_sorted); return $this->get_search_set(); } @@ -2011,32 +1931,25 @@ class rcube_imap /** * Return message headers object of a specific message * - * @param int $id Message ID + * @param int $id Message sequence ID or UID * @param string $mailbox Mailbox to read from - * @param boolean $is_uid True if $id is the message UID - * @param boolean $bodystr True if we need also BODYSTRUCTURE in headers - * @return object Message headers representation + * @param bool $force True to skip cache + * + * @return rcube_mail_header Message headers */ - function get_headers($id, $mailbox=null, $is_uid=true, $bodystr=false) + function get_headers($uid, $mailbox = null, $force = false) { if (!strlen($mailbox)) { $mailbox = $this->mailbox; } - $uid = $is_uid ? $id : $this->_id2uid($id, $mailbox); // get cached headers - if ($uid && ($headers = &$this->get_cached_message($mailbox.'.msg', $uid))) - return $headers; - - $headers = $this->conn->fetchHeader( - $mailbox, $id, $is_uid, $bodystr, $this->get_fetch_headers()); - - // write headers cache - if ($headers) { - if ($headers->uid && $headers->id) - $this->uid_id_map[$mailbox][$headers->uid] = $headers->id; - - $this->add_message_cache($mailbox.'.msg', $headers->id, $headers, NULL, false, true); + if (!$force && $uid && ($mcache = $this->get_mcache_engine())) { + $headers = $mcache->get_message($mailbox, $uid); + } + else { + $headers = $this->conn->fetchHeader( + $mailbox, $uid, true, true, $this->get_fetch_headers()); } return $headers; @@ -2044,33 +1957,47 @@ class rcube_imap /** - * Fetch body structure from the IMAP server and build + * Fetch message headers and body structure from the IMAP server and build * an object structure similar to the one generated by PEAR::Mail_mimeDecode * - * @param int $uid Message UID to fetch - * @param string $structure_str Message BODYSTRUCTURE string (optional) - * @return object rcube_message_part Message part tree or False on failure + * @param int $uid Message UID to fetch + * @param string $mailbox Mailbox to read from + * + * @return object rcube_mail_header Message data */ - function &get_structure($uid, $structure_str='') + function get_message($uid, $mailbox = null) { - $cache_key = $this->mailbox.'.msg'; - $headers = &$this->get_cached_message($cache_key, $uid); + if (!strlen($mailbox)) { + $mailbox = $this->mailbox; + } - // return cached message structure - if (is_object($headers) && is_object($headers->structure)) { - return $headers->structure; + // Check internal cache + if (!empty($this->icache['message'])) { + if (($headers = $this->icache['message']) && $headers->uid == $uid) { + return $headers; + } } - if (!$structure_str) { - $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); + $headers = $this->get_headers($uid, $mailbox); + + // message doesn't exist? + if (empty($headers)) + return null; + + // structure might be cached + if (!empty($headers->structure)) + return $headers; + + $this->_msg_uid = $uid; + + if (empty($headers->bodystructure)) { + $headers->bodystructure = $this->conn->getStructure($mailbox, $uid, true); } - $structure = rcube_mime_struct::parseStructure($structure_str); - $struct = false; - // parse structure and add headers - if (!empty($structure)) { - $headers = $this->get_headers($uid); - $this->_msg_id = $headers->id; + $structure = $headers->bodystructure; + + if (empty($structure)) + return $headers; // set message charset from message headers if ($headers->charset) @@ -2093,26 +2020,21 @@ class rcube_imap $structure[1] = $m[2]; } else - return false; + return $headers; } $struct = &$this->_structure_part($structure, 0, '', $headers); - $struct->headers = get_object_vars($headers); // don't trust given content-type - if (empty($struct->parts) && !empty($struct->headers['ctype'])) { + if (empty($struct->parts) && !empty($headers->ctype)) { $struct->mime_id = '1'; - $struct->mimetype = strtolower($struct->headers['ctype']); + $struct->mimetype = strtolower($headers->ctype); list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype); } - // write structure to cache - if ($this->messages_caching) - $this->add_message_cache($cache_key, $this->_msg_id, $headers, $struct, - $this->icache['message.id'][$uid], true); - } + $headers->structure = $struct; - return $struct; + return $this->icache['message'] = $headers; } @@ -2177,7 +2099,7 @@ class rcube_imap // headers for parts on all levels if ($mime_part_headers) { $mime_part_headers = $this->conn->fetchMIMEHeaders($this->mailbox, - $this->_msg_id, $mime_part_headers); + $this->_msg_uid, $mime_part_headers); } $struct->parts = array(); @@ -2279,7 +2201,7 @@ class rcube_imap if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) { if (empty($mime_headers)) { $mime_headers = $this->conn->fetchPartHeader( - $this->mailbox, $this->_msg_id, false, $struct->mime_id); + $this->mailbox, $this->_msg_uid, true, $struct->mime_id); } if (is_string($mime_headers)) @@ -2342,7 +2264,7 @@ class rcube_imap if ($i<2) { if (!$headers) { $headers = $this->conn->fetchPartHeader( - $this->mailbox, $this->_msg_id, false, $part->mime_id); + $this->mailbox, $this->_msg_uid, true, $part->mime_id); } $filename_mime = ''; $i = 0; @@ -2361,7 +2283,7 @@ class rcube_imap if ($i<2) { if (!$headers) { $headers = $this->conn->fetchPartHeader( - $this->mailbox, $this->_msg_id, false, $part->mime_id); + $this->mailbox, $this->_msg_uid, true, $part->mime_id); } $filename_encoded = ''; $i = 0; $matches = array(); @@ -2380,7 +2302,7 @@ class rcube_imap if ($i<2) { if (!$headers) { $headers = $this->conn->fetchPartHeader( - $this->mailbox, $this->_msg_id, false, $part->mime_id); + $this->mailbox, $this->_msg_uid, true, $part->mime_id); } $filename_mime = ''; $i = 0; $matches = array(); @@ -2399,7 +2321,7 @@ class rcube_imap if ($i<2) { if (!$headers) { $headers = $this->conn->fetchPartHeader( - $this->mailbox, $this->_msg_id, false, $part->mime_id); + $this->mailbox, $this->_msg_uid, true, $part->mime_id); } $filename_encoded = ''; $i = 0; $matches = array(); @@ -2420,9 +2342,14 @@ class rcube_imap // decode filename if (!empty($filename_mime)) { - $part->filename = rcube_imap::decode_mime_string($filename_mime, - $part->charset ? $part->charset : ($this->struct_charset ? $this->struct_charset : - rc_detect_encoding($filename_mime, $this->default_charset))); + if (!empty($part->charset)) + $charset = $part->charset; + else if (!empty($this->struct_charset)) + $charset = $this->struct_charset; + else + $charset = rc_detect_encoding($filename_mime, $this->default_charset); + + $part->filename = rcube_imap::decode_mime_string($filename_mime, $charset); } else if (!empty($filename_encoded)) { // decode filename according to RFC 2231, Section 4 @@ -2430,6 +2357,7 @@ class rcube_imap $filename_charset = $fmatches[1]; $filename_encoded = $fmatches[2]; } + $part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset); } } @@ -2466,30 +2394,23 @@ class rcube_imap */ function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false) { - // get part encoding if not provided + // get part data if not provided if (!is_object($o_part)) { - $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); - $structure = new rcube_mime_struct(); - // error or message not found - if (!$structure->loadStructure($structure_str)) { - return false; - } + $structure = $this->conn->getStructure($this->mailbox, $uid, true); + $part_data = rcube_imap_generic::getStructurePartData($structure, $part); $o_part = new rcube_message_part; - $o_part->ctype_primary = strtolower($structure->getPartType($part)); - $o_part->encoding = strtolower($structure->getPartEncoding($part)); - $o_part->charset = $structure->getPartCharset($part); + $o_part->ctype_primary = $part_data['type']; + $o_part->encoding = $part_data['encoding']; + $o_part->charset = $part_data['charset']; + $o_part->size = $part_data['size']; } - // TODO: Add caching for message parts - - if (!$part) { - $part = 'TEXT'; + if ($o_part && $o_part->size) { + $body = $this->conn->handlePartBody($this->mailbox, $uid, true, + $part ? $part : 'TEXT', $o_part->encoding, $print, $fp); } - $body = $this->conn->handlePartBody($this->mailbox, $uid, true, $part, - $o_part->encoding, $print, $fp); - if ($fp || $print) { return true; } @@ -2501,7 +2422,11 @@ class rcube_imap if (!$skip_charset_conv) { if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') { - $o_part->charset = $this->default_charset; + // try to extract charset information from HTML meta tag (#1488125) + if ($o_part->ctype_secondary == 'html' && preg_match('/<meta[^>]+charset=([a-z0-9-_]+)/i', $body, $m)) + $o_part->charset = strtoupper($m[1]); + else + $o_part->charset = $this->default_charset; } $body = rcube_charset_convert($body, $o_part->charset); } @@ -2590,12 +2515,12 @@ class rcube_imap if ($result) { // reload message headers if cached - if ($this->messages_caching && !$skip_cache) { - $cache_key = $mailbox.'.msg'; - if ($all_mode) - $this->clear_message_cache($cache_key); - else - $this->remove_message_cache($cache_key, explode(',', $uids)); + // @TODO: update flags instead removing from cache + if (!$skip_cache && ($mcache = $this->get_mcache_engine())) { + $status = strpos($flag, 'UN') !== 0; + $mflag = preg_replace('/^UN/', '', $flag); + $mcache->change_flag($mailbox, $all_mode ? null : explode(',', $uids), + $mflag, $status); } // clear cached counters @@ -2636,7 +2561,7 @@ class rcube_imap * @param string $headers Headers string if $message contains only the body * @param boolean $is_file True if $message is a filename * - * @return boolean True on success, False on error + * @return int|bool Appended message UID or True on success, False on error */ function save_message($mailbox, &$message, $headers='', $is_file=false) { @@ -2687,10 +2612,14 @@ class rcube_imap // make sure mailbox exists if ($to_mbox != 'INBOX' && !$this->mailbox_exists($to_mbox)) { - if (in_array($to_mbox, $this->default_folders)) - $this->create_mailbox($to_mbox, true); - else + if (in_array($to_mbox, $this->default_folders)) { + if (!$this->create_mailbox($to_mbox, true)) { + return false; + } + } + else { return false; + } } $config = rcmail::get_instance()->config; @@ -2727,19 +2656,18 @@ class rcube_imap if ($this->search_threads || $all_mode) $this->refresh_search(); else { - $uids = explode(',', $uids); - foreach ($uids as $uid) - $a_mids[] = $this->_uid2id($uid, $from_mbox); + $a_uids = explode(',', $uids); + foreach ($a_uids as $uid) + $a_mids[] = $this->uid2id($uid, $from_mbox); $this->search_set = array_diff($this->search_set, $a_mids); } + unset($a_mids); + unset($a_uids); } - // update cached message headers - $cache_key = $from_mbox.'.msg'; - if ($all_mode || ($start_index = $this->get_message_cache_index_min($cache_key, $uids))) { - // clear cache from the lowest index on - $this->clear_message_cache($cache_key, $all_mode ? 1 : $start_index); - } + // remove cached messages + // @TODO: do cache update instead of clearing it + $this->clear_message_cache($from_mbox, $all_mode ? null : explode(',', $uids)); } return $moved; @@ -2769,10 +2697,14 @@ class rcube_imap // make sure mailbox exists if ($to_mbox != 'INBOX' && !$this->mailbox_exists($to_mbox)) { - if (in_array($to_mbox, $this->default_folders)) - $this->create_mailbox($to_mbox, true); - else + if (in_array($to_mbox, $this->default_folders)) { + if (!$this->create_mailbox($to_mbox, true)) { + return false; + } + } + else { return false; + } } // copy messages @@ -2824,19 +2756,17 @@ class rcube_imap if ($this->search_threads || $all_mode) $this->refresh_search(); else { - $uids = explode(',', $uids); - foreach ($uids as $uid) - $a_mids[] = $this->_uid2id($uid, $mailbox); + $a_uids = explode(',', $uids); + foreach ($a_uids as $uid) + $a_mids[] = $this->uid2id($uid, $mailbox); $this->search_set = array_diff($this->search_set, $a_mids); + unset($a_uids); + unset($a_mids); } } - // remove deleted messages from cache - $cache_key = $mailbox.'.msg'; - if ($all_mode || ($start_index = $this->get_message_cache_index_min($cache_key, $uids))) { - // clear cache from the lowest index on - $this->clear_message_cache($cache_key, $all_mode ? 1 : $start_index); - } + // remove cached messages + $this->clear_message_cache($mailbox, $all_mode ? null : explode(',', $uids)); } return $deleted; @@ -2861,9 +2791,9 @@ class rcube_imap $cleared = $this->conn->clearFolder($mailbox); } - // make sure the message count cache is cleared as well + // make sure the cache is cleared as well if ($cleared) { - $this->clear_message_cache($mailbox.'.msg'); + $this->clear_message_cache($mailbox); $a_mailbox_cache = $this->get_cache('messagecount'); unset($a_mailbox_cache[$mailbox]); $this->update_cache('messagecount', $a_mailbox_cache); @@ -2904,9 +2834,9 @@ class rcube_imap private function _expunge($mailbox, $clear_cache=true, $uids=NULL) { if ($uids && $this->get_capability('UIDPLUS')) - $a_uids = is_array($uids) ? join(',', $uids) : $uids; + list($uids, $all_mode) = $this->_parse_uids($uids, $mailbox); else - $a_uids = NULL; + $uids = null; // force mailbox selection and check if mailbox is writeable // to prevent a situation when CLOSE is executed on closed @@ -2921,13 +2851,13 @@ class rcube_imap } // CLOSE(+SELECT) should be faster than EXPUNGE - if (empty($a_uids) || $a_uids == '1:*') + if (empty($uids) || $all_mode) $result = $this->conn->close(); else - $result = $this->conn->expunge($mailbox, $a_uids); + $result = $this->conn->expunge($mailbox, $uids); if ($result && $clear_cache) { - $this->clear_message_cache($mailbox.'.msg'); + $this->clear_message_cache($mailbox, $all_mode ? null : explode(',', $uids)); $this->_clear_messagecount($mailbox); } @@ -2992,7 +2922,7 @@ class rcube_imap $mailbox = $this->mailbox; } - return $this->_uid2id($uid, $mailbox); + return $this->uid2id($uid, $mailbox); } @@ -3010,7 +2940,7 @@ class rcube_imap $mailbox = $this->mailbox; } - return $this->_id2uid($id, $mailbox); + return $this->id2uid($id, $mailbox); } @@ -3022,55 +2952,72 @@ class rcube_imap /** * Public method for listing subscribed folders * - * @param string $root Optional root folder - * @param string $name Optional name pattern - * @param string $filter Optional filter + * @param string $root Optional root folder + * @param string $name Optional name pattern + * @param string $filter Optional filter + * @param string $rights Optional ACL requirements + * @param bool $skip_sort Enable to return unsorted list (for better performance) * - * @return array List of mailboxes/folders + * @return array List of folders * @access public */ - function list_mailboxes($root='', $name='*', $filter=null) + function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) { - $a_mboxes = $this->_list_mailboxes($root, $name, $filter); + $cache_key = $root.':'.$name; + if (!empty($filter)) { + $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); + } + $cache_key .= ':'.$rights; + $cache_key = 'mailboxes.'.md5($cache_key); + + // get cached folder list + $a_mboxes = $this->get_cache($cache_key); + if (is_array($a_mboxes)) { + return $a_mboxes; + } + + $a_mboxes = $this->_list_mailboxes($root, $name, $filter, $rights); + + if (!is_array($a_mboxes)) { + return array(); + } + + // filter folders list according to rights requirements + if ($rights && $this->get_capability('ACL')) { + $a_mboxes = $this->filter_rights($a_mboxes, $rights); + } // INBOX should always be available if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) { array_unshift($a_mboxes, 'INBOX'); } - // sort mailboxes - $a_mboxes = $this->_sort_mailbox_list($a_mboxes); + // sort mailboxes (always sort for cache) + if (!$skip_sort || $this->cache) { + $a_mboxes = $this->_sort_mailbox_list($a_mboxes); + } + + // write mailboxlist to cache + $this->update_cache($cache_key, $a_mboxes); return $a_mboxes; } /** - * Private method for mailbox listing + * Private method for mailbox listing (LSUB) * * @param string $root Optional root folder * @param string $name Optional name pattern * @param mixed $filter Optional filter + * @param string $rights Optional ACL requirements * - * @return array List of mailboxes/folders + * @return array List of subscribed folders * @see rcube_imap::list_mailboxes() * @access private */ - private function _list_mailboxes($root='', $name='*', $filter=null) + private function _list_mailboxes($root='', $name='*', $filter=null, $rights=null) { - $cache_key = $root.':'.$name; - if (!empty($filter)) { - $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); - } - - $cache_key = 'mailboxes.'.md5($cache_key); - - // get cached folder list - $a_mboxes = $this->get_cache($cache_key); - if (is_array($a_mboxes)) { - return $a_mboxes; - } - $a_defaults = $a_out = array(); // Give plugins a chance to provide a list of mailboxes @@ -3081,7 +3028,7 @@ class rcube_imap $a_folders = $data['folders']; } else if (!$this->conn->connected()) { - return array(); + return null; } else { // Server supports LIST-EXTENDED, we can use selection options @@ -3129,9 +3076,6 @@ class rcube_imap $a_folders = array(); } - // write mailboxlist to cache - $this->update_cache($cache_key, $a_folders); - return $a_folders; } @@ -3139,15 +3083,29 @@ class rcube_imap /** * Get a list of all folders available on the IMAP server * - * @param string $root IMAP root dir - * @param string $name Optional name pattern - * @param mixed $filter Optional filter + * @param string $root IMAP root dir + * @param string $name Optional name pattern + * @param mixed $filter Optional filter + * @param string $rights Optional ACL requirements + * @param bool $skip_sort Enable to return unsorted list (for better performance) * * @return array Indexed array with folder names */ - function list_unsubscribed($root='', $name='*', $filter=null) + function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) { - // @TODO: caching + $cache_key = $root.':'.$name; + if (!empty($filter)) { + $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); + } + $cache_key .= ':'.$rights; + $cache_key = 'mailboxes.list.'.md5($cache_key); + + // get cached folder list + $a_mboxes = $this->get_cache($cache_key); + if (is_array($a_mboxes)) { + return $a_mboxes; + } + // Give plugins a chance to provide a list of mailboxes $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list', array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST')); @@ -3157,7 +3115,7 @@ class rcube_imap } else { // retrieve list of folders from IMAP server - $a_mboxes = $this->conn->listMailboxes($root, $name); + $a_mboxes = $this->_list_unsubscribed($root, $name); } if (!is_array($a_mboxes)) { @@ -3169,13 +3127,108 @@ class rcube_imap array_unshift($a_mboxes, 'INBOX'); } + // cache folder attributes + if ($root == '' && $name == '*' && empty($filter)) { + $this->update_cache('mailboxes.attributes', $this->conn->data['LIST']); + } + + // filter folders list according to rights requirements + if ($rights && $this->get_capability('ACL')) { + $a_folders = $this->filter_rights($a_folders, $rights); + } + // filter folders and sort them - $a_mboxes = $this->_sort_mailbox_list($a_mboxes); + if (!$skip_sort) { + $a_mboxes = $this->_sort_mailbox_list($a_mboxes); + } + + // write mailboxlist to cache + $this->update_cache($cache_key, $a_mboxes); return $a_mboxes; } + /** + * Private method for mailbox listing (LIST) + * + * @param string $root Optional root folder + * @param string $name Optional name pattern + * + * @return array List of folders + * @see rcube_imap::list_unsubscribed() + */ + private function _list_unsubscribed($root='', $name='*') + { + $result = $this->conn->listMailboxes($root, $name); + + if (!is_array($result)) { + return array(); + } + + // #1486796: some server configurations doesn't + // return folders in all namespaces, we'll try to detect that situation + // and ask for these namespaces separately + if ($root == '' && $name == '*') { + $delim = $this->get_hierarchy_delimiter(); + $namespace = $this->get_namespace(); + $search = array(); + + // build list of namespace prefixes + foreach ((array)$namespace as $ns) { + if (is_array($ns)) { + foreach ($ns as $ns_data) { + if (strlen($ns_data[0])) { + $search[] = $ns_data[0]; + } + } + } + } + + if (!empty($search)) { + // go through all folders detecting namespace usage + foreach ($result as $folder) { + foreach ($search as $idx => $prefix) { + if (strpos($folder, $prefix) === 0) { + unset($search[$idx]); + } + } + if (empty($search)) { + break; + } + } + + // get folders in hidden namespaces and add to the result + foreach ($search as $prefix) { + $list = $this->conn->listMailboxes($prefix, $name); + + if (!empty($list)) { + $result = array_merge($result, $list); + } + } + } + } + + return $result; + } + + + /** + * Filter the given list of folders according to access rights + */ + private function filter_rights($a_folders, $rights) + { + $regex = '/('.$rights.')/'; + foreach ($a_folders as $idx => $folder) { + $myrights = join('', (array)$this->my_rights($folder)); + if ($myrights !== null && !preg_match($regex, $myrights)) + unset($a_folders[$idx]); + } + + return $a_folders; + } + + /** * Get mailbox quota information * added by Nuny @@ -3308,11 +3361,14 @@ class rcube_imap $this->conn->unsubscribe($c_subscribed); $this->conn->subscribe(preg_replace('/^'.preg_quote($mailbox, '/').'/', $new_name, $c_subscribed)); + + // clear cache + $this->clear_message_cache($c_subscribed); } } // clear cache - $this->clear_message_cache($mailbox.'.msg'); + $this->clear_message_cache($mailbox); $this->clear_cache('mailboxes', true); } @@ -3348,13 +3404,13 @@ class rcube_imap if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_mbox)) { $this->conn->unsubscribe($c_mbox); if ($this->conn->deleteFolder($c_mbox)) { - $this->clear_message_cache($c_mbox.'.msg'); + $this->clear_message_cache($c_mbox); } } } // clear mailbox-related cache - $this->clear_message_cache($mailbox.'.msg'); + $this->clear_message_cache($mailbox); $this->clear_cache('mailboxes', true); } @@ -3429,8 +3485,8 @@ class rcube_imap foreach ($this->namespace as $type => $namespace) { if (is_array($namespace)) { foreach ($namespace as $ns) { - if (strlen($ns[0])) { - if ((strlen($ns[0])>1 && $mailbox == substr($ns[0], 0, -1)) + if ($len = strlen($ns[0])) { + if (($len > 1 && $mailbox == substr($ns[0], 0, -1)) || strpos($mailbox, $ns[0]) === 0 ) { return $type; @@ -3484,35 +3540,66 @@ class rcube_imap /** - * Gets folder options from LIST response, e.g. \Noselect, \Noinferiors + * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors * * @param string $mailbox Folder name - * @param bool $force Set to True if options should be refreshed - * Options are available after LIST command only + * @param bool $force Set to True if attributes should be refreshed * * @return array Options list */ - function mailbox_options($mailbox, $force=false) + function mailbox_attributes($mailbox, $force=false) { - if ($mailbox == 'INBOX') { - return array(); + // get attributes directly from LIST command + if (!empty($this->conn->data['LIST']) && is_array($this->conn->data['LIST'][$mailbox])) { + $opts = $this->conn->data['LIST'][$mailbox]; } - - if (!is_array($this->conn->data['LIST']) || !is_array($this->conn->data['LIST'][$mailbox])) { - if ($force) { - $this->conn->listMailboxes('', $mailbox); - } - else { - return array(); - } + // get cached folder attributes + else if (!$force) { + $opts = $this->get_cache('mailboxes.attributes'); + $opts = $opts[$mailbox]; } - $opts = $this->conn->data['LIST'][$mailbox]; + if (!is_array($opts)) { + $this->conn->listMailboxes('', $mailbox); + $opts = $this->conn->data['LIST'][$mailbox]; + } return is_array($opts) ? $opts : array(); } + /** + * Gets connection (and current mailbox) data: UIDVALIDITY, EXISTS, RECENT, + * PERMANENTFLAGS, UIDNEXT, UNSEEN + * + * @param string $mailbox Folder name + * + * @return array Data + */ + function mailbox_data($mailbox) + { + if (!strlen($mailbox)) + $mailbox = $this->mailbox !== null ? $this->mailbox : 'INBOX'; + + if ($this->conn->selected != $mailbox) { + if ($this->conn->select($mailbox)) + $this->mailbox = $mailbox; + else + return null; + } + + $data = $this->conn->data; + + // add (E)SEARCH result for ALL UNDELETED query + if (!empty($this->icache['undeleted_idx']) && $this->icache['undeleted_idx'][0] == $mailbox) { + $data['ALL_UNDELETED'] = $this->icache['undeleted_idx'][1]; + $data['COUNT_UNDELETED'] = $this->icache['undeleted_idx'][2]; + } + + return $data; + } + + /** * Returns extended information about the folder * @@ -3558,17 +3645,17 @@ class rcube_imap } } - $options['name'] = $mailbox; - $options['options'] = $this->mailbox_options($mailbox, true); - $options['namespace'] = $this->mailbox_namespace($mailbox); - $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); - $options['special'] = in_array($mailbox, $this->default_folders); + $options['name'] = $mailbox; + $options['attributes'] = $this->mailbox_attributes($mailbox, true); + $options['namespace'] = $this->mailbox_namespace($mailbox); + $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); + $options['special'] = in_array($mailbox, $this->default_folders); // Set 'noselect' and 'norename' flags - if (is_array($options['options'])) { - foreach ($options['options'] as $opt) { - $opt = strtolower($opt); - if ($opt == '\noselect' || $opt == '\nonexistent') { + if (is_array($options['attributes'])) { + foreach ($options['attributes'] as $attrib) { + $attrib = strtolower($attrib); + if ($attrib == '\noselect' || $attrib == '\nonexistent') { $options['noselect'] = true; } } @@ -3594,6 +3681,19 @@ class rcube_imap } + /** + * Synchronizes messages cache. + * + * @param string $mailbox Folder name + */ + public function mailbox_sync($mailbox) + { + if ($mcache = $this->get_mcache_engine()) { + $mcache->synchronize($mailbox); + } + } + + /** * Get message header names for rcube_imap_generic::fetchHeader(s) * @@ -3855,7 +3955,7 @@ class rcube_imap else { if ($this->cache) $this->cache->close(); - $this->cache = null; + $this->cache = null; $this->caching = false; } } @@ -3925,419 +4025,50 @@ class rcube_imap * Enable or disable messages caching * * @param boolean $set Flag - * @access public */ function set_messages_caching($set) { - $rcmail = rcmail::get_instance(); - - if ($set && ($dbh = $rcmail->get_dbh())) { - $this->db = $dbh; + if ($set) { $this->messages_caching = true; } else { + if ($this->mcache) + $this->mcache->close(); + $this->mcache = null; $this->messages_caching = false; } } /** - * Checks if the cache is up-to-date - * - * @param string $mailbox Mailbox name - * @param string $cache_key Internal cache key - * @return int Cache status: -3 = off, -2 = incomplete, -1 = dirty, 1 = OK - */ - private function check_cache_status($mailbox, $cache_key) - { - if (!$this->messages_caching) - return -3; - - $cache_index = $this->get_message_cache_index($cache_key); - $msg_count = $this->_messagecount($mailbox); - $cache_count = count($cache_index); - - // empty mailbox - if (!$msg_count) { - return $cache_count ? -2 : 1; - } - - if ($cache_count == $msg_count) { - if ($this->skip_deleted) { - if (!empty($this->icache['all_undeleted_idx'])) { - $uids = rcube_imap_generic::uncompressMessageSet($this->icache['all_undeleted_idx']); - $uids = array_flip($uids); - foreach ($cache_index as $uid) { - unset($uids[$uid]); - } - } - else { - // get all undeleted messages excluding cached UIDs - $uids = $this->search_once($mailbox, 'ALL UNDELETED NOT UID '. - rcube_imap_generic::compressMessageSet($cache_index)); - } - if (empty($uids)) { - return 1; - } - } else { - // get UID of the message with highest index - $uid = $this->_id2uid($msg_count, $mailbox); - $cache_uid = array_pop($cache_index); - - // uids of highest message matches -> cache seems OK - if ($cache_uid == $uid) { - return 1; - } - } - // cache is dirty - return -1; - } - - // if cache count differs less than 10% report as dirty - return (abs($msg_count - $cache_count) < $msg_count/10) ? -1 : -2; - } - - - /** - * @param string $key Cache key - * @param string $from - * @param string $to - * @param string $sort_field - * @param string $sort_order - * @access private + * Getter for messages cache object */ - private function get_message_cache($key, $from, $to, $sort_field, $sort_order) + private function get_mcache_engine() { - if (!$this->messages_caching) - return NULL; - - // use idx sort as default sorting - if (!$sort_field || !in_array($sort_field, $this->db_header_fields)) { - $sort_field = 'idx'; - } - - $result = array(); - - $sql_result = $this->db->limitquery( - "SELECT idx, uid, headers". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " ORDER BY ".$this->db->quoteIdentifier($sort_field)." ".strtoupper($sort_order), - $from, - $to - $from, - $_SESSION['user_id'], - $key); - - while ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $uid = intval($sql_arr['uid']); - $result[$uid] = $this->db->decode(unserialize($sql_arr['headers'])); - - // featch headers if unserialize failed - if (empty($result[$uid])) - $result[$uid] = $this->conn->fetchHeader( - preg_replace('/.msg$/', '', $key), $uid, true, false, $this->get_fetch_headers()); - } - - return $result; - } - - - /** - * @param string $key Cache key - * @param int $uid Message UID - * @return mixed - * @access private - */ - private function &get_cached_message($key, $uid) - { - $internal_key = 'message'; - - if ($this->messages_caching && !isset($this->icache[$internal_key][$uid])) { - $sql_result = $this->db->query( - "SELECT idx, headers, structure, message_id". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND uid=?", - $_SESSION['user_id'], - $key, - $uid); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $this->icache['message.id'][$uid] = intval($sql_arr['message_id']); - $this->uid_id_map[preg_replace('/\.msg$/', '', $key)][$uid] = intval($sql_arr['idx']); - $this->icache[$internal_key][$uid] = $this->db->decode(unserialize($sql_arr['headers'])); - - if (is_object($this->icache[$internal_key][$uid]) && !empty($sql_arr['structure'])) - $this->icache[$internal_key][$uid]->structure = $this->db->decode(unserialize($sql_arr['structure'])); + if ($this->messages_caching && !$this->mcache) { + $rcmail = rcmail::get_instance(); + if ($dbh = $rcmail->get_dbh()) { + $this->mcache = new rcube_imap_cache( + $dbh, $this, $rcmail->user->ID, $this->skip_deleted); } } - return $this->icache[$internal_key][$uid]; - } - - - /** - * @param string $key Cache key - * @param string $sort_field Sorting column - * @param string $sort_order Sorting order - * @return array Messages index - * @access private - */ - private function get_message_cache_index($key, $sort_field='idx', $sort_order='ASC') - { - if (!$this->messages_caching || empty($key)) - return NULL; - - // use idx sort as default - if (!$sort_field || !in_array($sort_field, $this->db_header_fields)) - $sort_field = 'idx'; - - if (array_key_exists('index', $this->icache) - && $this->icache['index']['key'] == $key - && $this->icache['index']['sort_field'] == $sort_field - ) { - if ($this->icache['index']['sort_order'] == $sort_order) - return $this->icache['index']['result']; - else - return array_reverse($this->icache['index']['result'], true); - } - - $this->icache['index'] = array( - 'result' => array(), - 'key' => $key, - 'sort_field' => $sort_field, - 'sort_order' => $sort_order, - ); - - $sql_result = $this->db->query( - "SELECT idx, uid". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " ORDER BY ".$this->db->quote_identifier($sort_field)." ".$sort_order, - $_SESSION['user_id'], - $key); - - while ($sql_arr = $this->db->fetch_assoc($sql_result)) - $this->icache['index']['result'][$sql_arr['idx']] = intval($sql_arr['uid']); - - return $this->icache['index']['result']; + return $this->mcache; } - /** - * @access private - */ - private function add_message_cache($key, $index, $headers, $struct=null, $force=false, $internal_cache=false) - { - if (empty($key) || !is_object($headers) || empty($headers->uid)) - return; - - // add to internal (fast) cache - if ($internal_cache) { - $this->icache['message'][$headers->uid] = clone $headers; - $this->icache['message'][$headers->uid]->structure = $struct; - } - - // no further caching - if (!$this->messages_caching) - return; - - // known message id - if (is_int($force) && $force > 0) { - $message_id = $force; - } - // check for an existing record (probably headers are cached but structure not) - else if (!$force) { - $sql_result = $this->db->query( - "SELECT message_id". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND uid=?", - $_SESSION['user_id'], - $key, - $headers->uid); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) - $message_id = $sql_arr['message_id']; - } - - // update cache record - if ($message_id) { - $this->db->query( - "UPDATE ".get_table_name('messages'). - " SET idx=?, headers=?, structure=?". - " WHERE message_id=?", - $index, - serialize($this->db->encode(clone $headers)), - is_object($struct) ? serialize($this->db->encode(clone $struct)) : NULL, - $message_id - ); - } - else { // insert new record - $this->db->query( - "INSERT INTO ".get_table_name('messages'). - " (user_id, del, cache_key, created, idx, uid, subject, ". - $this->db->quoteIdentifier('from').", ". - $this->db->quoteIdentifier('to').", ". - "cc, date, size, headers, structure)". - " VALUES (?, 0, ?, ".$this->db->now().", ?, ?, ?, ?, ?, ?, ". - $this->db->fromunixtime($headers->timestamp).", ?, ?, ?)", - $_SESSION['user_id'], - $key, - $index, - $headers->uid, - (string)mb_substr($this->db->encode($this->decode_header($headers->subject, true)), 0, 128), - (string)mb_substr($this->db->encode($this->decode_header($headers->from, true)), 0, 128), - (string)mb_substr($this->db->encode($this->decode_header($headers->to, true)), 0, 128), - (string)mb_substr($this->db->encode($this->decode_header($headers->cc, true)), 0, 128), - (int)$headers->size, - serialize($this->db->encode(clone $headers)), - is_object($struct) ? serialize($this->db->encode(clone $struct)) : NULL - ); - } - - unset($this->icache['index']); - } - - - /** - * @access private - */ - private function remove_message_cache($key, $ids, $idx=false) - { - if (!$this->messages_caching) - return; - - $this->db->query( - "DELETE FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND ".($idx ? "idx" : "uid")." IN (".$this->db->array2list($ids, 'integer').")", - $_SESSION['user_id'], - $key); - - unset($this->icache['index']); - } - - - /** - * @param string $key Cache key - * @param int $start_index Start index - * @access private - */ - private function clear_message_cache($key, $start_index=1) - { - if (!$this->messages_caching) - return; - - $this->db->query( - "DELETE FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND idx>=?", - $_SESSION['user_id'], $key, $start_index); - - unset($this->icache['index']); - } - - - /** - * @access private - */ - private function get_message_cache_index_min($key, $uids=NULL) - { - if (!$this->messages_caching) - return; - - if (!empty($uids) && !is_array($uids)) { - if ($uids == '*' || $uids == '1:*') - $uids = NULL; - else - $uids = explode(',', $uids); - } - - $sql_result = $this->db->query( - "SELECT MIN(idx) AS minidx". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?" - .(!empty($uids) ? " AND uid IN (".$this->db->array2list($uids, 'integer').")" : ''), - $_SESSION['user_id'], - $key); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) - return $sql_arr['minidx']; - else - return 0; - } - - - /** - * @param string $key Cache key - * @param int $id Message (sequence) ID - * @return int Message UID - * @access private + * Clears the messages cache. + * + * @param string $mailbox Folder name + * @param array $uids Optional message UIDs to remove from cache */ - private function get_cache_id2uid($key, $id) + function clear_message_cache($mailbox = null, $uids = null) { - if (!$this->messages_caching) - return null; - - if (array_key_exists('index', $this->icache) - && $this->icache['index']['key'] == $key - ) { - return $this->icache['index']['result'][$id]; + if ($mcache = $this->get_mcache_engine()) { + $mcache->clear($mailbox, $uids); } - - $sql_result = $this->db->query( - "SELECT uid". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND idx=?", - $_SESSION['user_id'], $key, $id); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) - return intval($sql_arr['uid']); - - return null; } - /** - * @param string $key Cache key - * @param int $uid Message UID - * @return int Message (sequence) ID - * @access private - */ - private function get_cache_uid2id($key, $uid) - { - if (!$this->messages_caching) - return null; - - if (array_key_exists('index', $this->icache) - && $this->icache['index']['key'] == $key - ) { - return array_search($uid, $this->icache['index']['result']); - } - - $sql_result = $this->db->query( - "SELECT idx". - " FROM ".get_table_name('messages'). - " WHERE user_id=?". - " AND cache_key=?". - " AND uid=?", - $_SESSION['user_id'], $key, $uid); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) - return intval($sql_arr['idx']); - - return null; - } - /* -------------------------------- * encoding/decoding methods @@ -4432,7 +4163,7 @@ class rcube_imap $input = preg_replace("/\?=\s+=\?/", '?==?', $input); // encoded-word regexp - $re = '/=\?([^?]+)\?([BbQq])\?([^?\n]*)\?=/'; + $re = '/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/'; // Find all RFC2047's encoded words if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { @@ -4634,36 +4365,46 @@ class rcube_imap /** - * @param int $uid Message UID - * @param string $mailbox Mailbox name + * Finds message sequence ID for specified UID + * + * @param int $uid Message UID + * @param string $mailbox Mailbox name + * @param bool $force True to skip cache + * * @return int Message (sequence) ID - * @access private */ - private function _uid2id($uid, $mailbox=NULL) + function uid2id($uid, $mailbox = null, $force = false) { if (!strlen($mailbox)) { $mailbox = $this->mailbox; } - if (!isset($this->uid_id_map[$mailbox][$uid])) { - if (!($id = $this->get_cache_uid2id($mailbox.'.msg', $uid))) - $id = $this->conn->UID2ID($mailbox, $uid); - - $this->uid_id_map[$mailbox][$uid] = $id; + if (!empty($this->uid_id_map[$mailbox][$uid])) { + return $this->uid_id_map[$mailbox][$uid]; } - return $this->uid_id_map[$mailbox][$uid]; + if (!$force && ($mcache = $this->get_mcache_engine())) + $id = $mcache->uid2id($mailbox, $uid); + + if (empty($id)) + $id = $this->conn->UID2ID($mailbox, $uid); + + $this->uid_id_map[$mailbox][$uid] = $id; + + return $id; } /** - * @param int $id Message (sequence) ID - * @param string $mailbox Mailbox name + * Find UID of the specified message sequence ID + * + * @param int $id Message (sequence) ID + * @param string $mailbox Mailbox name + * @param bool $force True to skip cache * * @return int Message UID - * @access private */ - private function _id2uid($id, $mailbox=null) + function id2uid($id, $mailbox = null, $force = false) { if (!strlen($mailbox)) { $mailbox = $this->mailbox; @@ -4673,9 +4414,11 @@ class rcube_imap return $uid; } - if (!($uid = $this->get_cache_id2uid($mailbox.'.msg', $id))) { + if (!$force && ($mcache = $this->get_mcache_engine())) + $uid = $mcache->id2uid($mailbox, $id); + + if (empty($uid)) $uid = $this->conn->ID2UID($mailbox, $id); - } $this->uid_id_map[$mailbox][$uid] = $id; @@ -4961,16 +4704,24 @@ class rcube_message_part */ class rcube_header_sorter { - var $sequence_numbers = array(); + private $seqs = array(); + private $uids = array(); + /** * Set the predetermined sort order. * - * @param array $seqnums Numerically indexed array of IMAP message sequence numbers + * @param array $index Numerically indexed array of IMAP ID or UIDs + * @param bool $is_uid Set to true if $index contains UIDs */ - function set_sequence_numbers($seqnums) + function set_index($index, $is_uid = false) { - $this->sequence_numbers = array_flip($seqnums); + $index = array_flip($index); + + if ($is_uid) + $this->uids = $index; + else + $this->seqs = $index; } /** @@ -4980,14 +4731,10 @@ class rcube_header_sorter */ function sort_headers(&$headers) { - /* - * uksort would work if the keys were the sequence number, but unfortunately - * the keys are the UIDs. We'll use uasort instead and dereference the value - * to get the sequence number (in the "id" field). - * - * uksort($headers, array($this, "compare_seqnums")); - */ - uasort($headers, array($this, "compare_seqnums")); + if (!empty($this->uids)) + uksort($headers, array($this, "compare_uids")); + else + uasort($headers, array($this, "compare_seqnums")); } /** @@ -5003,8 +4750,24 @@ class rcube_header_sorter $seqb = $b->id; // then find each sequence number in my ordered list - $posa = isset($this->sequence_numbers[$seqa]) ? intval($this->sequence_numbers[$seqa]) : -1; - $posb = isset($this->sequence_numbers[$seqb]) ? intval($this->sequence_numbers[$seqb]) : -1; + $posa = isset($this->seqs[$seqa]) ? intval($this->seqs[$seqa]) : -1; + $posb = isset($this->seqs[$seqb]) ? intval($this->seqs[$seqb]) : -1; + + // return the relative position as the comparison value + return $posa - $posb; + } + + /** + * Sort method called by uksort() + * + * @param int $a Array key (UID) + * @param int $b Array key (UID) + */ + function compare_uids($a, $b) + { + // then find each sequence number in my ordered list + $posa = isset($this->uids[$a]) ? intval($this->uids[$a]) : -1; + $posb = isset($this->uids[$b]) ? intval($this->uids[$b]) : -1; // return the relative position as the comparison value return $posa - $posb; diff --git a/program/include/rcube_imap_cache.php b/program/include/rcube_imap_cache.php new file mode 100644 index 0000000..75b9443 --- /dev/null +++ b/program/include/rcube_imap_cache.php @@ -0,0 +1,1212 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/include/rcube_imap_cache.php | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Caching of IMAP folder contents (messages and index) | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ + + $Id: rcube_imap_cache.php 5366 2011-10-26 11:48:27Z thomasb $ + +*/ + + +/** + * Interface class for accessing Roundcube messages cache + * + * @package Cache + * @author Thomas Bruederli <roundcube@gmail.com> + * @author Aleksander Machniak <alec@alec.pl> + * @version 1.0 + */ +class rcube_imap_cache +{ + /** + * Instance of rcube_imap + * + * @var rcube_imap + */ + private $imap; + + /** + * Instance of rcube_mdb2 + * + * @var rcube_mdb2 + */ + private $db; + + /** + * User ID + * + * @var int + */ + private $userid; + + /** + * Internal (in-memory) cache + * + * @var array + */ + private $icache = array(); + + private $skip_deleted = false; + + /** + * List of known flags. Thanks to this we can handle flag changes + * with good performance. Bad thing is we need to know used flags. + */ + public $flags = array( + 1 => 'SEEN', // RFC3501 + 2 => 'DELETED', // RFC3501 + 4 => 'ANSWERED', // RFC3501 + 8 => 'FLAGGED', // RFC3501 + 16 => 'DRAFT', // RFC3501 + 32 => 'MDNSENT', // RFC3503 + 64 => 'FORWARDED', // RFC5550 + 128 => 'SUBMITPENDING', // RFC5550 + 256 => 'SUBMITTED', // RFC5550 + 512 => 'JUNK', + 1024 => 'NONJUNK', + 2048 => 'LABEL1', + 4096 => 'LABEL2', + 8192 => 'LABEL3', + 16384 => 'LABEL4', + 32768 => 'LABEL5', + ); + + + /** + * Object constructor. + */ + function __construct($db, $imap, $userid, $skip_deleted) + { + $this->db = $db; + $this->imap = $imap; + $this->userid = (int)$userid; + $this->skip_deleted = $skip_deleted; + } + + + /** + * Cleanup actions (on shutdown). + */ + public function close() + { + $this->save_icache(); + $this->icache = null; + } + + + /** + * Return (sorted) messages index. + * If index doesn't exist or is invalid, will be updated. + * + * @param string $mailbox Folder name + * @param string $sort_field Sorting column + * @param string $sort_order Sorting order (ASC|DESC) + * @param bool $exiting Skip index initialization if it doesn't exist in DB + * + * @return array Messages index + */ + function get_index($mailbox, $sort_field = null, $sort_order = null, $existing = false) + { + if (empty($this->icache[$mailbox])) + $this->icache[$mailbox] = array(); + + $sort_order = strtoupper($sort_order) == 'ASC' ? 'ASC' : 'DESC'; + + // Seek in internal cache + if (array_key_exists('index', $this->icache[$mailbox])) { + // The index was fetched from database already, but not validated yet + if (!array_key_exists('result', $this->icache[$mailbox]['index'])) { + $index = $this->icache[$mailbox]['index']; + } + // We've got a valid index + else if ($sort_field == 'ANY' || $this->icache[$mailbox]['index']['sort_field'] == $sort_field + ) { + if ($this->icache[$mailbox]['index']['sort_order'] == $sort_order) + return $this->icache[$mailbox]['index']['result']; + else + return array_reverse($this->icache[$mailbox]['index']['result'], true); + } + } + + // Get index from DB (if DB wasn't already queried) + if (empty($index) && empty($this->icache[$mailbox]['index_queried'])) { + $index = $this->get_index_row($mailbox); + + // set the flag that DB was already queried for index + // this way we'll be able to skip one SELECT, when + // get_index() is called more than once + $this->icache[$mailbox]['index_queried'] = true; + } + + $data = null; + + // @TODO: Think about skipping validation checks. + // If we could check only every 10 minutes, we would be able to skip + // expensive checks, mailbox selection or even IMAP connection, this would require + // additional logic to force cache invalidation in some cases + // and many rcube_imap changes to connect when needed + + // Entry exists, check cache status + if (!empty($index)) { + $exists = true; + + if ($sort_field == 'ANY') { + $sort_field = $index['sort_field']; + } + + if ($sort_field != $index['sort_field']) { + $is_valid = false; + } + else { + $is_valid = $this->validate($mailbox, $index, $exists); + } + + if ($is_valid) { + // build index, assign sequence IDs to unique IDs + $data = array_combine($index['seq'], $index['uid']); + // revert the order if needed + if ($index['sort_order'] != $sort_order) + $data = array_reverse($data, true); + } + } + else { + if ($existing) { + return null; + } + else if ($sort_field == 'ANY') { + $sort_field = ''; + } + + // Got it in internal cache, so the row already exist + $exists = array_key_exists('index', $this->icache[$mailbox]); + } + + // Index not found, not valid or sort field changed, get index from IMAP server + if ($data === null) { + // Get mailbox data (UIDVALIDITY, counters, etc.) for status check + $mbox_data = $this->imap->mailbox_data($mailbox); + $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data); + + // insert/update + $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, + $exists, $index['modseq']); + } + + $this->icache[$mailbox]['index'] = array( + 'result' => $data, + 'sort_field' => $sort_field, + 'sort_order' => $sort_order, + 'modseq' => !empty($index['modseq']) ? $index['modseq'] : $mbox_data['HIGHESTMODSEQ'] + ); + + return $data; + } + + + /** + * Return messages thread. + * If threaded index doesn't exist or is invalid, will be updated. + * + * @param string $mailbox Folder name + * @param string $sort_field Sorting column + * @param string $sort_order Sorting order (ASC|DESC) + * + * @return array Messages threaded index + */ + function get_thread($mailbox) + { + if (empty($this->icache[$mailbox])) + $this->icache[$mailbox] = array(); + + // Seek in internal cache + if (array_key_exists('thread', $this->icache[$mailbox])) { + return array( + $this->icache[$mailbox]['thread']['tree'], + $this->icache[$mailbox]['thread']['depth'], + $this->icache[$mailbox]['thread']['children'], + ); + } + + // Get thread from DB (if DB wasn't already queried) + if (empty($this->icache[$mailbox]['thread_queried'])) { + $index = $this->get_thread_row($mailbox); + + // set the flag that DB was already queried for thread + // this way we'll be able to skip one SELECT, when + // get_thread() is called more than once or after clear() + $this->icache[$mailbox]['thread_queried'] = true; + } + + $data = null; + + // Entry exist, check cache status + if (!empty($index)) { + $exists = true; + $is_valid = $this->validate($mailbox, $index, $exists); + + if (!$is_valid) { + $index = null; + } + } + + // Index not found or not valid, get index from IMAP server + if ($index === null) { + // Get mailbox data (UIDVALIDITY, counters, etc.) for status check + $mbox_data = $this->imap->mailbox_data($mailbox); + + if ($mbox_data['EXISTS']) { + // get all threads (default sort order) + list ($thread_tree, $msg_depth, $has_children) = $this->imap->fetch_threads($mailbox, true); + } + + $index = array( + 'tree' => !empty($thread_tree) ? $thread_tree : array(), + 'depth' => !empty($msg_depth) ? $msg_depth : array(), + 'children' => !empty($has_children) ? $has_children : array(), + ); + + // insert/update + $this->add_thread_row($mailbox, $index, $mbox_data, $exists); + } + + $this->icache[$mailbox]['thread'] = $index; + + return array($index['tree'], $index['depth'], $index['children']); + } + + + /** + * Returns list of messages (headers). See rcube_imap::fetch_headers(). + * + * @param string $mailbox Folder name + * @param array $msgs Message sequence numbers + * @param bool $is_uid True if $msgs contains message UIDs + * + * @return array The list of messages (rcube_mail_header) indexed by UID + */ + function get_messages($mailbox, $msgs = array(), $is_uid = true) + { + if (empty($msgs)) { + return array(); + } + + // @TODO: it would be nice if we could work with UIDs only + // then index would be not needed. For now we need it to + // map id to uid here and to update message id for cached message + + // Convert IDs to UIDs + $index = $this->get_index($mailbox, 'ANY'); + if (!$is_uid) { + foreach ($msgs as $idx => $msgid) + if ($uid = $index[$msgid]) + $msgs[$idx] = $uid; + } + + // Fetch messages from cache + $sql_result = $this->db->query( + "SELECT uid, data, flags" + ." FROM ".get_table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ?" + ." AND uid IN (".$this->db->array2list($msgs, 'integer').")", + $this->userid, $mailbox); + + $msgs = array_flip($msgs); + $result = array(); + + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $uid = intval($sql_arr['uid']); + $result[$uid] = $this->build_message($sql_arr); + + // save memory, we don't need message body here (?) + $result[$uid]->body = null; + + // update message ID according to index data + if (!empty($index) && ($id = array_search($uid, $index))) + $result[$uid]->id = $id; + + if (!empty($result[$uid])) { + unset($msgs[$uid]); + } + } + + // Fetch not found messages from IMAP server + if (!empty($msgs)) { + $messages = $this->imap->fetch_headers($mailbox, array_keys($msgs), true, true); + + // Insert to DB and add to result list + if (!empty($messages)) { + foreach ($messages as $msg) { + $this->add_message($mailbox, $msg, !array_key_exists($msg->uid, $result)); + $result[$msg->uid] = $msg; + } + } + } + + return $result; + } + + + /** + * Returns message data. + * + * @param string $mailbox Folder name + * @param int $uid Message UID + * @param bool $update If message doesn't exists in cache it will be fetched + * from IMAP server + * @param bool $no_cache Enables internal cache usage + * + * @return rcube_mail_header Message data + */ + function get_message($mailbox, $uid, $update = true, $cache = true) + { + // Check internal cache + if (($message = $this->icache['message']) + && $message['mailbox'] == $mailbox && $message['object']->uid == $uid + ) { + return $this->icache['message']['object']; + } + + $sql_result = $this->db->query( + "SELECT flags, data" + ." FROM ".get_table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ?" + ." AND uid = ?", + $this->userid, $mailbox, (int)$uid); + + if ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $message = $this->build_message($sql_arr); + $found = true; + + // update message ID according to index data + $index = $this->get_index($mailbox, 'ANY'); + if (!empty($index) && ($id = array_search($uid, $index))) + $message->id = $id; + } + + // Get the message from IMAP server + if (empty($message) && $update) { + $message = $this->imap->get_headers($uid, $mailbox, true); + // cache will be updated in close(), see below + } + + // Save the message in internal cache, will be written to DB in close() + // Common scenario: user opens unseen message + // - get message (SELECT) + // - set message headers/structure (INSERT or UPDATE) + // - set \Seen flag (UPDATE) + // This way we can skip one UPDATE + if (!empty($message) && $cache) { + // Save current message from internal cache + $this->save_icache(); + + $this->icache['message'] = array( + 'object' => $message, + 'mailbox' => $mailbox, + 'exists' => $found, + 'md5sum' => md5(serialize($message)), + ); + } + + return $message; + } + + + /** + * Saves the message in cache. + * + * @param string $mailbox Folder name + * @param rcube_mail_header $message Message data + * @param bool $force Skips message in-cache existance check + */ + function add_message($mailbox, $message, $force = false) + { + if (!is_object($message) || empty($message->uid)) + return; + + $msg = serialize($this->db->encode(clone $message)); + $flags = 0; + + if (!empty($message->flags)) { + foreach ($this->flags as $idx => $flag) + if (!empty($message->flags[$flag])) + $flags += $idx; + } + unset($msg->flags); + + // update cache record (even if it exists, the update + // here will work as select, assume row exist if affected_rows=0) + if (!$force) { + $res = $this->db->query( + "UPDATE ".get_table_name('cache_messages') + ." 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()) + return; + } + + // insert new record + $this->db->query( + "INSERT INTO ".get_table_name('cache_messages') + ." (user_id, mailbox, uid, flags, changed, data)" + ." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)", + $this->userid, $mailbox, (int) $message->uid, $flags, $msg); + } + + + /** + * Sets the flag for specified message. + * + * @param string $mailbox Folder name + * @param array $uids Message UIDs or null to change flag + * of all messages in a folder + * @param string $flag The name of the flag + * @param bool $enabled Flag state + */ + function change_flag($mailbox, $uids, $flag, $enabled = false) + { + $flag = strtoupper($flag); + $idx = (int) array_search($flag, $this->flags); + + if (!$idx) { + return; + } + + // Internal cache update + if ($uids && count($uids) == 1 && ($uid = current($uids)) + && ($message = $this->icache['message']) + && $message['mailbox'] == $mailbox && $message['object']->uid == $uid + ) { + $message['object']->flags[$flag] = $enabled; + return; + } + + $this->db->query( + "UPDATE ".get_table_name('cache_messages') + ." SET changed = ".$this->db->now() + .", flags = flags ".($enabled ? "+ $idx" : "- $idx") + ." WHERE user_id = ?" + ." AND mailbox = ?" + .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : "") + ." AND (flags & $idx) ".($enabled ? "= 0" : "= $idx"), + $this->userid, $mailbox); + } + + + /** + * Removes message(s) from cache. + * + * @param string $mailbox Folder name + * @param array $uids Message UIDs, NULL removes all messages + */ + function remove_message($mailbox = null, $uids = null) + { + if (!strlen($mailbox)) { + $this->db->query( + "DELETE FROM ".get_table_name('cache_messages') + ." WHERE user_id = ?", + $this->userid); + } + else { + // Remove the message from internal cache + if (!empty($uids) && !is_array($uids) && ($message = $this->icache['message']) + && $message['mailbox'] == $mailbox && $message['object']->uid == $uids + ) { + $this->icache['message'] = null; + } + + $this->db->query( + "DELETE FROM ".get_table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ".$this->db->quote($mailbox) + .($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""), + $this->userid); + } + + } + + + /** + * Clears index cache. + * + * @param string $mailbox Folder name + * @param bool $remove Enable to remove the DB row + */ + function remove_index($mailbox = null, $remove = false) + { + // The index should be only removed from database when + // UIDVALIDITY was detected or the mailbox is empty + // otherwise use 'valid' flag to not loose HIGHESTMODSEQ value + if ($remove) + $this->db->query( + "DELETE FROM ".get_table_name('cache_index') + ." WHERE user_id = ".intval($this->userid) + .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") + ); + else + $this->db->query( + "UPDATE ".get_table_name('cache_index') + ." SET valid = 0" + ." WHERE user_id = ".intval($this->userid) + .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") + ); + + if (strlen($mailbox)) { + unset($this->icache[$mailbox]['index']); + // Index removed, set flag to skip SELECT query in get_index() + $this->icache[$mailbox]['index_queried'] = true; + } + else + $this->icache = array(); + } + + + /** + * Clears thread cache. + * + * @param string $mailbox Folder name + */ + function remove_thread($mailbox = null) + { + $this->db->query( + "DELETE FROM ".get_table_name('cache_thread') + ." WHERE user_id = ".intval($this->userid) + .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "") + ); + + if (strlen($mailbox)) { + unset($this->icache[$mailbox]['thread']); + // Thread data removed, set flag to skip SELECT query in get_thread() + $this->icache[$mailbox]['thread_queried'] = true; + } + else + $this->icache = array(); + } + + + /** + * Clears the cache. + * + * @param string $mailbox Folder name + * @param array $uids Message UIDs, NULL removes all messages in a folder + */ + function clear($mailbox = null, $uids = null) + { + $this->remove_index($mailbox, true); + $this->remove_thread($mailbox); + $this->remove_message($mailbox, $uids); + } + + + /** + * @param string $mailbox Folder name + * @param int $id Message (sequence) ID + * + * @return int Message UID + */ + function id2uid($mailbox, $id) + { + if (!empty($this->icache['pending_index_update'])) + return null; + + // get index if it exists + $index = $this->get_index($mailbox, 'ANY', null, true); + + return $index[$id]; + } + + + /** + * @param string $mailbox Folder name + * @param int $uid Message UID + * + * @return int Message (sequence) ID + */ + function uid2id($mailbox, $uid) + { + if (!empty($this->icache['pending_index_update'])) + return null; + + // get index if it exists + $index = $this->get_index($mailbox, 'ANY', null, true); + + return array_search($uid, (array)$index); + } + + /** + * Fetches index data from database + */ + private function get_index_row($mailbox) + { + // Get index from DB + $sql_result = $this->db->query( + "SELECT data, valid" + ." FROM ".get_table_name('cache_index') + ." WHERE user_id = ?" + ." AND mailbox = ?", + $this->userid, $mailbox); + + if ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $data = explode('@', $sql_arr['data']); + + return array( + 'valid' => $sql_arr['valid'], + 'seq' => explode(',', $data[0]), + 'uid' => explode(',', $data[1]), + 'sort_field' => $data[2], + 'sort_order' => $data[3], + 'deleted' => $data[4], + 'validity' => $data[5], + 'uidnext' => $data[6], + 'modseq' => $data[7], + ); + } + + return null; + } + + + /** + * Fetches thread data from database + */ + private function get_thread_row($mailbox) + { + // Get thread from DB + $sql_result = $this->db->query( + "SELECT data" + ." FROM ".get_table_name('cache_thread') + ." WHERE user_id = ?" + ." AND mailbox = ?", + $this->userid, $mailbox); + + if ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $data = explode('@', $sql_arr['data']); + + // Uncompress data, see add_thread_row() + // $data[0] = str_replace(array('*', '^', '#'), array(';a:0:{}', 'i:', ';a:1:'), $data[0]); + $data[0] = unserialize($data[0]); + + // build 'depth' and 'children' arrays + $depth = $children = array(); + $this->build_thread_data($data[0], $depth, $children); + + return array( + 'tree' => $data[0], + 'depth' => $depth, + 'children' => $children, + 'deleted' => $data[1], + 'validity' => $data[2], + 'uidnext' => $data[3], + ); + } + + return null; + } + + + /** + * Saves index data into database + */ + private function add_index_row($mailbox, $sort_field, $sort_order, + $data = array(), $mbox_data = array(), $exists = false, $modseq = null) + { + $data = array( + implode(',', array_keys($data)), + implode(',', array_values($data)), + $sort_field, + $sort_order, + (int) $this->skip_deleted, + (int) $mbox_data['UIDVALIDITY'], + (int) $mbox_data['UIDNEXT'], + $modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'], + ); + $data = implode('@', $data); + + if ($exists) + $sql_result = $this->db->query( + "UPDATE ".get_table_name('cache_index') + ." SET data = ?, valid = 1, changed = ".$this->db->now() + ." WHERE user_id = ?" + ." AND mailbox = ?", + $data, $this->userid, $mailbox); + else + $sql_result = $this->db->query( + "INSERT INTO ".get_table_name('cache_index') + ." (user_id, mailbox, data, valid, changed)" + ." VALUES (?, ?, ?, 1, ".$this->db->now().")", + $this->userid, $mailbox, $data); + } + + + /** + * Saves thread data into database + */ + private function add_thread_row($mailbox, $data = array(), $mbox_data = array(), $exists = false) + { + $tree = serialize($data['tree']); + // This significantly reduces data length +// $tree = str_replace(array(';a:0:{}', 'i:', ';a:1:'), array('*', '^', '#'), $tree); + + $data = array( + $tree, + (int) $this->skip_deleted, + (int) $mbox_data['UIDVALIDITY'], + (int) $mbox_data['UIDNEXT'], + ); + $data = implode('@', $data); + + if ($exists) + $sql_result = $this->db->query( + "UPDATE ".get_table_name('cache_thread') + ." SET data = ?, changed = ".$this->db->now() + ." WHERE user_id = ?" + ." AND mailbox = ?", + $data, $this->userid, $mailbox); + else + $sql_result = $this->db->query( + "INSERT INTO ".get_table_name('cache_thread') + ." (user_id, mailbox, data, changed)" + ." VALUES (?, ?, ?, ".$this->db->now().")", + $this->userid, $mailbox, $data); + } + + + /** + * Checks index/thread validity + */ + private function validate($mailbox, $index, &$exists = true) + { + $is_thread = isset($index['tree']); + + // Get mailbox data (UIDVALIDITY, counters, etc.) for status check + $mbox_data = $this->imap->mailbox_data($mailbox); + + // @TODO: Think about skipping validation checks. + // If we could check only every 10 minutes, we would be able to skip + // expensive checks, mailbox selection or even IMAP connection, this would require + // additional logic to force cache invalidation in some cases + // and many rcube_imap changes to connect when needed + + // Check UIDVALIDITY + if ($index['validity'] != $mbox_data['UIDVALIDITY']) { + $this->clear($mailbox); + $exists = false; + return false; + } + + // Folder is empty but cache isn't + if (empty($mbox_data['EXISTS'])) { + if (!empty($index['seq']) || !empty($index['tree'])) { + $this->clear($mailbox); + $exists = false; + return false; + } + } + // Folder is not empty but cache is + else if (empty($index['seq']) && empty($index['tree'])) { + unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); + return false; + } + + // Validation flag + if (!$is_thread && empty($index['valid'])) { + unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); + return false; + } + + // Index was created with different skip_deleted setting + if ($this->skip_deleted != $index['deleted']) { + return false; + } + + // Check HIGHESTMODSEQ + if (!empty($index['modseq']) && !empty($mbox_data['HIGHESTMODSEQ']) + && $index['modseq'] == $mbox_data['HIGHESTMODSEQ'] + ) { + return true; + } + + // Check UIDNEXT + if ($index['uidnext'] != $mbox_data['UIDNEXT']) { + unset($this->icache[$mailbox][$is_thread ? 'thread' : 'index']); + return false; + } + + // @TODO: find better validity check for threaded index + if ($is_thread) { + // check messages number... + if (!$this->skip_deleted && $mbox_data['EXISTS'] != @max(array_keys($index['depth']))) { + return false; + } + return true; + } + + // The rest of checks, more expensive + if (!empty($this->skip_deleted)) { + // compare counts if available + if ($mbox_data['COUNT_UNDELETED'] != null + && $mbox_data['COUNT_UNDELETED'] != count($index['uid'])) { + return false; + } + // compare UID sets + if ($mbox_data['ALL_UNDELETED'] != null) { + $uids_new = rcube_imap_generic::uncompressMessageSet($mbox_data['ALL_UNDELETED']); + $uids_old = $index['uid']; + + if (count($uids_new) != count($uids_old)) { + return false; + } + + sort($uids_new, SORT_NUMERIC); + sort($uids_old, SORT_NUMERIC); + + if ($uids_old != $uids_new) + return false; + } + else { + // get all undeleted messages excluding cached UIDs + $ids = $this->imap->search_once($mailbox, 'ALL UNDELETED NOT UID '. + rcube_imap_generic::compressMessageSet($index['uid'])); + + if (!empty($ids)) { + return false; + } + } + } + else { + // check messages number... + if ($mbox_data['EXISTS'] != max($index['seq'])) { + return false; + } + // ... and max UID + if (max($index['uid']) != $this->imap->id2uid($mbox_data['EXISTS'], $mailbox, true)) { + return false; + } + } + + return true; + } + + + /** + * Synchronizes the mailbox. + * + * @param string $mailbox Folder name + */ + function synchronize($mailbox) + { + // RFC4549: Synchronization Operations for Disconnected IMAP4 Clients + // RFC4551: IMAP Extension for Conditional STORE Operation + // or Quick Flag Changes Resynchronization + // RFC5162: IMAP Extensions for Quick Mailbox Resynchronization + + // @TODO: synchronize with other methods? + $qresync = $this->imap->get_capability('QRESYNC'); + $condstore = $qresync ? true : $this->imap->get_capability('CONDSTORE'); + + if (!$qresync && !$condstore) { + return; + } + + // Get stored index + $index = $this->get_index_row($mailbox); + + // database is empty + if (empty($index)) { + // set the flag that DB was already queried for index + // this way we'll be able to skip one SELECT in get_index() + $this->icache[$mailbox]['index_queried'] = true; + return; + } + + $this->icache[$mailbox]['index'] = $index; + + // no last HIGHESTMODSEQ value + if (empty($index['modseq'])) { + return; + } + + // NOTE: make sure the mailbox isn't selected, before + // enabling QRESYNC and invoking SELECT + if ($this->imap->conn->selected !== null) { + $this->imap->conn->close(); + } + + // Enable QRESYNC + $res = $this->imap->conn->enable($qresync ? 'QRESYNC' : 'CONDSTORE'); + if (!is_array($res)) { + return; + } + + // Get mailbox data (UIDVALIDITY, HIGHESTMODSEQ, counters, etc.) + $mbox_data = $this->imap->mailbox_data($mailbox); + + if (empty($mbox_data)) { + return; + } + + // Check UIDVALIDITY + if ($index['validity'] != $mbox_data['UIDVALIDITY']) { + $this->clear($mailbox); + return; + } + + // QRESYNC not supported on specified mailbox + if (!empty($mbox_data['NOMODSEQ']) || empty($mbox_data['HIGHESTMODSEQ'])) { + return; + } + + // Nothing new + if ($mbox_data['HIGHESTMODSEQ'] == $index['modseq']) { + return; + } + + // Get known uids + $uids = array(); + $sql_result = $this->db->query( + "SELECT uid" + ." FROM ".get_table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ?", + $this->userid, $mailbox); + + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $uids[] = $sql_arr['uid']; + } + + // No messages in database, nothing to sync + if (empty($uids)) { + return; + } + + // Get modified flags and vanished messages + // UID FETCH 1:* (FLAGS) (CHANGEDSINCE 0123456789 VANISHED) + $result = $this->imap->conn->fetch($mailbox, + !empty($uids) ? $uids : '1:*', true, array('FLAGS'), + $index['modseq'], $qresync); + + $invalidated = false; + + if (!empty($result)) { + foreach ($result as $id => $msg) { + $uid = $msg->uid; + // Remove deleted message + if ($this->skip_deleted && !empty($msg->flags['DELETED'])) { + $this->remove_message($mailbox, $uid); + + if (!$invalidated) { + $invalidated = true; + // Invalidate thread indexes (?) + $this->remove_thread($mailbox); + // Invalidate index + $index['valid'] = false; + } + continue; + } + + $flags = 0; + if (!empty($msg->flags)) { + foreach ($this->flags as $idx => $flag) + if (!empty($msg->flags[$flag])) + $flags += $idx; + } + + $this->db->query( + "UPDATE ".get_table_name('cache_messages') + ." SET flags = ?, changed = ".$this->db->now() + ." WHERE user_id = ?" + ." AND mailbox = ?" + ." AND uid = ?" + ." AND flags <> ?", + $flags, $this->userid, $mailbox, $uid, $flags); + } + } + + // Get VANISHED + if ($qresync) { + $mbox_data = $this->imap->mailbox_data($mailbox); + + // Removed messages + if (!empty($mbox_data['VANISHED'])) { + $uids = rcube_imap_generic::uncompressMessageSet($mbox_data['VANISHED']); + if (!empty($uids)) { + // remove messages from database + $this->remove_message($mailbox, $uids); + + // Invalidate thread indexes (?) + $this->remove_thread($mailbox); + // Invalidate index + $index['valid'] = false; + } + } + } + + $sort_field = $index['sort_field']; + $sort_order = $index['sort_order']; + $exists = true; + + // Validate index + if (!$this->validate($mailbox, $index, $exists)) { + // Update index + $data = $this->get_index_data($mailbox, $sort_field, $sort_order, $mbox_data); + } + else { + $data = array_combine($index['seq'], $index['uid']); + } + + // update index and/or HIGHESTMODSEQ value + $this->add_index_row($mailbox, $sort_field, $sort_order, $data, $mbox_data, $exists); + + // update internal cache for get_index() + $this->icache[$mailbox]['index']['result'] = $data; + } + + + /** + * Converts cache row into message object. + * + * @param array $sql_arr Message row data + * + * @return rcube_mail_header Message object + */ + private function build_message($sql_arr) + { + $message = $this->db->decode(unserialize($sql_arr['data'])); + + if ($message) { + $message->flags = array(); + foreach ($this->flags as $idx => $flag) + if (($sql_arr['flags'] & $idx) == $idx) + $message->flags[$flag] = true; + } + + return $message; + } + + + /** + * Creates 'depth' and 'children' arrays from stored thread 'tree' data. + */ + private function build_thread_data($data, &$depth, &$children, $level = 0) + { + foreach ((array)$data as $key => $val) { + $children[$key] = !empty($val); + $depth[$key] = $level; + if (!empty($val)) + $this->build_thread_data($val, $depth, $children, $level + 1); + } + } + + + /** + * Saves message stored in internal cache + */ + private function save_icache() + { + // Save current message from internal cache + if ($message = $this->icache['message']) { + // clean up some object's data + $object = $this->message_object_prepare($message['object']); + + // calculate current md5 sum + $md5sum = md5(serialize($object)); + + if ($message['md5sum'] != $md5sum) { + $this->add_message($message['mailbox'], $object, !$message['exists']); + } + + $this->icache['message']['md5sum'] = $md5sum; + } + } + + + /** + * Prepares message object to be stored in database. + */ + private function message_object_prepare($msg) + { + // 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 + // Another solution would be to use object's copy in rcube_message class + // to prevent related issues, however I'm not sure which is better + if ($msg->mimetype) { + list($msg->ctype_primary, $msg->ctype_secondary) = explode('/', $msg->mimetype); + } + + if (is_array($msg->structure->parts)) { + foreach ($msg->structure->parts as $idx => $part) { + $msg->structure->parts[$idx] = $this->message_object_prepare($part); + } + } + + return $msg; + } + + + /** + * Fetches index data from IMAP server + */ + private function get_index_data($mailbox, $sort_field, $sort_order, $mbox_data = array()) + { + $data = array(); + + if (empty($mbox_data)) { + $mbox_data = $this->imap->mailbox_data($mailbox); + } + + // Prevent infinite loop. + // It happens when rcube_imap::message_index_direct() is called. + // There id2uid() is called which will again call get_index() and so on. + if (!$sort_field && !$this->skip_deleted) + $this->icache['pending_index_update'] = true; + + if ($mbox_data['EXISTS']) { + // fetch sorted sequence numbers + $data_seq = $this->imap->message_index_direct($mailbox, $sort_field, $sort_order); + // fetch UIDs + if (!empty($data_seq)) { + // Seek in internal cache + if (array_key_exists('index', (array)$this->icache[$mailbox]) + && array_key_exists('result', (array)$this->icache[$mailbox]['index']) + ) + $data_uid = $this->icache[$mailbox]['index']['result']; + else + $data_uid = $this->imap->conn->fetchUIDs($mailbox, $data_seq); + + // build index + if (!empty($data_uid)) { + foreach ($data_seq as $seq) + if ($uid = $data_uid[$seq]) + $data[$seq] = $uid; + } + } + } + + // Reset internal flags + $this->icache['pending_index_update'] = false; + + return $data; + } +} diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 7ae59bb..4c002fc 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -6,6 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -21,7 +22,7 @@ | Author: Ryo Chijiiwa <Ryo@IlohaMail.org> | +-----------------------------------------------------------------------+ - $Id: rcube_imap_generic.php 5213 2011-09-13 08:09:50Z alec $ + $Id: rcube_imap_generic.php 5402 2011-11-09 10:03:54Z alec $ */ @@ -48,23 +49,14 @@ class rcube_mail_header public $encoding; public $charset; public $ctype; - public $flags; public $timestamp; - public $body_structure; + public $bodystructure; public $internaldate; public $references; public $priority; public $mdn_to; - public $mdn_sent = false; - public $seen = false; - public $deleted = false; - public $answered = false; - public $forwarded = false; - public $flagged = false; - public $has_children = false; - public $depth = 0; - public $unread_children = 0; public $others = array(); + public $flags = array(); } // For backward compatibility with cached messages (#1486602) @@ -84,6 +76,7 @@ class rcube_imap_generic public $errornum; public $result; public $resultcode; + public $selected; public $data = array(); public $flags = array( 'SEEN' => '\\Seen', @@ -96,7 +89,6 @@ class rcube_imap_generic '*' => '\\*', ); - private $selected; private $fp; private $host; private $logged = false; @@ -235,14 +227,14 @@ class rcube_imap_generic return $line; } - function multLine($line, $escape=false) + function multLine($line, $escape = false) { $line = rtrim($line); - if (preg_match('/\{[0-9]+\}$/', $line)) { - $out = ''; + if (preg_match('/\{([0-9]+)\}$/', $line, $m)) { + $out = ''; + $str = substr($line, 0, -strlen($m[0])); + $bytes = $m[1]; - preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a); - $bytes = $a[2][0]; while (strlen($out) < $bytes) { $line = $this->readBytes($bytes); if ($line === NULL) @@ -250,7 +242,7 @@ class rcube_imap_generic $out .= $line; } - $line = $a[1][0] . ($escape ? $this->escape($out) : $out); + $line = $str . ($escape ? $this->escape($out) : $out); } return $line; @@ -318,6 +310,10 @@ class rcube_imap_generic } else { $this->resultcode = null; + // parse response for [APPENDUID 1204196876 3456] + if (preg_match("/^\[APPENDUID [0-9]+ ([0-9,:*]+)\]/i", $str, $m)) { + $this->data['APPENDUID'] = $m[1]; + } } $this->result = $str; @@ -680,8 +676,8 @@ class rcube_imap_generic $this->prefs = $options; } // set auth method - if (!empty($this->prefs['auth_method'])) { - $auth_method = strtoupper($this->prefs['auth_method']); + if (!empty($this->prefs['auth_type'])) { + $auth_method = strtoupper($this->prefs['auth_type']); } else { $auth_method = 'CHECK'; } @@ -691,7 +687,7 @@ class rcube_imap_generic // initialize connection $this->error = ''; $this->errornum = self::ERROR_OK; - $this->selected = ''; + $this->selected = null; $this->user = $user; $this->host = $host; $this->logged = false; @@ -877,18 +873,18 @@ class rcube_imap_generic /** * Executes SELECT command (if mailbox is already not in selected state) * - * @param string $mailbox Mailbox name + * @param string $mailbox Mailbox name + * @param array $qresync_data QRESYNC data (RFC5162) * * @return boolean True on success, false on error - * @access public */ - function select($mailbox) + function select($mailbox, $qresync_data = null) { if (!strlen($mailbox)) { return false; } - if ($this->selected == $mailbox) { + if ($this->selected === $mailbox) { return true; } /* @@ -901,7 +897,21 @@ class rcube_imap_generic } } */ - list($code, $response) = $this->execute('SELECT', array($this->escape($mailbox))); + $params = array($this->escape($mailbox)); + + // QRESYNC data items + // 0. the last known UIDVALIDITY, + // 1. the last known modification sequence, + // 2. the optional set of known UIDs, and + // 3. an optional parenthesized list of known sequence ranges and their + // corresponding UIDs. + if (!empty($qresync_data)) { + if (!empty($qresync_data[2])) + $qresync_data[2] = self::compressMessageSet($qresync_data[2]); + $params[] = array('QRESYNC', $qresync_data); + } + + list($code, $response) = $this->execute('SELECT', $params); if ($code == self::ERROR_OK) { $response = explode("\r\n", $response); @@ -909,11 +919,39 @@ class rcube_imap_generic if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/i', $line, $m)) { $this->data[strtoupper($m[2])] = (int) $m[1]; } - else if (preg_match('/^\* OK \[(UIDNEXT|UIDVALIDITY|UNSEEN) ([0-9]+)\]/i', $line, $match)) { - $this->data[strtoupper($match[1])] = (int) $match[2]; + else if (preg_match('/^\* OK \[/i', $line, $match)) { + $line = substr($line, 6); + if (preg_match('/^(UIDNEXT|UIDVALIDITY|UNSEEN) ([0-9]+)/i', $line, $match)) { + $this->data[strtoupper($match[1])] = (int) $match[2]; + } + else if (preg_match('/^(HIGHESTMODSEQ) ([0-9]+)/i', $line, $match)) { + $this->data[strtoupper($match[1])] = (string) $match[2]; + } + else if (preg_match('/^(NOMODSEQ)/i', $line, $match)) { + $this->data[strtoupper($match[1])] = true; + } + else if (preg_match('/^PERMANENTFLAGS \(([^\)]+)\)/iU', $line, $match)) { + $this->data['PERMANENTFLAGS'] = explode(' ', $match[1]); + } + } + // QRESYNC FETCH response (RFC5162) + else if (preg_match('/^\* ([0-9+]) FETCH/i', $line, $match)) { + $line = substr($line, strlen($match[0])); + $fetch_data = $this->tokenizeResponse($line, 1); + $data = array('id' => $match[1]); + + for ($i=0, $size=count($fetch_data); $i<$size; $i+=2) { + $data[strtolower($fetch_data[$i])] = $fetch_data[$i+1]; + } + + $this->data['QRESYNC'][$data['uid']] = $data; } - else if (preg_match('/^\* OK \[PERMANENTFLAGS \(([^\)]+)\)\]/iU', $line, $match)) { - $this->data['PERMANENTFLAGS'] = explode(' ', $match[1]); + // QRESYNC VANISHED response (RFC5162) + else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { + $line = substr($line, strlen($match[0])); + $v_data = $this->tokenizeResponse($line, 1); + + $this->data['VANISHED'] = $v_data; } } @@ -935,7 +973,6 @@ class rcube_imap_generic * in RFC3501: UIDNEXT, UIDVALIDITY, RECENT * * @return array Status item-value hash - * @access public * @since 0.5-beta */ function status($mailbox, $items=array()) @@ -971,7 +1008,7 @@ class rcube_imap_generic } for ($i=0, $len=count($items); $i<$len; $i += 2) { - $result[$items[$i]] = (int) $items[$i+1]; + $result[$items[$i]] = $items[$i+1]; } $this->data['STATUS:'.$mailbox] = $result; @@ -989,7 +1026,6 @@ class rcube_imap_generic * @param string $messages Message UIDs to expunge * * @return boolean True on success, False on error - * @access public */ function expunge($mailbox, $messages=NULL) { @@ -1011,7 +1047,7 @@ class rcube_imap_generic $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE); if ($result == self::ERROR_OK) { - $this->selected = ''; // state has changed, need to reselect + $this->selected = null; // state has changed, need to reselect return true; } @@ -1022,7 +1058,6 @@ class rcube_imap_generic * Executes CLOSE command * * @return boolean True on success, False on error - * @access public * @since 0.5 */ function close() @@ -1030,7 +1065,7 @@ class rcube_imap_generic $result = $this->execute('CLOSE', NULL, self::COMMAND_NORESPONSE); if ($result == self::ERROR_OK) { - $this->selected = ''; + $this->selected = null; return true; } @@ -1043,7 +1078,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return boolean True on success, False on error - * @access public */ function subscribe($mailbox) { @@ -1059,7 +1093,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return boolean True on success, False on error - * @access public */ function unsubscribe($mailbox) { @@ -1075,7 +1108,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return boolean True on success, False on error - * @access public */ function deleteFolder($mailbox) { @@ -1091,7 +1123,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return boolean True on success, False on error - * @access public */ function clearFolder($mailbox) { @@ -1101,7 +1132,7 @@ class rcube_imap_generic } if ($res) { - if ($this->selected == $mailbox) + if ($this->selected === $mailbox) $res = $this->close(); else $res = $this->expunge($mailbox); @@ -1116,15 +1147,14 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return int Number of messages, False on error - * @access public */ function countMessages($mailbox, $refresh = false) { if ($refresh) { - $this->selected = ''; + $this->selected = null; } - if ($this->selected == $mailbox) { + if ($this->selected === $mailbox) { return $this->data['EXISTS']; } @@ -1149,7 +1179,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return int Number of messages, False on error - * @access public */ function countRecent($mailbox) { @@ -1159,7 +1188,7 @@ class rcube_imap_generic $this->select($mailbox); - if ($this->selected == $mailbox) { + if ($this->selected === $mailbox) { return $this->data['RECENT']; } @@ -1172,7 +1201,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return int Number of messages, False on error - * @access public */ function countUnseen($mailbox) { @@ -1203,7 +1231,6 @@ class rcube_imap_generic * @param array $items Client identification information key/value hash * * @return array Server identification information key/value hash - * @access public * @since 0.6 */ function id($items=array()) @@ -1235,6 +1262,37 @@ class rcube_imap_generic return false; } + /** + * Executes ENABLE command (RFC5161) + * + * @param mixed $extension Extension name to enable (or array of names) + * + * @return array|bool List of enabled extensions, False on error + * @since 0.6 + */ + function enable($extension) + { + if (empty($extension)) + return false; + + if (!$this->hasCapability('ENABLE')) + return false; + + if (!is_array($extension)) + $extension = array($extension); + + list($code, $response) = $this->execute('ENABLE', $extension); + + if ($code == self::ERROR_OK && preg_match('/\* ENABLED /i', $response)) { + $response = substr($response, 10); // remove prefix "* ENABLED " + $result = (array) $this->tokenizeResponse($response); + + return $result; + } + + return false; + } + function sort($mailbox, $field, $add='', $is_uid=FALSE, $encoding = 'US-ASCII') { $field = strtoupper($field); @@ -1472,7 +1530,6 @@ class rcube_imap_generic * @param int $uid Message unique identifier (UID) * * @return int Message sequence identifier - * @access public */ function UID2ID($mailbox, $uid) { @@ -1492,12 +1549,11 @@ class rcube_imap_generic * @param int $uid Message sequence identifier * * @return int Message unique identifier - * @access public */ function ID2UID($mailbox, $id) { if (empty($id) || $id < 0) { - return null; + return null; } if (!$this->select($mailbox)) { @@ -1515,47 +1571,59 @@ class rcube_imap_generic function fetchUIDs($mailbox, $message_set=null) { - if (is_array($message_set)) - $message_set = join(',', $message_set); - else if (empty($message_set)) + if (empty($message_set)) $message_set = '1:*'; return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false); } - function fetchHeaders($mailbox, $message_set, $uidfetch=false, $bodystr=false, $add='') + /** + * FETCH command (RFC3501) + * + * @param string $mailbox Mailbox name + * @param mixed $message_set Message(s) sequence identifier(s) or UID(s) + * @param bool $is_uid True if $message_set contains UIDs + * @param array $query_items FETCH command data items + * @param string $mod_seq Modification sequence for CHANGEDSINCE (RFC4551) query + * @param bool $vanished Enables VANISHED parameter (RFC5162) for CHANGEDSINCE query + * + * @return array List of rcube_mail_header elements, False on error + * @since 0.6 + */ + function fetch($mailbox, $message_set, $is_uid = false, $query_items = array(), + $mod_seq = null, $vanished = false) { - $result = array(); - if (!$this->select($mailbox)) { return false; } $message_set = $this->compressMessageSet($message_set); + $result = array(); - if ($add) - $add = ' '.trim($add); - - /* FETCH uid, size, flags and headers */ $key = $this->nextTag(); - $request = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set "; - $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE "; - if ($bodystr) - $request .= "BODYSTRUCTURE "; - $request .= "BODY.PEEK[HEADER.FIELDS (DATE FROM TO SUBJECT CONTENT-TYPE "; - $request .= "CC REPLY-TO LIST-POST DISPOSITION-NOTIFICATION-TO".$add.")])"; + $request = $key . ($is_uid ? ' UID' : '') . " FETCH $message_set "; + $request .= "(" . implode(' ', $query_items) . ")"; + + if ($mod_seq !== null && $this->hasCapability('CONDSTORE')) { + $request .= " (CHANGEDSINCE $mod_seq" . ($vanished ? " VANISHED" : '') .")"; + } if (!$this->putLine($request)) { $this->setError(self::ERROR_COMMAND, "Unable to send command: $request"); return false; } + do { $line = $this->readLine(4096); - $line = $this->multLine($line); if (!$line) break; + // Sample reply line: + // * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen) + // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) + // BODY[HEADER.FIELDS ... + if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { $id = intval($m[1]); @@ -1565,101 +1633,91 @@ class rcube_imap_generic $result[$id]->messageID = 'mid:' . $id; $lines = array(); - $ln = 0; - - // Sample reply line: - // * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen) - // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) - // BODY[HEADER.FIELDS ... + $line = substr($line, strlen($m[0]) + 2); + $ln = 0; - if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/sU', $line, $matches)) { - $str = $matches[1]; + // get complete entry + while (preg_match('/\{([0-9]+)\}\r\n$/', $line, $m)) { + $bytes = $m[1]; + $out = ''; - while (list($name, $value) = $this->tokenizeResponse($str, 2)) { - if ($name == 'UID') { - $result[$id]->uid = intval($value); - } - else if ($name == 'RFC822.SIZE') { - $result[$id]->size = intval($value); - } - else if ($name == 'INTERNALDATE') { - $result[$id]->internaldate = $value; - $result[$id]->date = $value; - $result[$id]->timestamp = $this->StrToTime($value); - } - else if ($name == 'FLAGS') { - $flags_a = $value; - } + while (strlen($out) < $bytes) { + $out = $this->readBytes($bytes); + if ($out === NULL) + break; + $line .= $out; } - // BODYSTRUCTURE - if ($bodystr) { - while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/sU', $line, $m)) { - $line2 = $this->readLine(1024); - $line .= $this->multLine($line2, true); - } - $result[$id]->body_structure = $m[1]; + $str = $this->readLine(4096); + if ($str === false) + break; + + $line .= $str; + } + + // Tokenize response and assign to object properties + while (list($name, $value) = $this->tokenizeResponse($line, 2)) { + if ($name == 'UID') { + $result[$id]->uid = intval($value); + } + else if ($name == 'RFC822.SIZE') { + $result[$id]->size = intval($value); } + else if ($name == 'RFC822.TEXT') { + $result[$id]->body = $value; + } + else if ($name == 'INTERNALDATE') { + $result[$id]->internaldate = $value; + $result[$id]->date = $value; + $result[$id]->timestamp = $this->StrToTime($value); + } + else if ($name == 'FLAGS') { + if (!empty($value)) { + foreach ((array)$value as $flag) { + $flag = str_replace(array('$', '\\'), '', $flag); + $flag = strtoupper($flag); - // the rest of the result - if (preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m)) { - $reslines = explode("\n", trim($m[1], '"')); - // re-parse (see below) - foreach ($reslines as $resln) { - if (ord($resln[0])<=32) { - $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($resln); - } else { - $lines[++$ln] = trim($resln); + $result[$id]->flags[$flag] = true; } } } - } - - // Start parsing headers. The problem is, some header "lines" take up multiple lines. - // So, we'll read ahead, and if the one we're reading now is a valid header, we'll - // process the previous line. Otherwise, we'll keep adding the strings until we come - // to the next valid header line. - - do { - $line = rtrim($this->readLine(300), "\r\n"); - - // The preg_match below works around communigate imap, which outputs " UID <number>)". - // Without this, the while statement continues on and gets the "FH0 OK completed" message. - // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. - // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing - // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin - // An alternative might be: - // if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break; - // however, unsure how well this would work with all imap clients. - if (preg_match("/^\s*UID [0-9]+\)$/", $line)) { - break; + else if ($name == 'MODSEQ') { + $result[$id]->modseq = $value[0]; } - - // handle FLAGS reply after headers (AOL, Zimbra?) - if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) { - $flags_a = $this->tokenizeResponse($matches[1]); - break; + else if ($name == 'ENVELOPE') { + $result[$id]->envelope = $value; } - - if (ord($line[0])<=32) { - $lines[$ln] .= (empty($lines[$ln])?'':"\n").trim($line); - } else { - $lines[++$ln] = trim($line); + else if ($name == 'BODYSTRUCTURE' || ($name == 'BODY' && count($value) > 2)) { + if (!is_array($value[0]) && (strtolower($value[0]) == 'message' && strtolower($value[1]) == 'rfc822')) { + $value = array($value); + } + $result[$id]->bodystructure = $value; } - // patch from "Maksim Rubis" <siburny@hotmail.com> - } while ($line[0] != ')' && !$this->startsWith($line, $key, true)); - - if (strncmp($line, $key, strlen($key))) { - // process header, fill rcube_mail_header obj. - // initialize - if (is_array($headers)) { - reset($headers); - while (list($k, $bar) = each($headers)) { - $headers[$k] = ''; + else if ($name == 'RFC822') { + $result[$id]->body = $value; + } + else if ($name == 'BODY') { + $body = $this->tokenizeResponse($line, 1); + if ($value[0] == 'HEADER.FIELDS') + $headers = $body; + else if (!empty($value)) + $result[$id]->bodypart[$value[0]] = $body; + else + $result[$id]->body = $body; + } + } + + // create array with header field:data + if (!empty($headers)) { + $headers = explode("\n", trim($headers)); + foreach ($headers as $hid => $resln) { + if (ord($resln[0]) <= 32) { + $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln); + } else { + $lines[++$ln] = trim($resln); } } - // create array with header field:data while (list($lines_key, $str) = each($lines)) { list($field, $string) = explode(':', $str, 2); @@ -1723,47 +1781,44 @@ class rcube_imap_generic $result[$id]->others[$field] = $string; } break; - } // end switch () - } // end while () - } - - // process flags - if (!empty($flags_a)) { - foreach ($flags_a as $flag) { - $flag = str_replace('\\', '', $flag); - $result[$id]->flags[] = $flag; - - switch (strtoupper($flag)) { - case 'SEEN': - $result[$id]->seen = true; - break; - case 'DELETED': - $result[$id]->deleted = true; - break; - case 'ANSWERED': - $result[$id]->answered = true; - break; - case '$FORWARDED': - $result[$id]->forwarded = true; - break; - case '$MDNSENT': - $result[$id]->mdn_sent = true; - break; - case 'FLAGGED': - $result[$id]->flagged = true; - break; } } } } + + // VANISHED response (QRESYNC RFC5162) + // Sample: * VANISHED (EARLIER) 300:310,405,411 + + else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { + $line = substr($line, strlen($match[0])); + $v_data = $this->tokenizeResponse($line, 1); + + $this->data['VANISHED'] = $v_data; + } + } while (!$this->startsWith($line, $key, true)); return $result; } + function fetchHeaders($mailbox, $message_set, $is_uid = false, $bodystr = false, $add = '') + { + $query_items = array('UID', 'RFC822.SIZE', 'FLAGS', 'INTERNALDATE'); + if ($bodystr) + $query_items[] = 'BODYSTRUCTURE'; + $query_items[] = 'BODY.PEEK[HEADER.FIELDS (' + . 'DATE FROM TO SUBJECT CONTENT-TYPE CC REPLY-TO LIST-POST DISPOSITION-NOTIFICATION-TO X-PRIORITY' + . ($add ? ' ' . trim($add) : '') + . ')]'; + + $result = $this->fetch($mailbox, $message_set, $is_uid, $query_items); + + return $result; + } + function fetchHeader($mailbox, $id, $uidfetch=false, $bodystr=false, $add='') { - $a = $this->fetchHeaders($mailbox, $id, $uidfetch, $bodystr, $add); + $a = $this->fetchHeaders($mailbox, $id, $uidfetch, $bodystr, $add); if (is_array($a)) { return array_shift($a); } @@ -2043,6 +2098,7 @@ class rcube_imap_generic $params .= 'RETURN (' . implode(' ', $items) . ')'; } if (!empty($criteria)) { + $modseq = stripos($criteria, 'MODSEQ') !== false; $params .= ($params ? ' ' : '') . $criteria; } else { @@ -2054,20 +2110,27 @@ class rcube_imap_generic if ($code == self::ERROR_OK) { // remove prefix... - $response = substr($response, stripos($response, + $response = substr($response, stripos($response, $esearch ? '* ESEARCH' : '* SEARCH') + ($esearch ? 10 : 9)); // ...and unilateral untagged server responses if ($pos = strpos($response, '*')) { $response = rtrim(substr($response, 0, $pos)); } + // remove MODSEQ response + if ($modseq) { + if (preg_match('/\(MODSEQ ([0-9]+)\)$/', $response, $m)) { + $response = substr($response, 0, -strlen($m[0])); + } + } + if ($esearch) { // Skip prefix: ... (TAG "A285") UID ... $this->tokenizeResponse($response, $return_uid ? 2 : 1); $result = array(); for ($i=0; $i<count($items); $i++) { - // If the SEARCH results in no matches, the server MUST NOT + // If the SEARCH returns no matches, the server MUST NOT // include the item result option in the ESEARCH response if ($ret = $this->tokenizeResponse($response, 2)) { list ($name, $value) = $ret; @@ -2116,7 +2179,6 @@ class rcube_imap_generic * * @return array List of mailboxes or hash of options if $status_opts argument * is non-empty. - * @access public */ function listMailboxes($ref, $mailbox, $status_opts=array(), $select_opts=array()) { @@ -2132,7 +2194,6 @@ class rcube_imap_generic * * @return array List of mailboxes or hash of options if $status_opts argument * is non-empty. - * @access public */ function listSubscribed($ref, $mailbox, $status_opts=array()) { @@ -2152,7 +2213,6 @@ class rcube_imap_generic * * @return array List of mailboxes or hash of options if $status_ops argument * is non-empty. - * @access private */ private function _listMailboxes($ref, $mailbox, $subscribed=false, $status_opts=array(), $select_opts=array()) @@ -2182,12 +2242,29 @@ class rcube_imap_generic list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args); if ($code == self::ERROR_OK) { - $folders = array(); - while ($this->tokenizeResponse($response, 1) == '*') { - $cmd = strtoupper($this->tokenizeResponse($response, 1)); + $folders = array(); + $last = 0; + $pos = 0; + $response .= "\r\n"; + + while ($pos = strpos($response, "\r\n", $pos+1)) { + // literal string, not real end-of-command-line + if ($response[$pos-1] == '}') { + continue; + } + + $line = substr($response, $last, $pos - $last); + $last = $pos + 2; + + if (!preg_match('/^\* (LIST|LSUB|STATUS) /i', $line, $m)) { + continue; + } + $cmd = strtoupper($m[1]); + $line = substr($line, strlen($m[0])); + // * LIST (<options>) <delimiter> <mailbox> if ($cmd == 'LIST' || $cmd == 'LSUB') { - list($opts, $delim, $mailbox) = $this->tokenizeResponse($response, 3); + list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3); // Add to result array if (!$lstatus) { @@ -2198,31 +2275,21 @@ class rcube_imap_generic } // Add to options array - if (!empty($opts)) { - if (empty($this->data['LIST'][$mailbox])) - $this->data['LIST'][$mailbox] = $opts; - else - $this->data['LIST'][$mailbox] = array_unique(array_merge( - $this->data['LIST'][$mailbox], $opts)); - } + if (empty($this->data['LIST'][$mailbox])) + $this->data['LIST'][$mailbox] = $opts; + else if (!empty($opts)) + $this->data['LIST'][$mailbox] = array_unique(array_merge( + $this->data['LIST'][$mailbox], $opts)); } // * STATUS <mailbox> (<result>) else if ($cmd == 'STATUS') { - list($mailbox, $status) = $this->tokenizeResponse($response, 2); + list($mailbox, $status) = $this->tokenizeResponse($line, 2); for ($i=0, $len=count($status); $i<$len; $i += 2) { list($name, $value) = $this->tokenizeResponse($status, 2); $folders[$mailbox][$name] = $value; } } - // other untagged response line, skip it - else { - $response = ltrim($response); - if (($position = strpos($response, "\n")) !== false) - $response = substr($response, $position+1); - else - $response = ''; - } } return $folders; @@ -2231,7 +2298,7 @@ class rcube_imap_generic return false; } - function fetchMIMEHeaders($mailbox, $id, $parts, $mime=true) + function fetchMIMEHeaders($mailbox, $uid, $parts, $mime=true) { if (!$this->select($mailbox)) { return false; @@ -2240,16 +2307,15 @@ class rcube_imap_generic $result = false; $parts = (array) $parts; $key = $this->nextTag(); - $peeks = ''; - $idx = 0; + $peeks = array(); $type = $mime ? 'MIME' : 'HEADER'; // format request - foreach($parts as $part) { + foreach ($parts as $part) { $peeks[] = "BODY.PEEK[$part.$type]"; } - $request = "$key FETCH $id (" . implode(' ', $peeks) . ')'; + $request = "$key UID FETCH $uid (" . implode(' ', $peeks) . ')'; // send request if (!$this->putLine($request)) { @@ -2259,13 +2325,25 @@ class rcube_imap_generic do { $line = $this->readLine(1024); - $line = $this->multLine($line); - if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { - $idx = $matches[1]; - $result[$idx] = preg_replace('/^(\* '.$id.' FETCH \()?\s*BODY\['.$idx.'\.'.$type.'\]\s+/', '', $line); - $result[$idx] = trim($result[$idx], '"'); - $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B"); + if (preg_match('/^\* [0-9]+ FETCH [0-9UID( ]+BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { + $idx = $matches[1]; + $headers = ''; + + // get complete entry + if (preg_match('/\{([0-9]+)\}\r\n$/', $line, $m)) { + $bytes = $m[1]; + $out = ''; + + while (strlen($out) < $bytes) { + $out = $this->readBytes($bytes); + if ($out === null) + break; + $headers .= $out; + } + } + + $result[$idx] = trim($headers); } } while (!$this->startsWith($line, $key, true)); @@ -2322,8 +2400,10 @@ class rcube_imap_generic $len = strlen($line); $result = false; + if ($a[2] != 'FETCH') { + } // handle empty "* X FETCH ()" response - if ($line[$len-1] == ')' && $line[$len-2] != '(') { + else if ($line[$len-1] == ')' && $line[$len-2] != '(') { // one line response, get everything between first and last quotes if (substr($line, -4, 3) == 'NIL') { // NIL response @@ -2442,8 +2522,18 @@ class rcube_imap_generic return ($result == self::ERROR_OK); } + /** + * Handler for IMAP APPEND command + * + * @param string $mailbox Mailbox name + * @param string $message Message content + * + * @return string|bool On success APPENDUID response (if available) or True, False on failure + */ function append($mailbox, &$message) { + unset($this->data['APPENDUID']); + if (!$mailbox) { return false; } @@ -2482,7 +2572,12 @@ class rcube_imap_generic // Clear internal status cache unset($this->data['STATUS:'.$mailbox]); - return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); + 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"); @@ -2491,8 +2586,19 @@ class rcube_imap_generic return false; } + /** + * Handler for IMAP APPEND command. + * + * @param string $mailbox Mailbox name + * @param string $path Path to the file with message body + * @param string $headers Message headers + * + * @return string|bool On success APPENDUID response (if available) or True, False on failure + */ function appendFromFile($mailbox, $path, $headers=null) { + unset($this->data['APPENDUID']); + if (!$mailbox) { return false; } @@ -2559,7 +2665,12 @@ class rcube_imap_generic // Clear internal status cache unset($this->data['STATUS:'.$mailbox]); - return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK); + 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"); @@ -2568,33 +2679,6 @@ class rcube_imap_generic return false; } - function fetchStructureString($mailbox, $id, $is_uid=false) - { - if (!$this->select($mailbox)) { - return false; - } - - $key = $this->nextTag(); - $result = false; - $command = $key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)"; - - if ($this->putLine($command)) { - do { - $line = $this->readLine(5000); - $line = $this->multLine($line, true); - if (!preg_match("/^$key /", $line)) - $result .= $line; - } while (!$this->startsWith($line, $key, true, true)); - - $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1)); - } - else { - $this->setError(self::ERROR_COMMAND, "Unable to send command: $command"); - } - - return $result; - } - function getQuota() { /* @@ -2658,7 +2742,6 @@ class rcube_imap_generic * * @return boolean True on success, False on failure * - * @access public * @since 0.5-beta */ function setACL($mailbox, $user, $acl) @@ -2682,7 +2765,6 @@ class rcube_imap_generic * * @return boolean True on success, False on failure * - * @access public * @since 0.5-beta */ function deleteACL($mailbox, $user) @@ -2700,7 +2782,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return array User-rights array on success, NULL on error - * @access public * @since 0.5-beta */ function getACL($mailbox) @@ -2741,7 +2822,6 @@ class rcube_imap_generic * @param string $user User name * * @return array List of user rights - * @access public * @since 0.5-beta */ function listRights($mailbox, $user) @@ -2773,7 +2853,6 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * * @return array MYRIGHTS response on success, NULL on error - * @access public * @since 0.5-beta */ function myRights($mailbox) @@ -2800,7 +2879,6 @@ class rcube_imap_generic * @param array $entries Entry-value array (use NULL value as NIL) * * @return boolean True on success, False on failure - * @access public * @since 0.5-beta */ function setMetadata($mailbox, $entries) @@ -2830,7 +2908,6 @@ class rcube_imap_generic * * @return boolean True on success, False on failure * - * @access public * @since 0.5-beta */ function deleteMetadata($mailbox, $entries) @@ -2860,7 +2937,6 @@ class rcube_imap_generic * * @return array GETMETADATA result on success, NULL on error * - * @access public * @since 0.5-beta */ function getMetadata($mailbox, $entries, $options=array()) @@ -2952,7 +3028,6 @@ class rcube_imap_generic * three elements: entry name, attribute name, value * * @return boolean True on success, False on failure - * @access public * @since 0.5-beta */ function setAnnotation($mailbox, $data) @@ -2984,7 +3059,6 @@ class rcube_imap_generic * * @return boolean True on success, False on failure * - * @access public * @since 0.5-beta */ function deleteAnnotation($mailbox, $data) @@ -3006,7 +3080,6 @@ class rcube_imap_generic * * @return array Annotations result on success, NULL on error * - * @access public * @since 0.5-beta */ function getAnnotation($mailbox, $entries, $attribs) @@ -3090,11 +3163,104 @@ class rcube_imap_generic return NULL; } + /** + * Returns BODYSTRUCTURE for the specified message. + * + * @param string $mailbox Folder name + * @param int $id Message sequence number or UID + * @param bool $is_uid True if $id is an UID + * + * @return array/bool Body structure array or False on error. + * @since 0.6 + */ + function getStructure($mailbox, $id, $is_uid = false) + { + $result = $this->fetch($mailbox, $id, $is_uid, array('BODYSTRUCTURE')); + if (is_array($result)) { + $result = array_shift($result); + return $result->bodystructure; + } + return false; + } + + /** + * Returns data of a message part according to specified structure. + * + * @param array $structure Message structure (getStructure() result) + * @param string $part Message part identifier + * + * @return array Part data as hash array (type, encoding, charset, size) + */ + static function getStructurePartData($structure, $part) + { + $part_a = self::getStructurePartArray($structure, $part); + $data = array(); + + if (empty($part_a)) { + return $data; + } + + // content-type + if (is_array($part_a[0])) { + $data['type'] = 'multipart'; + } + else { + $data['type'] = strtolower($part_a[0]); + + // encoding + $data['encoding'] = strtolower($part_a[5]); + + // charset + if (is_array($part_a[2])) { + while (list($key, $val) = each($part_a[2])) { + if (strcasecmp($val, 'charset') == 0) { + $data['charset'] = $part_a[2][$key+1]; + break; + } + } + } + } + + // size + $data['size'] = intval($part_a[6]); + + return $data; + } + + static function getStructurePartArray($a, $part) + { + if (!is_array($a)) { + return false; + } + if (strpos($part, '.') > 0) { + $original_part = $part; + $pos = strpos($part, '.'); + $rest = substr($original_part, $pos+1); + $part = substr($original_part, 0, $pos); + if ((strcasecmp($a[0], 'message') == 0) && (strcasecmp($a[1], 'rfc822') == 0)) { + $a = $a[8]; + } + return self::getStructurePartArray($a[$part-1], $rest); + } + else if ($part>0) { + if (!is_array($a[0]) && (strcasecmp($a[0], 'message') == 0) + && (strcasecmp($a[1], 'rfc822') == 0)) { + $a = $a[8]; + } + if (is_array($a[$part-1])) + return $a[$part-1]; + else + return $a; + } + else if (($part == 0) || (empty($part))) { + return $a; + } + } + /** * Creates next command identifier (tag) * * @return string Command identifier - * @access public * @since 0.5-beta */ function nextTag() @@ -3113,7 +3279,6 @@ class rcube_imap_generic * @param int $options Execution options * * @return mixed Response code or list of response code and data - * @access public * @since 0.5-beta */ function execute($command, $arguments=array(), $options=0) @@ -3124,7 +3289,9 @@ class rcube_imap_generic $response = $noresp ? null : ''; if (!empty($arguments)) { - $query .= ' ' . implode(' ', $arguments); + foreach ($arguments as $arg) { + $query .= ' ' . self::r_implode($arg); + } } // Send command @@ -3171,7 +3338,6 @@ class rcube_imap_generic * @param int $num Number of tokens to return * * @return mixed Tokens array or string if $num=1 - * @access public * @since 0.5-beta */ static function tokenizeResponse(&$str, $num=0) @@ -3192,7 +3358,7 @@ class rcube_imap_generic if (!is_numeric(($bytes = substr($str, 1, $epos - 1)))) { // error } - $result[] = substr($str, $epos + 3, $bytes); + $result[] = $bytes ? substr($str, $epos + 3, $bytes) : ''; // Advance the string $str = substr($str, $epos + 3 + $bytes); break; @@ -3221,28 +3387,25 @@ class rcube_imap_generic // Parenthesized list case '(': + case '[': $str = substr($str, 1); $result[] = self::tokenizeResponse($str); break; case ')': + case ']': $str = substr($str, 1); return $result; break; // String atom, number, NIL, *, % default: - // empty or one character - if ($str === '') { + // empty string + if ($str === '' || $str === null) { break 2; } - if (strlen($str) < 2) { - $result[] = $str; - $str = ''; - break; - } - // excluded chars: SP, CTL, ) - if (preg_match('/^([^\x00-\x20\x29\x7F]+)/', $str, $m)) { + // excluded chars: SP, CTL, ), [, ] + if (preg_match('/^([^\x00-\x20\x29\x5B\x5D\x7F]+)/', $str, $m)) { $result[] = $m[1] == 'NIL' ? NULL : $m[1]; $str = substr($str, strlen($m[1])); } @@ -3253,6 +3416,23 @@ class rcube_imap_generic return $num == 1 ? $result[0] : $result; } + static function r_implode($element) + { + $string = ''; + + if (is_array($element)) { + reset($element); + while (list($key, $value) = each($element)) { + $string .= ' ' . self::r_implode($value); + } + } + else { + return $element; + } + + return '(' . trim($string) . ')'; + } + private function _xor($string, $string2) { $result = ''; @@ -3346,7 +3526,6 @@ class rcube_imap_generic * * @param boolean $debug New value for the debugging flag. * - * @access public * @since 0.5-stable */ function setDebug($debug, $handler = null) @@ -3360,7 +3539,6 @@ class rcube_imap_generic * * @param string $message Debug mesage text. * - * @access private * @since 0.5-stable */ private function debug($message) diff --git a/program/include/rcube_json_output.php b/program/include/rcube_json_output.php index 60b90ec..6801a40 100644 --- a/program/include/rcube_json_output.php +++ b/program/include/rcube_json_output.php @@ -16,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_json_output.php 5037 2011-08-09 18:40:42Z alec $ + $Id: rcube_json_output.php 5227 2011-09-16 17:54:07Z thomasb $ */ diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 5db60c5..0cd179b 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -17,7 +17,7 @@ | Aleksander Machniak <machniak@kolabsys.com> | +-----------------------------------------------------------------------+ - $Id: rcube_ldap.php 5261 2011-09-21 12:22:40Z alec $ + $Id: rcube_ldap.php 5541 2011-12-04 17:05:42Z thomasb $ */ @@ -53,8 +53,8 @@ class rcube_ldap extends rcube_addressbook private $base_dn = ''; private $groups_base_dn = ''; - private $group_cache = array(); - private $group_members = array(); + private $group_url = null; + private $cache; private $vlv_active = false; private $vlv_count = 0; @@ -72,6 +72,9 @@ class rcube_ldap extends rcube_addressbook { $this->prop = $p; + if (isset($p['searchonly'])) + $this->searchonly = $p['searchonly']; + // check if groups are configured if (is_array($p['groups']) && count($p['groups'])) { $this->groups = true; @@ -80,6 +83,11 @@ class rcube_ldap extends rcube_addressbook $this->prop['member_attr'] = strtolower($p['groups']['member_attr']); else if (empty($p['member_attr'])) $this->prop['member_attr'] = 'member'; + // set default name attribute to cn + if (empty($this->prop['groups']['name_attr'])) + $this->prop['groups']['name_attr'] = 'cn'; + if (empty($this->prop['groups']['scope'])) + $this->prop['groups']['scope'] = 'sub'; } // fieldmap property is given @@ -125,6 +133,10 @@ class rcube_ldap extends rcube_addressbook $this->debug = $debug; $this->mail_domain = $mail_domain; + // initialize cache + $rcmail = rcmail::get_instance(); + $this->cache = $rcmail->get_cache('LDAP.' . asciiwords($this->prop['name']), 'db', 600); + $this->_connect(); } @@ -153,12 +165,14 @@ class rcube_ldap extends rcube_addressbook foreach ($this->prop['hosts'] as $host) { - $host = idn_to_ascii(rcube_parse_host($host)); - $this->_debug("C: Connect [$host".($this->prop['port'] ? ':'.$this->prop['port'] : '')."]"); + $host = idn_to_ascii(rcube_parse_host($host)); + $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); + + $this->_debug("C: Connect [$hostname]"); if ($lc = @ldap_connect($host, $this->prop['port'])) { - if ($this->prop['use_tls']===true) + if ($this->prop['use_tls'] === true) if (!ldap_start_tls($lc)) continue; @@ -167,90 +181,117 @@ class rcube_ldap extends rcube_addressbook ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']); $this->prop['host'] = $host; $this->conn = $lc; + + if (isset($this->prop['referrals'])) + ldap_set_option($lc, LDAP_OPT_REFERRALS, $this->prop['referrals']); break; } $this->_debug("S: NOT OK"); } - if (is_resource($this->conn)) - { - $this->ready = true; + // See if the directory is writeable. + if ($this->prop['writable']) { + $this->readonly = false; + } - $bind_pass = $this->prop['bind_pass']; - $bind_user = $this->prop['bind_user']; - $bind_dn = $this->prop['bind_dn']; + if (!is_resource($this->conn)) { + raise_error(array('code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); - $this->base_dn = $this->prop['base_dn']; - $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? - $this->prop['groups']['base_dn'] : $this->base_dn; + return false; + } - // User specific access, generate the proper values to use. - if ($this->prop['user_specific']) { - // No password set, use the session password - if (empty($bind_pass)) { - $bind_pass = $RCMAIL->decrypt($_SESSION['password']); - } + $bind_pass = $this->prop['bind_pass']; + $bind_user = $this->prop['bind_user']; + $bind_dn = $this->prop['bind_dn']; - // Get the pieces needed for variable replacement. - if ($fu = $RCMAIL->user->get_username()) - list($u, $d) = explode('@', $fu); - else - $d = $this->mail_domain; + $this->base_dn = $this->prop['base_dn']; + $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? + $this->prop['groups']['base_dn'] : $this->base_dn; - $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string + // User specific access, generate the proper values to use. + if ($this->prop['user_specific']) { + // No password set, use the session password + if (empty($bind_pass)) { + $bind_pass = $RCMAIL->decrypt($_SESSION['password']); + } - $replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); + // Get the pieces needed for variable replacement. + if ($fu = $RCMAIL->user->get_username()) + list($u, $d) = explode('@', $fu); + else + $d = $this->mail_domain; - if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { - // 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); + $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string - $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); + $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); - $res = @ldap_search($this->conn, $this->prop['search_base_dn'], $this->prop['search_filter'], array('uid')); - if ($res && ($entry = ldap_first_entry($this->conn, $res))) { - $bind_dn = ldap_get_dn($this->conn, $entry); + if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { + 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']); + } - $this->_debug("S: search returned dn: $bind_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); - if ($bind_dn) { - $dn = ldap_explode_dn($bind_dn, 1); - $replaces['%dn'] = $dn[0]; - } + $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); + + $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]; } } - // Replace the bind_dn and base_dn variables. - $bind_dn = strtr($bind_dn, $replaces); - $this->base_dn = strtr($this->base_dn, $replaces); - $this->groups_base_dn = strtr($this->groups_base_dn, $replaces); + else { + $this->_debug("S: ".ldap_error($this->conn)); + } - if (empty($bind_user)) { - $bind_user = $u; + // DN not found + if (empty($replaces['%dn'])) { + if (!empty($this->prop['search_dn_default'])) + $replaces['%dn'] = $this->prop['search_dn_default']; + else { + raise_error(array( + 'code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "DN not found using LDAP search."), true); + return false; + } } } - if (!empty($bind_pass)) { - if (!empty($bind_dn)) { - $this->ready = $this->_bind($bind_dn, $bind_pass); - } - else if (!empty($this->prop['auth_cid'])) { - $this->ready = $this->_sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); - } - else { - $this->ready = $this->_sasl_bind($bind_user, $bind_pass); - } + // Replace the bind_dn and base_dn variables. + $bind_dn = strtr($bind_dn, $replaces); + $this->base_dn = strtr($this->base_dn, $replaces); + $this->groups_base_dn = strtr($this->groups_base_dn, $replaces); + + if (empty($bind_user)) { + $bind_user = $u; } } - else - raise_error(array('code' => 100, 'type' => 'ldap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not connect to any LDAP server, last tried $host:{$this->prop[port]}"), true); - // See if the directory is writeable. - if ($this->prop['writable']) { - $this->readonly = false; - } // end if + if (empty($bind_pass)) { + $this->ready = true; + } + else { + if (!empty($bind_dn)) { + $this->ready = $this->bind($bind_dn, $bind_pass); + } + else if (!empty($this->prop['auth_cid'])) { + $this->ready = $this->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); + } + else { + $this->ready = $this->sasl_bind($bind_user, $bind_pass); + } + } + + return $this->ready; } @@ -263,7 +304,7 @@ class rcube_ldap extends rcube_addressbook * * @return boolean True on success, False on error */ - private function _sasl_bind($authc, $pass, $authz=null) + public function sasl_bind($authc, $pass, $authz=null) { if (!$this->conn) { return false; @@ -314,7 +355,7 @@ class rcube_ldap extends rcube_addressbook * * @return boolean True on success, False on error */ - private function _bind($dn, $pass) + public function bind($dn, $pass) { if (!$this->conn) { return false; @@ -429,59 +470,219 @@ class rcube_ldap extends rcube_addressbook */ function list_records($cols=null, $subset=0) { - // add general filter to query - if (!empty($this->prop['filter']) && empty($this->filter)) + if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id) { - $filter = $this->prop['filter']; - $this->set_search_set($filter); + $this->result = new rcube_result_set(0); + $this->result->searchonly = true; + return $this->result; } - // exec LDAP search if no result resource is stored - if ($this->conn && !$this->ldap_result) - $this->_exec_search(); + // fetch group members recursively + if ($this->group_id && $this->group_data['dn']) + { + $entries = $this->list_group_members($this->group_data['dn']); - // count contacts for this user - $this->result = $this->count(); + // make list of entries unique and sort it + $seen = array(); + foreach ($entries as $i => $rec) { + if ($seen[$rec['dn']]++) + unset($entries[$i]); + } + usort($entries, array($this, '_entry_sort_cmp')); - // we have a search result resource - if ($this->ldap_result && $this->result->count > 0) + $entries['count'] = count($entries); + $this->result = new rcube_result_set($entries['count'], ($this->list_page-1) * $this->page_size); + } + else { - // sorting still on the ldap server - if ($this->sort_col && $this->prop['scope'] !== 'base' && !$this->vlv_active) - ldap_sort($this->conn, $this->ldap_result, $this->sort_col); + // add general filter to query + if (!empty($this->prop['filter']) && empty($this->filter)) + $this->set_search_set($this->prop['filter']); - // start and end of the page - $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; + // exec LDAP search if no result resource is stored + if ($this->conn && !$this->ldap_result) + $this->_exec_search(); - // get all entries from the ldap server - $entries = ldap_get_entries($this->conn, $this->ldap_result); + // count contacts for this user + $this->result = $this->count(); - // filtering for group members - if ($this->groups and $this->group_id) + // we have a search result resource + if ($this->ldap_result && $this->result->count > 0) { - $count = 0; - $members = array(); - foreach ($entries as $entry) - { - if ($this->group_members[self::dn_encode($entry['dn'])]) - { - $members[] = $entry; - $count++; - } + // sorting still on the ldap server + 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 = ldap_get_entries($this->conn, $this->ldap_result); + } + + } // end else + + // start and end of the page + $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; + + // filter entries for this page + for ($i = $start_row; $i < min($entries['count'], $last_row); $i++) + $this->result->add($this->_ldap2result($entries[$i])); + + return $this->result; + } + + /** + * Get all members of the given group + * + * @param string Group DN + * @param array Group entries (if called recursively) + * @return array Accumulated group members + */ + function list_group_members($dn, $count = false, $entries = null) + { + $group_members = array(); + + // fetch group object + if (empty($entries)) { + $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++) + { + $entry = $entries[$i]; + + if (empty($entry['objectclass'])) + continue; + + foreach ((array)$entry['objectclass'] as $objectclass) + { + switch (strtolower($objectclass)) { + 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; } - $entries = $members; - $entries['count'] = $count; - $this->result->count = $count; } + + if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) + break; + } + + return array_filter($group_members); + } - // filter entries for this page - for ($i = $start_row; $i < min($entries['count'], $last_row); $i++) - $this->result->add($this->_ldap2result($entries[$i])); + /** + * Fetch members of the given group entry from server + * + * @param string Group DN + * @param array Group entry + * @param string Member attribute to use + * @return array Accumulated group members + */ + private function _list_group_members($dn, $entry, $attr, $count) + { + // 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])) + return $group_members; + + // read these attributes for all members + $attrib = $count ? array('dn') : array_values($this->fieldmap); + $attrib[] = 'objectClass'; + $attrib[] = 'member'; + $attrib[] = 'uniqueMember'; + $attrib[] = 'memberURL'; + + for ($i=0; $i < $entry[$attr]['count']; $i++) + { + $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(); + } + + // for nested groups, call recursively + $nested_group_members = $this->list_group_members($entry[$attr][$i], $count, $members); + + unset($members['count']); + $group_members = array_merge($group_members, array_filter($members), $nested_group_members); } - return $this->result; + + return $group_members; + } + + /** + * List members of group class groupOfUrls + * + * @param string Group DN + * @param array Group entry + * @param boolean True if only used for counting + * @return array Accumulated group members + */ + private function _list_group_memberurl($dn, $entry, $count) + { + $group_members = array(); + + 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]; + $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]; + } + } + + return $group_members; + } + + /** + * Callback for sorting entries + */ + function _entry_sort_cmp($a, $b) + { + return strcmp($a[$this->sort_col][0], $b[$this->sort_col][0]); } @@ -490,15 +691,20 @@ class rcube_ldap extends rcube_addressbook * * @param mixed $fields The field name of array of field names to search in * @param mixed $value Search value (or array of values when $fields is array) - * @param boolean $strict True for strict, False for partial (fuzzy) matching + * @param int $mode Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) * @param boolean $select True if results are requested, False if count only * @param boolean $nocount (Not used) * @param array $required List of fields that cannot be empty * * @return array Indexed list of contact records and 'count' value */ - function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) + function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()) { + $mode = intval($mode); + // special treatment for ID-based search if ($fields == 'ID' || $fields == $this->primary_key) { @@ -515,9 +721,70 @@ class rcube_ldap extends rcube_addressbook return $result; } + // use VLV pseudo-search for autocompletion + if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == 'email,name') + { + // 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); + + 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); + $entries = ldap_get_entries($this->conn, $this->ldap_result); + + for ($i = 0; $i < $entries['count']; $i++) { + $rec = $this->_ldap2result($entries[$i]); + foreach (array('email', 'name') as $f) { + $val = mb_strtolower($rec[$f]); + switch ($mode) { + case 1: + $got = ($val == $search); + break; + case 2: + $got = ($search == substr($val, 0, strlen($search))); + break; + default: + $got = (strpos($val, $search) !== false); + break; + } + + if ($got) { + $this->result->add($rec); + $this->result->count++; + break; + } + } + } + + return $this->result; + } + // use AND operator for advanced searches $filter = is_array($value) ? '(&' : '(|'; - $wc = !$strict && $this->prop['fuzzy_search'] ? '*' : ''; + // set wildcards + $wp = $ws = ''; + if (!empty($this->prop['fuzzy_search']) && $mode != 1) { + $ws = '*'; + if (!$mode) { + $wp = '*'; + } + } if ($fields == '*') { @@ -531,7 +798,7 @@ class rcube_ldap extends rcube_addressbook if (is_array($this->prop['search_fields'])) { foreach ($this->prop['search_fields'] as $field) { - $filter .= "($field=$wc" . $this->_quote_string($value) . "$wc)"; + $filter .= "($field=$wp" . $this->_quote_string($value) . "$ws)"; } } } @@ -540,7 +807,7 @@ class rcube_ldap extends rcube_addressbook foreach ((array)$fields as $idx => $field) { $val = is_array($value) ? $value[$idx] : $value; if ($f = $this->_map_field($field)) { - $filter .= "($f=$wc" . $this->_quote_string($val) . "$wc)"; + $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; } } } @@ -585,18 +852,21 @@ class rcube_ldap extends rcube_addressbook $count = 0; if ($this->conn && $this->ldap_result) { $count = $this->vlv_active ? $this->vlv_count : ldap_count_entries($this->conn, $this->ldap_result); - } // end if - elseif ($this->conn) { + } + else if ($this->group_id && $this->group_data['dn']) { + $count = count($this->list_group_members($this->group_data['dn'], true)); + } + 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']; - } // end if + } $this->_exec_search(true); if ($this->ldap_result) { $count = ldap_count_entries($this->conn, $this->ldap_result); - } // end if - } // end else + } + } return new rcube_result_set($count, ($this->list_page-1) * $this->page_size); } @@ -658,19 +928,49 @@ class rcube_ldap extends rcube_addressbook * If input not valid, the message to display can be fetched using get_error() * * @param array Assoziative array with data to save - * + * @param boolean Try to fix/complete record automatically * @return boolean True if input is valid, False if not. */ - public function validate($save_data) + public function validate(&$save_data, $autofix = false) { // check for name input if (empty($save_data['name'])) { - $this->set_error('warning', 'nonamewarning'); + $this->set_error(self::ERROR_VALIDATE, 'nonamewarning'); + return false; + } + + // Verify that the required fields are set. + $missing = null; + $ldap_data = $this->_map_data($save_data); + foreach ($this->prop['required_fields'] as $fld) { + if (!isset($ldap_data[$fld])) { + $missing[$fld] = 1; + } + } + + if ($missing) { + // try to complete record automatically + if ($autofix) { + $reverse_map = array_flip($this->fieldmap); + $name_parts = preg_split('/[\s,.]+/', $save_data['name']); + if ($missing['sn']) { + $sn_field = $reverse_map['sn']; + $save_data[$sn_field] = array_pop ($name_parts); + } + if ($missing[($fn_field = $this->fieldmap['firstname'])]) { + $save_data['firstname'] = array_shift($name_parts); + } + + return $this->validate($save_data, false); + } + + // TODO: generate message saying which fields are missing + $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); return false; } // validate e-mail addresses - return parent::validate($save_data); + return parent::validate($save_data, $autofix); } @@ -684,17 +984,8 @@ class rcube_ldap extends rcube_addressbook function insert($save_cols) { // Map out the column names to their LDAP ones to build the new entry. - $newentry = array(); + $newentry = $this->_map_data($save_cols); $newentry['objectClass'] = $this->prop['LDAP_Object_Classes']; - foreach ($this->fieldmap as $col => $fld) { - $val = $save_cols[$col]; - if (is_array($val)) - $val = array_filter($val); // remove empty entries - if ($fld && $val) { - // The field does exist, add it to the entry. - $newentry[$fld] = $val; - } // end if - } // end foreach // Verify that the required fields are set. $missing = null; @@ -707,7 +998,7 @@ class rcube_ldap extends rcube_addressbook // abort process if requiered fields are missing // TODO: generate message saying which fields are missing if ($missing) { - $this->set_error(self::ERROR_INCOMPLETE, 'formincomplete'); + $this->set_error(self::ERROR_VALIDATE, 'formincomplete'); return false; } @@ -728,7 +1019,7 @@ class rcube_ldap extends rcube_addressbook $dn = self::dn_encode($dn); // add new contact to the selected group - if ($this->groups) + if ($this->group_id) $this->add_to_group($this->group_id, $dn); return $dn; @@ -753,39 +1044,33 @@ class rcube_ldap extends rcube_addressbook $replacedata = array(); $deletedata = array(); - // flatten composite fields in $record - if (is_array($record['address'])) { - foreach ($record['address'] as $i => $struct) { - foreach ($struct as $col => $val) { - $record[$col][$i] = $val; - } - } - } + $ldap_data = $this->_map_data($save_cols); + $old_data = $record['_raw_attrib']; foreach ($this->fieldmap as $col => $fld) { - $val = $save_cols[$col]; + $val = $ldap_data[$fld]; if ($fld) { // remove empty array values if (is_array($val)) $val = array_filter($val); // The field does exist compare it to the ldap record. - if ($record[$col] != $val) { + if ($old_data[$fld] != $val) { // Changed, but find out how. - if (!isset($record[$col])) { + if (!isset($old_data[$fld])) { // Field was not set prior, need to add it. $newdata[$fld] = $val; - } // end if - elseif ($val == '') { + } + else if ($val == '') { // Field supplied is empty, verify that it is not required. if (!in_array($fld, $this->prop['required_fields'])) { // It is not, safe to clear. - $deletedata[$fld] = $record[$col]; - } // end if + $deletedata[$fld] = $old_data[$fld]; + } } // end elseif else { // The data was modified, save it out. $replacedata[$fld] = $val; - } // end else + } } // end if } // end if } // end foreach @@ -917,14 +1202,14 @@ class rcube_ldap extends rcube_addressbook if ($this->ready) { $filter = $this->filter ? $this->filter : '(objectclass=*)'; - $function = $this->prop['scope'] == 'sub' ? 'ldap_search' : ($this->prop['scope'] == 'base' ? 'ldap_read' : 'ldap_list'); + $function = $this->_scope2func($this->prop['scope'], $ns_function); - $this->_debug("C: Search [$filter]"); + $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']) { + if (!$count && $function != 'ldap_read' && $this->prop['vlv'] && !$this->group_id) { // ...either reading numSubOrdinates attribute - if ($this->prop['numsub_filter'] && ($result_count = @$function($this->conn, $this->base_dn, $this->prop['numsub_filter'], array('numSubOrdinates'), 0, 0, 0))) { + 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]; @@ -933,21 +1218,20 @@ class rcube_ldap extends rcube_addressbook else // ...or by fetching all records dn and count them $this->vlv_count = $this->_exec_search(true); - $this->vlv_active = $this->_vlv_set_controls(); + $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'])) - { - $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); - if ($err = ldap_errno($this->conn)) - $this->_debug("S: Error: " .ldap_err2str($err)); - return true; + $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) + ) { + $entries_count = ldap_count_entries($this->conn, $this->ldap_result); + $this->_debug("S: $count_entries record(s)"); + + return $count ? $count_entries : true; } - else - { + else { $this->_debug("S: ".ldap_error($this->conn)); } } @@ -955,16 +1239,38 @@ class rcube_ldap extends rcube_addressbook 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() + 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)$this->prop['sort'])); - $vlv_ctrl = array('oid' => "2.16.840.1.113730.3.4.9", 'value' => $this->_vlv_ber_encode(($offset = ($this->list_page-1) * $this->page_size + 1), $this->page_size), 'iscritical' => true); + $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); - $this->_debug("C: set controls sort=" . join(' ', unpack('H'.(strlen($sort_ctrl['value'])*2), $sort_ctrl['value'])) . " ({$this->sort_col});" - . " vlv=" . join(' ', (unpack('H'.(strlen($vlv_ctrl['value'])*2), $vlv_ctrl['value']))) . " ($offset)"); + $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)); @@ -991,6 +1297,9 @@ class rcube_ldap extends rcube_addressbook for ($i=0; $i < $rec[$lf]['count']; $i++) { if (!($value = $rec[$lf][$i])) continue; + + $out['_raw_attrib'][$lf][$i] = $value; + if ($rf == 'email' && $this->mail_domain && !strpos($value, '@')) $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); else if (in_array($rf, array('street','zipcode','locality','country','region'))) @@ -1000,6 +1309,11 @@ class rcube_ldap extends rcube_addressbook else $out[$rf] = $value; } + + // Make sure name fields aren't arrays (#1488108) + if (is_array($out[$rf]) && in_array($rf, array('name', 'surname', 'firstname', 'middlename', 'nickname'))) { + $out[$rf] = $out['_raw_attrib'][$lf] = $out[$rf][0]; + } } return $out; @@ -1015,6 +1329,40 @@ class rcube_ldap extends rcube_addressbook } + /** + * Convert a record data set into LDAP field attributes + */ + private function _map_data($save_cols) + { + // flatten composite fields first + foreach ($this->coltypes as $col => $colprop) { + if (is_array($colprop['childs']) && ($values = $this->get_col_values($col, $save_cols, false))) { + foreach ($values as $subtype => $childs) { + $subtype = $subtype ? ':'.$subtype : ''; + foreach ($childs as $i => $child_values) { + foreach ((array)$child_values as $childcol => $value) { + $save_cols[$childcol.$subtype][$i] = $value; + } + } + } + } + } + + $ldap_data = array(); + foreach ($this->fieldmap as $col => $fld) { + $val = $save_cols[$col]; + if (is_array($val)) + $val = array_filter($val); // remove empty entries + if ($fld && $val) { + // The field does exist, add it to the entry. + $ldap_data[$fld] = $val; + } + } + + return $ldap_data; + } + + /** * Returns unified attribute name (resolving aliases) */ @@ -1042,6 +1390,18 @@ 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; + } + + /** * Quotes attribute value string * @@ -1075,22 +1435,17 @@ class rcube_ldap extends rcube_addressbook { if ($group_id) { - if (!$this->group_cache) - $this->list_groups(); - - $cache_members = $this->group_cache[$group_id]['members']; + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); - $members = array(); - for ($i=0; $i<$cache_members["count"]; $i++) - { - if (!empty($cache_members[$i])) - $members[self::dn_encode($cache_members[$i])] = 1; - } - $this->group_members = $members; $this->group_id = $group_id; + $this->group_data = $group_cache[$group_id]; } else + { $this->group_id = 0; + $this->group_data = null; + } } /** @@ -1104,12 +1459,49 @@ class rcube_ldap extends rcube_addressbook if (!$this->groups) return 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) { + $search = mb_strtolower($search); + foreach ($group_cache as $group) { + if (strpos(mb_strtolower($group['name']), $search) !== false) + $groups[] = $group; + } + } + else + $groups = $group_cache; + + return array_values($groups); + } + + /** + * Fetch groups from server + */ + private function _fetch_groups($vlv_page = 0) + { $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]; $this->_debug("C: Search [$filter][dn: $base_dn]"); - $res = @ldap_search($this->conn, $base_dn, $filter, array('cn', $this->prop['member_attr'])); + // use vlv to list groups + if ($this->prop['groups']['vlv']) { + $page_size = 200; + if (!$this->prop['groups']['sort']) + $this->prop['groups']['sort'] = $sort_attrs; + $vlv_active = $this->_vlv_set_controls($this->prop['groups'], $vlv_page+1, $page_size); + } + + $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)); @@ -1121,24 +1513,79 @@ class rcube_ldap extends rcube_addressbook $groups = array(); $group_sortnames = array(); - for ($i=0; $i<$ldap_data["count"]; $i++) + $group_count = $ldap_data["count"]; + for ($i=0; $i < $group_count; $i++) { - $group_name = $ldap_data[$i]['cn'][0]; - if (!$search || strstr(strtolower($group_name), strtolower($search))) - { - $group_id = self::dn_encode($group_name); - $groups[$group_id]['ID'] = $group_id; - $groups[$group_id]['name'] = $group_name; - $groups[$group_id]['members'] = $ldap_data[$i][$this->prop['member_attr']]; - $group_sortnames[] = strtolower($group_name); + $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'] = $ldap_data[$i]['dn']; + $groups[$group_id]['name'] = $group_name; + $groups[$group_id]['member_attr'] = $this->prop['member_attr']; + + // check objectClass attributes of group and act accordingly + for ($j=0; $j < $ldap_data[$i]['objectclass']['count']; $j++) { + switch (strtolower($ldap_data[$i]['objectclass'][$j])) { + case 'groupofnames': + case 'kolabgroupofnames': + $groups[$group_id]['member_attr'] = 'member'; + break; + + case 'groupofuniquenames': + case 'kolabgroupofuniquenames': + $groups[$group_id]['member_attr'] = 'uniqueMember'; + break; + } } + + // list email attributes of a group + 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($ldap_data[$i][$sort_attr][0]); } - array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups); - $this->group_cache = $groups; + + // recursive call can exit here + if ($vlv_page > 0) + return $groups; + + // call recursively until we have fetched all groups + 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']) + array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups); + + // cache this + $this->cache->set('groups', $groups); return $groups; } + /** + * Get group properties such as name and email address(es) + * + * @param string Group identifier + * @return array Group properties as hash array + */ + function get_group($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; + } + /** * Create a contact group with the given name * @@ -1147,17 +1594,16 @@ class rcube_ldap extends rcube_addressbook */ function create_group($group_name) { - if (!$this->group_cache) - $this->list_groups(); - $base_dn = $this->groups_base_dn; $new_dn = "cn=$group_name,$base_dn"; $new_gid = self::dn_encode($group_name); + $member_attr = $this->prop['groups']['member_attr']; + $name_attr = $this->prop['groups']['name_attr']; $new_entry = array( 'objectClass' => $this->prop['groups']['object_classes'], - 'cn' => $group_name, - $this->prop['member_attr'] => '', + $name_attr => $group_name, + $member_attr => '', ); $this->_debug("C: Add [dn: $new_dn]: ".print_r($new_entry, true)); @@ -1171,6 +1617,7 @@ class rcube_ldap extends rcube_addressbook } $this->_debug("S: OK"); + $this->cache->remove('groups'); return array('id' => $new_gid, 'name' => $group_name); } @@ -1183,11 +1630,11 @@ class rcube_ldap extends rcube_addressbook */ function delete_group($group_id) { - if (!$this->group_cache) - $this->list_groups(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); $base_dn = $this->groups_base_dn; - $group_name = $this->group_cache[$group_id]['name']; + $group_name = $group_cache[$group_id]['name']; $del_dn = "cn=$group_name,$base_dn"; $this->_debug("C: Delete [dn: $del_dn]"); @@ -1201,6 +1648,7 @@ class rcube_ldap extends rcube_addressbook } $this->_debug("S: OK"); + $this->cache->remove('groups'); return true; } @@ -1215,11 +1663,11 @@ class rcube_ldap extends rcube_addressbook */ function rename_group($group_id, $new_name, &$new_gid) { - if (!$this->group_cache) - $this->list_groups(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); $base_dn = $this->groups_base_dn; - $group_name = $this->group_cache[$group_id]['name']; + $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); @@ -1235,6 +1683,7 @@ class rcube_ldap extends rcube_addressbook } $this->_debug("S: OK"); + $this->cache->remove('groups'); return $new_name; } @@ -1248,16 +1697,19 @@ class rcube_ldap extends rcube_addressbook */ function add_to_group($group_id, $contact_ids) { - if (!$this->group_cache) - $this->list_groups(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); + + if (!is_array($contact_ids)) + $contact_ids = explode(',', $contact_ids); $base_dn = $this->groups_base_dn; - $group_name = $this->group_cache[$group_id]['name']; - $member_attr = $this->prop['member_attr']; + $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 (explode(",", $contact_ids) as $id) + foreach ($contact_ids as $id) $new_attrs[$member_attr][] = self::dn_decode($id); $this->_debug("C: Add [dn: $group_dn]: ".print_r($new_attrs, true)); @@ -1271,6 +1723,7 @@ class rcube_ldap extends rcube_addressbook } $this->_debug("S: OK"); + $this->cache->remove('groups'); return count($new_attrs['member']); } @@ -1284,12 +1737,12 @@ class rcube_ldap extends rcube_addressbook */ function remove_from_group($group_id, $contact_ids) { - if (!$this->group_cache) - $this->list_groups(); + if (($group_cache = $this->cache->get('groups')) === null) + $group_cache = $this->_fetch_groups(); $base_dn = $this->groups_base_dn; - $group_name = $this->group_cache[$group_id]['name']; - $member_attr = $this->prop['member_attr']; + $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(); @@ -1307,6 +1760,7 @@ class rcube_ldap extends rcube_addressbook } $this->_debug("S: OK"); + $this->cache->remove('groups'); return count($del_attrs['member']); } @@ -1326,12 +1780,16 @@ class rcube_ldap extends rcube_addressbook $base_dn = $this->groups_base_dn; $contact_dn = self::dn_decode($contact_id); + $name_attr = $this->prop['groups']['name_attr']; $member_attr = $this->prop['member_attr']; - $filter = strtr("($member_attr=$contact_dn)", array('\\' => '\\\\')); + $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('\\' => '\\\\')); $this->_debug("C: Search [$filter][dn: $base_dn]"); - $res = @ldap_search($this->conn, $base_dn, $filter, array('cn')); + $res = @ldap_search($this->conn, $base_dn, $filter, array($name_attr)); if ($res === false) { $this->_debug("S: ".ldap_error($this->conn)); @@ -1343,7 +1801,7 @@ class rcube_ldap extends rcube_addressbook $groups = array(); for ($i=0; $i<$ldap_data["count"]; $i++) { - $group_name = $ldap_data[$i]['cn'][0]; + $group_name = $ldap_data[$i][$name_attr][0]; $group_id = self::dn_encode($group_name); $groups[$group_id] = $group_id; } @@ -1358,17 +1816,23 @@ class rcube_ldap extends rcube_addressbook * @param integer Records per page * @return string BER encoded option value */ - private function _vlv_ber_encode($offset, $rpp) + 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 - # 20 = type integer (in two's complement form) with 2 bytes following (beforeCount): 01 00 (ie 0) - # 20 = type integer (in two's complement form) with 2 bytes following (afterCount): 01 18 (ie 25-1=24) + # 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 - # 20 = type integer with 2 bytes following (offset): 01 01 (ie 1) - # 20 = type integer with 2 bytes following (contentCount): 01 00 + # 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 @@ -1378,20 +1842,29 @@ class rcube_ldap extends rcube_addressbook # 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 - # 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; + $ber_val = self::_ber_encode_int($offset); // returns encoded integer value in hex format - // now compute length over $str - $str = self::_ber_addseq($str, 'a0'); + // 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 = sprintf("0201000201%02x", min(255, $rpp)-1) . $str; + $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'); diff --git a/program/include/rcube_mdb2.php b/program/include/rcube_mdb2.php index e44826e..f25acef 100644 --- a/program/include/rcube_mdb2.php +++ b/program/include/rcube_mdb2.php @@ -16,7 +16,7 @@ | Author: Lukas Kahwe Smith <smith@pooteeweet.org> | +-----------------------------------------------------------------------+ - $Id: rcube_mdb2.php 4810 2011-05-27 11:02:51Z alec $ + $Id: rcube_mdb2.php 5543 2011-12-05 07:24:36Z alec $ */ @@ -35,16 +35,16 @@ */ class rcube_mdb2 { - var $db_dsnw; // DSN for write operations - var $db_dsnr; // DSN for read operations - var $db_connected = false; // Already connected ? - var $db_mode = ''; // Connection mode - var $db_handle = 0; // Connection handle - var $db_error = false; - var $db_error_msg = ''; + public $db_dsnw; // DSN for write operations + public $db_dsnr; // DSN for read operations + public $db_connected = false; // Already connected ? + public $db_mode = ''; // Connection mode + public $db_handle = 0; // Connection handle + public $db_error = false; + public $db_error_msg = ''; private $debug_mode = false; - private $write_failure = false; + private $conn_failure = false; private $a_query_results = array('dummy'); private $last_res_id = 0; private $tables; @@ -58,7 +58,7 @@ class rcube_mdb2 */ function __construct($db_dsnw, $db_dsnr='', $pconn=false) { - if ($db_dsnr == '') + if (empty($db_dsnr)) $db_dsnr = $db_dsnw; $this->db_dsnw = $db_dsnw; @@ -91,6 +91,8 @@ class rcube_mdb2 $db_options['disable_smart_seqname'] = true; $db_options['seqname_format'] = '%s'; } + $this->db_error = false; + $this->db_error_msg = null; $dbh = MDB2::connect($dsn, $db_options); @@ -122,30 +124,40 @@ class rcube_mdb2 */ function db_connect($mode) { + // previous connection failed, don't attempt to connect again + if ($this->conn_failure) { + return; + } + + // no replication + if ($this->db_dsnw == $this->db_dsnr) { + $mode = 'w'; + } + // Already connected if ($this->db_connected) { - // connected to read-write db, current connection is ok - if ($this->db_mode == 'w' && !$this->write_failure) - return; - - // no replication, current connection is ok for read and write - if (empty($this->db_dsnr) || $this->db_dsnw == $this->db_dsnr) { - $this->db_mode = 'w'; + // connected to db with the same or "higher" mode + if ($this->db_mode == 'w' || $this->db_mode == $mode) { return; } - - // Same mode, current connection is ok - if ($this->db_mode == $mode) - return; } $dsn = ($mode == 'r') ? $this->db_dsnr : $this->db_dsnw; - $this->db_handle = $this->dsn_connect($dsn); + $this->db_handle = $this->dsn_connect($dsn); $this->db_connected = !PEAR::isError($this->db_handle); + // use write-master when read-only fails + if (!$this->db_connected && $mode == 'r') { + $mode = 'w'; + $this->db_handle = $this->dsn_connect($this->db_dsnw); + $this->db_connected = !PEAR::isError($this->db_handle); + } + if ($this->db_connected) - $this->db_mode = $mode; + $this->db_mode = $mode; + else + $this->conn_failure = true; } @@ -256,10 +268,6 @@ class rcube_mdb2 // Read or write ? $mode = (strtolower(substr(trim($query),0,6)) == 'select') ? 'r' : 'w'; - // don't event attempt to connect if previous write-operation failed - if ($this->write_failure && $mode == 'w') - return false; - $this->db_connect($mode); // check connection before proceeding @@ -284,7 +292,7 @@ class rcube_mdb2 raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, 'message' => $this->db_error_msg), true, false); - + $result = false; } else { @@ -293,10 +301,6 @@ class rcube_mdb2 } } - // remember that write-operation failed - if ($mode == 'w' && ($result === false || PEAR::isError($result))) - $this->write_failure = true; - // add result, even if it's an error return $this->_add_result($result); } @@ -447,7 +451,7 @@ class rcube_mdb2 if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) { return $result; } - + return null; } @@ -530,7 +534,7 @@ class rcube_mdb2 */ function now() { - switch($this->db_provider) { + switch ($this->db_provider) { case 'mssql': case 'sqlsrv': return "getdate()"; diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 667657b..05ae2b1 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_message.php 5261 2011-09-21 12:22:40Z alec $ + $Id: rcube_message.php 5514 2011-11-30 11:35:43Z alec $ */ @@ -48,7 +48,6 @@ class rcube_message public $uid = null; public $headers; - public $structure; public $parts = array(); public $mime_parts = array(); public $attachments = array(); @@ -77,7 +76,7 @@ class rcube_message $this->imap->get_all_headers = true; $this->uid = $uid; - $this->headers = $this->imap->get_headers($uid, NULL, true, true); + $this->headers = $this->imap->get_message($uid); if (!$this->headers) return; @@ -94,9 +93,9 @@ class rcube_message '_mbox' => $this->imap->get_mailbox_name(), '_uid' => $uid)) ); - if ($this->structure = $this->imap->get_structure($uid, $this->headers->body_structure)) { - $this->get_mime_numbers($this->structure); - $this->parse_structure($this->structure); + if (!empty($this->headers->structure)) { + $this->get_mime_numbers($this->headers->structure); + $this->parse_structure($this->headers->structure); } else { $this->body = $this->imap->get_body($uid); @@ -143,10 +142,10 @@ class rcube_message * @param string $mime_id Part MIME-ID * @return string URL or false if part does not exist */ - public function get_part_url($mime_id) + public function get_part_url($mime_id, $embed = false) { if ($this->mime_parts[$mime_id]) - return $this->opt['get_url'] . '&_part=' . $mime_id; + return $this->opt['get_url'] . '&_part=' . $mime_id . ($embed ? '&_embed=1' : ''); else return false; } @@ -299,8 +298,10 @@ class rcube_message $structure->type = 'content'; $this->parts[] = &$structure; } - // message contains alternative parts - else if ($mimetype == 'multipart/alternative' && is_array($structure->parts)) { + // message contains (more than one!) alternative parts + else if ($mimetype == 'multipart/alternative' + && is_array($structure->parts) && count($structure->parts) > 1 + ) { // get html/plaintext parts $plain_part = $html_part = $print_part = $related_part = null; @@ -510,7 +511,7 @@ class rcube_message $img_regexp = '/^image\/(gif|jpe?g|png|tiff|bmp|svg)/'; foreach ($this->inline_parts as $inline_object) { - $part_url = $this->get_part_url($inline_object->mime_id); + $part_url = $this->get_part_url($inline_object->mime_id, true); if ($inline_object->content_id) $a_replaces['cid:'.$inline_object->content_id] = $part_url; if ($inline_object->content_location) { diff --git a/program/include/rcube_mime_struct.php b/program/include/rcube_mime_struct.php index de283d2..ed28af3 100644 --- a/program/include/rcube_mime_struct.php +++ b/program/include/rcube_mime_struct.php @@ -1,77 +1,7 @@ -<?php - -/* - +-----------------------------------------------------------------------+ - | program/include/rcube_mime_struct.php | - | | - | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | - | Licensed under the GNU GPL | - | | - | PURPOSE: | - | Provide functions for handling mime messages structure | - | | - | Based on Iloha MIME Library. See http://ilohamail.org/ for details | - | | - +-----------------------------------------------------------------------+ - | Author: Aleksander Machniak <alec@alec.pl> | - | Author: Ryo Chijiiwa <Ryo@IlohaMail.org> | - +-----------------------------------------------------------------------+ - - $Id: rcube_mime_struct.php 4980 2011-07-27 18:21:49Z alec $ - -*/ - -/** - * Helper class to process IMAP's BODYSTRUCTURE string - * - * @package Mail - * @author Aleksander Machniak <alec@alec.pl> - */ -class rcube_mime_struct -{ - private $structure; - - - function __construct($str=null) - { - if ($str) - $this->structure = $this->parseStructure($str); - } - - /* - * Parses IMAP's BODYSTRUCTURE string into array - */ - function parseStructure($str) - { - $line = substr($str, 1, strlen($str) - 2); - $line = str_replace(')(', ') (', $line); - - $struct = rcube_imap_generic::tokenizeResponse($line); - if (!is_array($struct[0]) && (strcasecmp($struct[0], 'message') == 0) - && (strcasecmp($struct[1], 'rfc822') == 0)) { - $struct = array($struct); - } - - return $struct; - } - - /* - * Parses IMAP's BODYSTRUCTURE string into array and loads it into class internal variable - */ - function loadStructure($str) + function getStructurePartType($structure, $part) { - if (empty($str)) - return true; - - $this->structure = $this->parseStructure($str); - return (!empty($this->structure)); - } - - function getPartType($part) - { - $part_a = $this->getPartArray($this->structure, $part); + $part_a = self::getPartArray($structure, $part); if (!empty($part_a)) { if (is_array($part_a[0])) return 'multipart'; @@ -82,9 +12,9 @@ class rcube_mime_struct return 'other'; } - function getPartEncoding($part) + function getStructurePartEncoding($structure, $part) { - $part_a = $this->getPartArray($this->structure, $part); + $part_a = self::getPartArray($structure, $part); if ($part_a) { if (!is_array($part_a[0])) return $part_a[5]; @@ -93,9 +23,9 @@ class rcube_mime_struct return ''; } - function getPartCharset($part) + function getStructurePartCharset($structure, $part) { - $part_a = $this->getPartArray($this->structure, $part); + $part_a = self::getPartArray($structure, $part); if ($part_a) { if (is_array($part_a[0])) return ''; @@ -112,7 +42,7 @@ class rcube_mime_struct return ''; } - function getPartArray($a, $part) + function getStructurePartArray($a, $part) { if (!is_array($a)) { return false; @@ -137,9 +67,7 @@ class rcube_mime_struct else return $a; } - else if (($part==0) || (empty($part))) { + else if (($part == 0) || (empty($part))) { return $a; } } - -} diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php index c75a17c..748d958 100644 --- a/program/include/rcube_plugin.php +++ b/program/include/rcube_plugin.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_plugin.php 4870 2011-06-21 09:10:14Z alec $ + $Id: rcube_plugin.php 5168 2011-09-05 11:08:48Z alec $ */ @@ -147,8 +147,11 @@ abstract class rcube_plugin ob_start(); foreach (array('en_US', $lang) as $lng) { - @include($locdir . $lng . '.inc'); - $texts = (array)$labels + (array)$messages + (array)$texts; + $fpath = $locdir . $lng . '.inc'; + if (is_file($fpath) && is_readable($fpath)) { + include($fpath); + $texts = (array)$labels + (array)$messages + (array)$texts; + } } ob_end_clean(); diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php index 6fa566b..e762fff 100644 --- a/program/include/rcube_plugin_api.php +++ b/program/include/rcube_plugin_api.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_plugin_api.php 5151 2011-08-31 12:49:44Z alec $ + $Id: rcube_plugin_api.php 5207 2011-09-12 12:52:01Z alec $ */ @@ -421,6 +421,17 @@ class rcube_plugin_api } + /** + * Returns list of loaded plugins names + * + * @return array List of plugin names + */ + public function loaded_plugins() + { + return array_keys($this->plugins); + } + + /** * Callback for template_container hooks * diff --git a/program/include/rcube_result_set.php b/program/include/rcube_result_set.php index cf023d6..e4a4ad4 100644 --- a/program/include/rcube_result_set.php +++ b/program/include/rcube_result_set.php @@ -5,7 +5,7 @@ | program/include/rcube_result_set.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2006-2010, The Roundcube Dev Team | + | Copyright (C) 2006-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_result_set.php 4834 2011-06-03 11:03:13Z alec $ + $Id: rcube_result_set.php 5258 2011-09-21 11:17:46Z thomasb $ */ @@ -31,6 +31,7 @@ class rcube_result_set var $count = 0; var $first = 0; var $current = 0; + var $searchonly = false; var $records = array(); diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php index 01b9367..bd0ce60 100644 --- a/program/include/rcube_session.php +++ b/program/include/rcube_session.php @@ -6,6 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -330,20 +331,7 @@ class rcube_session public function gc() { foreach ($this->gc_handlers as $fct) - $fct(); - } - - - /** - * Cleanup session data before saving - */ - public function cleanup() - { - // current compose information is stored in $_SESSION['compose'], move it to $_SESSION['compose_data_<ID>'] - if ($compose_id = $_SESSION['compose']['id']) { - $_SESSION['compose_data_'.$compose_id] = $_SESSION['compose']; - $this->remove('compose'); - } + call_user_func($fct); } @@ -403,6 +391,21 @@ class rcube_session } + /** + * Re-read session data from storage backend + */ + public function reload() + { + if ($this->key && $this->memcache) + $data = $this->mc_read($this->key); + else if ($this->key) + $data = $this->db_read($this->key); + + if ($data) + session_decode($data); + } + + /** * Serialize session data */ diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 3cd96c9..6e58ad8 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -15,14 +15,14 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_shared.inc 4710 2011-04-29 08:17:42Z alec $ + $Id: rcube_shared.inc 5274 2011-09-23 10:11:27Z alec $ */ /** * Roundcube shared functions - * + * * @package Core */ @@ -69,50 +69,6 @@ function send_future_expire_header($offset=2600000) } -/** - * Check request for If-Modified-Since and send an according response. - * This will terminate the current script if headers match the given values - * - * @param int Modified date as unix timestamp - * @param string Etag value for caching - */ -function send_modified_header($mdate, $etag=null, $skip_check=false) -{ - if (headers_sent()) - return; - - $iscached = false; - $etag = $etag ? "\"$etag\"" : null; - - if (!$skip_check) - { - if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mdate) - $iscached = true; - - if ($etag) - $iscached = ($_SERVER['HTTP_IF_NONE_MATCH'] == $etag); - } - - if ($iscached) - header("HTTP/1.x 304 Not Modified"); - else - header("Last-Modified: ".gmdate("D, d M Y H:i:s", $mdate)." GMT"); - - header("Cache-Control: private, must-revalidate, max-age=0"); - header("Expires: "); - header("Pragma: "); - - if ($etag) - header("Etag: $etag"); - - if ($iscached) - { - ob_end_clean(); - exit; - } -} - - /** * Similar function as in_array() but case-insensitive * @@ -126,7 +82,7 @@ function in_array_nocase($needle, $haystack) foreach ($haystack as $value) if ($needle===mb_strtolower($value)) return true; - + return false; } @@ -218,7 +174,7 @@ function make_absolute_url($path, $base_url) { $host_url = $base_url; $abs_path = $path; - + // check if path is an absolute URL if (preg_match('/^[fhtps]+:\/\//', $path)) return $path; @@ -325,7 +281,7 @@ function rc_request_header($name) } return $hdrs[$key]; - } +} /** @@ -344,7 +300,7 @@ function unslashify($str) { return preg_replace('/\/$/', '', $str); } - + /** * Delete all files within a folder @@ -374,7 +330,7 @@ function clear_directory($dir_path) * @return int Unix timestamp */ function get_offset_time($offset_str, $factor=1) - { +{ if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs)) { $amount = (int)$regs[1]; @@ -385,7 +341,7 @@ function get_offset_time($offset_str, $factor=1) $amount = (int)$offset_str; $unit = 's'; } - + $ts = mktime(); switch ($unit) { @@ -418,7 +374,7 @@ function get_offset_time($offset_str, $factor=1) function abbreviate_string($str, $maxlength, $place_holder='...', $ending=false) { $length = mb_strlen($str); - + if ($length > $maxlength) { if ($ending) @@ -433,6 +389,7 @@ function abbreviate_string($str, $maxlength, $place_holder='...', $ending=false) return $str; } + /** * A method to guess the mime_type of an attachment. * @@ -547,7 +504,7 @@ function rc_utf8_clean($input) $input[$idx] = rc_utf8_clean($val); return $input; } - + if (!is_string($input) || $input == '') return $input; @@ -569,7 +526,7 @@ function rc_utf8_clean($input) '|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.// UTF8-4 '|\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]'. // UTF8-4 ')$/'; - + $seq = ''; $out = ''; @@ -640,7 +597,7 @@ function rcube_explode_quoted_string($delimiter, $string) $p = $i + 1; } } - + $result[] = substr($string, $p); return $result; } @@ -655,7 +612,7 @@ function rcube_explode_quoted_string($delimiter, $string) function array_keys_recursive($array) { $keys = array(); - + if (!empty($array)) foreach ($array as $key => $child) { $keys[] = $key; diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php index 28df53b..8c668c0 100644 --- a/program/include/rcube_smtp.php +++ b/program/include/rcube_smtp.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_smtp.php 5033 2011-08-09 09:46:54Z alec $ + $Id: rcube_smtp.php 5499 2011-11-28 09:03:27Z alec $ */ @@ -214,14 +214,10 @@ class rcube_smtp if ($opts['dsn']) { $exts = $this->conn->getServiceExtensions(); - if (!isset($exts['DSN'])) { - $this->error = array('label' => 'smtpdsnerror'); - $this->response[] = "DSN not supported"; - return false; + if (isset($exts['DSN'])) { + $from_params = 'RET=HDRS'; + $recipient_params = 'NOTIFY=SUCCESS,FAILURE'; } - - $from_params = 'RET=HDRS'; - $recipient_params = 'NOTIFY=SUCCESS,FAILURE'; } // RFC2298.3: remove envelope sender address @@ -385,7 +381,7 @@ class rcube_smtp $from = $addresses[0]; // Reject envelope From: addresses with spaces. - if (strstr($from, ' ')) + if (strpos($from, ' ') !== false) return false; $lines[] = $key . ': ' . $value; diff --git a/program/include/rcube_spellchecker.php b/program/include/rcube_spellchecker.php index 8046223..3b565c3 100644 --- a/program/include/rcube_spellchecker.php +++ b/program/include/rcube_spellchecker.php @@ -17,7 +17,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_spellchecker.php 4817 2011-05-30 17:08:47Z alec $ + $Id: rcube_spellchecker.php 5181 2011-09-06 13:39:45Z alec $ */ @@ -34,8 +34,11 @@ class rcube_spellchecker private $lang; private $rc; private $error; - private $separator = '/[ !"#$%&()*+\\,\/\n:;<=>?@\[\]^_{|}-]+|\.[^\w]/'; - + private $separator = '/[\s\r\n\t\(\)\/\[\]{}<>\\"]+|[:;?!,\.]([^\w]|$)/'; + private $options = array(); + private $dict; + private $have_dict; + // default settings const GOOGLE_HOST = 'ssl://www.google.com'; @@ -50,9 +53,9 @@ class rcube_spellchecker */ function __construct($lang = 'en') { - $this->rc = rcmail::get_instance(); + $this->rc = rcmail::get_instance(); $this->engine = $this->rc->config->get('spellcheck_engine', 'googie'); - $this->lang = $lang ? $lang : 'en'; + $this->lang = $lang ? $lang : 'en'; if ($this->engine == 'pspell' && !extension_loaded('pspell')) { raise_error(array( @@ -60,6 +63,13 @@ class rcube_spellchecker 'file' => __FILE__, 'line' => __LINE__, 'message' => "Pspell extension not available"), true, true); } + + $this->options = array( + 'ignore_syms' => $this->rc->config->get('spellcheck_ignore_syms'), + 'ignore_nums' => $this->rc->config->get('spellcheck_ignore_nums'), + 'ignore_caps' => $this->rc->config->get('spellcheck_ignore_caps'), + 'dictionary' => $this->rc->config->get('spellcheck_dictionary'), + ); } @@ -71,7 +81,7 @@ class rcube_spellchecker * * @return bool True when no mispelling found, otherwise false */ - function check($text, $is_html=false) + function check($text, $is_html = false) { // convert to plain text if ($is_html) { @@ -116,9 +126,9 @@ class rcube_spellchecker return $this->_pspell_suggestions($word); } - return $this->_googie_suggestions($word); + return $this->_googie_suggestions($word); } - + /** * Returns mispelled words @@ -179,7 +189,7 @@ class rcube_spellchecker $result[$word] = is_array($item[4]) ? implode("\t", $item[4]) : $item[4]; } - return $out; + return $result; } @@ -211,15 +221,18 @@ class rcube_spellchecker // tokenize $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); - $diff = 0; - $matches = array(); + $diff = 0; + $matches = array(); foreach ($text as $w) { $word = trim($w[0]); $pos = $w[1] - $diff; $len = mb_strlen($word); - if ($word && preg_match('/[^0-9\.]/', $word) && !pspell_check($this->plink, $word)) { + // skip exceptions + if ($this->is_exception($word)) { + } + else if (!pspell_check($this->plink, $word)) { $suggestions = pspell_suggest($this->plink, $word); if (sizeof($suggestions) > self::MAX_SUGGESTIONS) @@ -240,6 +253,8 @@ class rcube_spellchecker */ private function _pspell_words($text = null, $is_html=false) { + $result = array(); + if ($text) { // init spellchecker $this->_pspell_init(); @@ -257,7 +272,13 @@ class rcube_spellchecker foreach ($text as $w) { $word = trim($w[0]); - if ($word && preg_match('/[^0-9\.]/', $word) && !pspell_check($this->plink, $word)) { + + // skip exceptions + if ($this->is_exception($word)) { + continue; + } + + if (!pspell_check($this->plink, $word)) { $result[] = $word; } } @@ -265,8 +286,6 @@ class rcube_spellchecker return $result; } - $result = array(); - foreach ($this->matches as $m) { $result[] = $m[0]; } @@ -330,21 +349,21 @@ class rcube_spellchecker } // Google has some problem with spaces, use \n instead - $text = str_replace(' ', "\n", $text); + $gtext = str_replace(' ', "\n", $text); - $text = '<?xml version="1.0" encoding="utf-8" ?>' + $gtext = '<?xml version="1.0" encoding="utf-8" ?>' .'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">' - .'<text>' . $text . '</text>' + .'<text>' . $gtext . '</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 .= "Content-Length: " . strlen($text) . "\r\n"; + $out .= "Content-Length: " . strlen($gtext) . "\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "Connection: Close\r\n\r\n"; - $out .= $text; + $out .= $gtext; fwrite($fp, $out); while (!feof($fp)) @@ -358,6 +377,19 @@ class rcube_spellchecker preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); + // skip exceptions (if appropriate options are enabled) + if (!empty($this->options['ignore_syms']) || !empty($this->options['ignore_nums']) + || !empty($this->options['ignore_caps']) || !empty($this->options['dictionary']) + ) { + foreach ($matches as $idx => $m) { + $word = mb_substr($text, $m[1], $m[2], RCMAIL_CHARSET); + // skip exceptions + if ($this->is_exception($word)) { + unset($matches[$idx]); + } + } + } + return $matches; } @@ -413,4 +445,172 @@ class rcube_spellchecker $h2t = new html2text($text, false, true, 0); return $h2t->get_text(); } + + + /** + * Check if the specified word is an exception accoring to + * spellcheck options. + * + * @param string $word The word + * + * @return bool True if the word is an exception, False otherwise + */ + public function is_exception($word) + { + // Contain only symbols (e.g. "+9,0", "2:2") + if (!$word || preg_match('/^[0-9@#$%^&_+~*=:;?!,.-]+$/', $word)) + return true; + + // Contain symbols (e.g. "g@@gle"), all symbols excluding separators + if (!empty($this->options['ignore_syms']) && preg_match('/[@#$%^&_+~*=-]/', $word)) + return true; + + // Contain numbers (e.g. "g00g13") + if (!empty($this->options['ignore_nums']) && preg_match('/[0-9]/', $word)) + return true; + + // Blocked caps (e.g. "GOOGLE") + if (!empty($this->options['ignore_caps']) && $word == mb_strtoupper($word)) + return true; + + // Use exceptions from dictionary + if (!empty($this->options['dictionary'])) { + $this->load_dict(); + + // @TODO: should dictionary be case-insensitive? + if (!empty($this->dict) && in_array($word, $this->dict)) + return true; + } + + return false; + } + + + /** + * Add a word to dictionary + * + * @param string $word The word to add + */ + public function add_word($word) + { + $this->load_dict(); + + foreach (explode(' ', $word) as $word) { + // sanity check + if (strlen($word) < 512) { + $this->dict[] = $word; + $valid = true; + } + } + + if ($valid) { + $this->dict = array_unique($this->dict); + $this->update_dict(); + } + } + + + /** + * Remove a word from dictionary + * + * @param string $word The word to remove + */ + public function remove_word($word) + { + $this->load_dict(); + + if (($key = array_search($word, $this->dict)) !== false) { + unset($this->dict[$key]); + $this->update_dict(); + } + } + + + /** + * Update dictionary row in DB + */ + private function update_dict() + { + if (strcasecmp($this->options['dictionary'], 'shared') != 0) { + $userid = (int) $this->rc->user->ID; + } + + $plugin = $this->rc->plugins->exec_hook('spell_dictionary_save', array( + 'userid' => $userid, 'language' => $this->lang, 'dictionary' => $this->dict)); + + if (!empty($plugin['abort'])) { + return; + } + + if ($this->have_dict) { + if (!empty($this->dict)) { + $this->rc->db->query( + "UPDATE ".get_table_name('dictionary') + ." SET data = ?" + ." WHERE user_id " . ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL") + ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + implode(' ', $plugin['dictionary']), $plugin['language']); + } + // don't store empty dict + else { + $this->rc->db->query( + "DELETE FROM " . get_table_name('dictionary') + ." WHERE user_id " . ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL") + ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + $plugin['language']); + } + } + else if (!empty($this->dict)) { + $this->rc->db->query( + "INSERT INTO " .get_table_name('dictionary') + ." (user_id, " . $this->rc->db->quoteIdentifier('language') . ", data) VALUES (?, ?, ?)", + $plugin['userid'], $plugin['language'], implode(' ', $plugin['dictionary'])); + } + } + + + /** + * Get dictionary from DB + */ + private function load_dict() + { + if (is_array($this->dict)) { + return $this->dict; + } + + if (strcasecmp($this->options['dictionary'], 'shared') != 0) { + $userid = (int) $this->rc->user->ID; + } + + $plugin = $this->rc->plugins->exec_hook('spell_dictionary_get', array( + 'userid' => $userid, 'language' => $this->lang, 'dictionary' => array())); + + if (empty($plugin['abort'])) { + $dict = array(); + $this->rc->db->query( + "SELECT data FROM ".get_table_name('dictionary') + ." WHERE user_id ". ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL") + ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + $plugin['language']); + + if ($sql_arr = $this->rc->db->fetch_assoc($sql_result)) { + $this->have_dict = true; + if (!empty($sql_arr['data'])) { + $dict = explode(' ', $sql_arr['data']); + } + } + + $plugin['dictionary'] = array_merge((array)$plugin['dictionary'], $dict); + } + + if (!empty($plugin['dictionary']) && is_array($plugin['dictionary'])) { + $this->dict = $plugin['dictionary']; + } + else { + $this->dict = array(); + } + + return $this->dict; + } + } diff --git a/program/include/rcube_string_replacer.php b/program/include/rcube_string_replacer.php index f753aa8..b69e9cf 100644 --- a/program/include/rcube_string_replacer.php +++ b/program/include/rcube_string_replacer.php @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_string_replacer.php 5203 2011-09-12 06:44:56Z alec $ + $Id: rcube_string_replacer.php 5481 2011-11-24 07:53:00Z alec $ */ @@ -39,7 +39,7 @@ class rcube_string_replacer // Support unicode/punycode in top-level domain part $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})'; $url1 = '.:;,'; - $url2 = 'a-z0-9%=#@+?&\\/_~\\[\\]-'; + $url2 = 'a-z0-9%=#@+?!&\\/_~\\[\\]{}-'; $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i"; $this->mailto_pattern = "/(" diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php index 9c208b3..5a09fca 100755 --- a/program/include/rcube_template.php +++ b/program/include/rcube_template.php @@ -16,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_template.php 5165 2011-09-05 08:49:04Z thomasb $ + $Id: rcube_template.php 5481 2011-11-24 07:53:00Z alec $ */ @@ -71,6 +71,7 @@ class rcube_template extends rcube_html_page //$this->framed = $framed; $this->set_env('task', $task); + $this->set_env('x_frame_options', $this->app->config->get('x_frame_options', 'sameorigin')); // load the correct skin (in case user-defined) $this->set_skin($this->config['skin']); @@ -217,7 +218,9 @@ class rcube_template extends rcube_html_page public function command() { $cmd = func_get_args(); - if (strpos($cmd[0], 'plugin.') === false) + if (strpos($cmd[0], 'plugin.') !== false) + $this->js_commands[] = array('triggerEvent', $cmd[0], $cmd[1]); + else $this->js_commands[] = $cmd; } @@ -353,10 +356,6 @@ class rcube_template extends rcube_html_page $js .= $this->get_js_commands() . ($this->framed ? ' }' : ''); $this->add_script($js, 'head_top'); - // make sure all <form> tags have a valid request token - $template = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $template); - $this->footer = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $this->footer); - // send clickjacking protection headers $iframe = $this->framed || !empty($_REQUEST['_framed']); if (!headers_sent() && ($xframe = $this->app->config->get('x_frame_options', 'sameorigin'))) @@ -437,6 +436,10 @@ class rcube_template extends rcube_html_page $output = $this->parse_with_globals($hook['content']); + // make sure all <form> tags have a valid request token + $output = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $output); + $this->footer = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $this->footer); + if ($write) { // add debug console if ($realname != 'error' && ($this->config['debug_level'] & 8)) { @@ -689,7 +692,7 @@ class rcube_template extends rcube_html_page $vars = $attrib + array('product' => $this->config['product_name']); unset($vars['name'], $vars['command']); $label = rcube_label($attrib + array('vars' => $vars)); - return !$attrbi['noshow'] ? Q($label) : ''; + return !$attrib['noshow'] ? (get_boolean((string)$attrib['html']) ? $label : Q($label)) : ''; } break; @@ -913,6 +916,7 @@ class rcube_template extends rcube_html_page // make valid href to specific buttons if (in_array($attrib['command'], rcmail::$main_tasks)) { $attrib['href'] = rcmail_url(null, null, $attrib['command']); + $attrib['onclick'] = sprintf("%s.switch_task('%s');return false", JS_OBJECT_NAME, $attrib['command']); } else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) { $attrib['href'] = rcmail_url($attrib['command'], null, $attrib['task']); @@ -1105,6 +1109,7 @@ class rcube_template extends rcube_html_page $input_task = new html_hiddenfield(array('name' => '_task', 'value' => 'login')); $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login')); $input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_')); + $input_dst = new html_hiddenfield(array('name' => '_dstactive', 'id' => 'rcmlogindst', 'value' => '_default_')); $input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url)); $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser') + $attrib + $user_attrib); @@ -1142,20 +1147,21 @@ class rcube_template extends rcube_html_page $table = new html_table(array('cols' => 2)); $table->add('title', html::label('rcmloginuser', Q(rcube_label('username')))); - $table->add(null, $input_user->show(get_input_value('_user', RCUBE_INPUT_GPC))); + $table->add('input', $input_user->show(get_input_value('_user', RCUBE_INPUT_GPC))); $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password')))); - $table->add(null, $input_pass->show()); + $table->add('input', $input_pass->show()); // add host selection row if (is_object($input_host) && !$hide_host) { $table->add('title', html::label('rcmloginhost', Q(rcube_label('server')))); - $table->add(null, $input_host->show(get_input_value('_host', RCUBE_INPUT_GPC))); + $table->add('input', $input_host->show(get_input_value('_host', RCUBE_INPUT_GPC))); } $out = $input_task->show(); $out .= $input_action->show(); $out .= $input_tzone->show(); + $out .= $input_dst->show(); $out .= $input_url->show(); $out .= $table->show(); diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php index 19d0811..cc006c0 100644 --- a/program/include/rcube_user.php +++ b/program/include/rcube_user.php @@ -16,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_user.php 5165 2011-09-05 08:49:04Z thomasb $ + $Id: rcube_user.php 5183 2011-09-06 17:18:12Z alec $ */ @@ -47,6 +47,8 @@ class rcube_user */ private $rc; + const SEARCH_ADDRESSBOOK = 1; + const SEARCH_MAIL = 2; /** * Object constructor @@ -397,11 +399,8 @@ class rcube_user { $dbh = rcmail::get_instance()->get_dbh(); - // use BINARY (case-sensitive) comparison on MySQL, other engines are case-sensitive - $mod = preg_match('/^mysql/', $dbh->db_provider) ? 'BINARY' : ''; - // query for matching user name - $query = "SELECT * FROM ".get_table_name('users')." WHERE mail_host = ? AND %s = $mod ?"; + $query = "SELECT * FROM ".get_table_name('users')." WHERE mail_host = ? AND %s = ?"; $sql_result = $dbh->query(sprintf($query, 'username'), $host, $user); // query for matching alias @@ -551,4 +550,129 @@ class rcube_user return empty($plugin['email']) ? NULL : $plugin['email']; } + + /** + * Return a list of saved searches linked with this user + * + * @param int $type Search type + * + * @return array List of saved searches indexed by search ID + */ + function list_searches($type) + { + $plugin = $this->rc->plugins->exec_hook('saved_search_list', array('type' => $type)); + + if ($plugin['abort']) { + return (array) $plugin['result']; + } + + $result = array(); + + $sql_result = $this->db->query( + "SELECT search_id AS id, ".$this->db->quoteIdentifier('name') + ." FROM ".get_table_name('searches') + ." WHERE user_id = ?" + ." AND ".$this->db->quoteIdentifier('type')." = ?" + ." ORDER BY ".$this->db->quoteIdentifier('name'), + (int) $this->ID, (int) $type); + + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $sql_arr['data'] = unserialize($sql_arr['data']); + $result[$sql_arr['id']] = $sql_arr; + } + + return $result; + } + + + /** + * Return saved search data. + * + * @param int $id Row identifier + * + * @return array Data + */ + function get_search($id) + { + $plugin = $this->rc->plugins->exec_hook('saved_search_get', array('id' => $id)); + + if ($plugin['abort']) { + return $plugin['result']; + } + + $sql_result = $this->db->query( + "SELECT ".$this->db->quoteIdentifier('name') + .", ".$this->db->quoteIdentifier('data') + .", ".$this->db->quoteIdentifier('type') + ." FROM ".get_table_name('searches') + ." WHERE user_id = ?" + ." AND search_id = ?", + (int) $this->ID, (int) $id); + + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + return array( + 'id' => $id, + 'name' => $sql_arr['name'], + 'type' => $sql_arr['type'], + 'data' => unserialize($sql_arr['data']), + ); + } + + return null; + } + + + /** + * Deletes given saved search record + * + * @param int $sid Search ID + * + * @return boolean True if deleted successfully, false if nothing changed + */ + function delete_search($sid) + { + if (!$this->ID) + return false; + + $this->db->query( + "DELETE FROM ".get_table_name('searches') + ." WHERE user_id = ?" + ." AND search_id = ?", + (int) $this->ID, $sid); + + return $this->db->affected_rows(); + } + + + /** + * Create a new saved search record linked with this user + * + * @param array $data Hash array with col->value pairs to save + * + * @return int The inserted search ID or false on error + */ + function insert_search($data) + { + if (!$this->ID) + return false; + + $insert_cols[] = 'user_id'; + $insert_values[] = (int) $this->ID; + $insert_cols[] = $this->db->quoteIdentifier('type'); + $insert_values[] = (int) $data['type']; + $insert_cols[] = $this->db->quoteIdentifier('name'); + $insert_values[] = $data['name']; + $insert_cols[] = $this->db->quoteIdentifier('data'); + $insert_values[] = serialize($data['data']); + + $sql = "INSERT INTO ".get_table_name('searches') + ." (".join(', ', $insert_cols).")" + ." VALUES (".join(', ', array_pad(array(), sizeof($insert_values), '?')).")"; + + call_user_func_array(array($this->db, 'query'), + array_merge(array($sql), $insert_values)); + + return $this->db->insert_id('searches'); + } + } diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index c02210b..dba020a 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -14,7 +14,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: rcube_vcard.php 5165 2011-09-05 08:49:04Z thomasb $ + $Id: rcube_vcard.php 5160 2011-09-05 07:40:18Z thomasb $ */ diff --git a/program/js/app.js b/program/js/app.js index 5957acf..c871cc6 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1,205 +1,213 @@ -function rcube_webmail(){this.env={};this.labels={};this.buttons={};this.buttons_sel={};this.gui_objects={};this.gui_containers={};this.commands={};this.command_handlers={};this.onloads=[];this.messages={};this.ref="rcmail";var l=this;this.dblclick_time=500;this.message_time=2E3;this.identifier_expr=RegExp("[^0-9a-z-_]","gi");this.env.keep_alive=60;this.env.request_timeout=180;this.env.draft_autosave=0;this.env.comm_path="./";this.env.blankpage="program/blank.gif";$.ajaxSetup({cache:!1,error:function(a, -b,d){l.http_error(a,b,d)},beforeSend:function(a){a.setRequestHeader("X-Roundcube-Request",l.env.request_token)}});this.set_env=function(a,b){if(a!=null&&typeof a==="object"&&!b)for(var d in a)this.env[d]=a[d];else this.env[a]=b};this.add_label=function(a,b){typeof a=="string"?this.labels[a]=b:typeof a=="object"&&$.extend(this.labels,a)};this.register_button=function(a,b,d,e,f,g){this.buttons[a]||(this.buttons[a]=[]);b={id:b,type:d};if(e)b.act=e;if(f)b.sel=f;if(g)b.over=g;this.buttons[a].push(b);this.loaded&& -t(a,b)};this.gui_object=function(a,b){this.gui_objects[a]=this.loaded?rcube_find_object(b):b};this.gui_container=function(a,b){this.gui_containers[a]=b};this.add_element=function(a,b){this.gui_containers[b]&&this.gui_containers[b].jquery&&this.gui_containers[b].append(a)};this.register_command=function(a,b,d){this.command_handlers[a]=b;d&&this.enable_command(a,!0)};this.add_onload=function(a){this.onloads.push(a)};this.init=function(){var a=this;this.task=this.env.task;if(!bw.dom||!bw.xmlhttp_test())this.goto_url("error", -"_code=0x199");else{for(var b in this.gui_containers)this.gui_containers[b]=$("#"+this.gui_containers[b]);for(b in this.gui_objects)this.gui_objects[b]=rcube_find_object(this.gui_objects[b]);this.init_buttons();if(this.is_framed())parent.rcmail.set_busy(!1,null,parent.rcmail.env.frame_lock),parent.rcmail.env.frame_lock=null;this.enable_command("logout","mail","addressbook","settings","save-pref","undo",!0);this.env.permaurl&&this.enable_command("permaurl",!0);switch(this.task){case "mail":this.enable_command("list", -"checkmail","compose","add-contact","search","reset-search","collapse-folder",!0);if(this.gui_objects.messagelist)this.message_list=new rcube_list_widget(this.gui_objects.messagelist,{multiselect:!0,multiexpand:!0,draggable:!0,keyboard:!0,column_movable:this.env.col_movable,dblclick_time:this.dblclick_time}),this.message_list.row_init=function(b){a.init_message_row(b)},this.message_list.addEventListener("dblclick",function(b){a.msglist_dbl_click(b)}),this.message_list.addEventListener("click",function(b){a.msglist_click(b)}), -this.message_list.addEventListener("keypress",function(b){a.msglist_keypress(b)}),this.message_list.addEventListener("select",function(b){a.msglist_select(b)}),this.message_list.addEventListener("dragstart",function(b){a.drag_start(b)}),this.message_list.addEventListener("dragmove",function(b){a.drag_move(b)}),this.message_list.addEventListener("dragend",function(b){a.drag_end(b)}),this.message_list.addEventListener("expandcollapse",function(b){a.msglist_expand(b)}),this.message_list.addEventListener("column_replace", -function(b){a.msglist_set_coltypes(b)}),document.onmouseup=function(b){return a.doc_mouse_up(b)},this.gui_objects.messagelist.parentNode.onmousedown=function(b){return a.click_on_list(b)},this.message_list.init(),this.enable_command("toggle_status","toggle_flag","menu-open","menu-save",!0),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.blur()})}!this.env.flag_for_deletion&& -this.env.trash_mailbox&&this.env.mailbox!=this.env.trash_mailbox&&this.set_alttext("delete","movemessagetotrash");this.env.message_commands="show,reply,reply-all,reply-list,forward,moveto,copy,delete,open,mark,edit,viewsource,download,print,load-attachment,load-headers,forward-attachment".split(",");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);this.env.action=="show"&&this.http_request("pagenav", -"_uid="+this.env.uid+"&_mbox="+urlencode(this.env.mailbox),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",!0)}this.env.action=="preview"&&this.is_framed()&&(this.enable_command("compose","add-contact",!1),parent.rcmail.show_contentframe(!0))}else if(this.env.action=="compose"){this.env.compose_commands=["send-attachment","remove-attachment", -"send","cancel","toggle-editor"];this.env.drafts_mailbox&&this.env.compose_commands.push("savedraft");this.enable_command(this.env.compose_commands,"identities",!0);if(this.env.spellcheck)this.env.spellcheck.spelling_state_observer=function(a){l.set_spellcheck_state(a)},this.env.compose_commands.push("spellcheck"),this.set_spellcheck_state("ready"),$("input[name='_is_html']").val()=="1"&&this.display_spellcheck_controls(!1);document.onmouseup=function(b){return a.doc_mouse_up(b)};this.init_messageform()}else this.env.action== -"print"&&this.env.uid&&(bw.safari?window.setTimeout("window.print()",10):window.print());if(this.gui_objects.mailboxlist)this.env.unread_counts={},this.gui_objects.folderlist=this.gui_objects.mailboxlist,this.http_request("getunread","");this.env.mdn_request&&this.env.uid&&(b="_uid="+this.env.uid+"&_mbox="+urlencode(this.env.mailbox),confirm(this.get_label("mdnrequest"))?this.http_post("sendmdn",b):this.http_post("mark",b+"&_flag=mdnsent"));break;case "addressbook":if(this.gui_objects.folderlist)this.env.contactfolders= -$.extend($.extend({},this.env.address_sources),this.env.contactgroups);if(this.gui_objects.contactslist)this.contact_list=new rcube_list_widget(this.gui_objects.contactslist,{multiselect:!0,draggable:this.gui_objects.folderlist?!0:!1,keyboard:!0}),this.contact_list.row_init=function(b){a.triggerEvent("insertrow",{cid:b.uid,row:b})},this.contact_list.addEventListener("keypress",function(b){a.contactlist_keypress(b)}),this.contact_list.addEventListener("select",function(b){a.contactlist_select(b)}), -this.contact_list.addEventListener("dragstart",function(b){a.drag_start(b)}),this.contact_list.addEventListener("dragmove",function(b){a.drag_move(b)}),this.contact_list.addEventListener("dragend",function(b){a.drag_end(b)}),this.contact_list.init(),this.env.cid&&this.contact_list.highlight_row(this.env.cid),this.gui_objects.contactslist.parentNode.onmousedown=function(b){return a.click_on_list(b)},document.onmouseup=function(b){return a.doc_mouse_up(b)},this.gui_objects.qsearchbox&&$(this.gui_objects.qsearchbox).focusin(function(){rcmail.contact_list.blur()}), -this.update_group_commands();this.set_page_buttons();this.env.cid&&(this.enable_command("show","edit",!0),this.gui_objects.editform&&$("input.groupmember").change(function(){l.group_member_change(this.checked?"add":"del",l.env.cid,l.env.source,this.value)}));this.gui_objects.editform&&(this.enable_command("save",!0),(this.env.action=="add"||this.env.action=="edit")&&this.init_contact_form());this.gui_objects.qsearchbox&&this.enable_command("search","reset-search","moveto",!0);this.contact_list&&this.contact_list.rowcount> -0&&this.enable_command("export",!0);this.enable_command("add","import",this.env.writable_source);this.enable_command("list","listgroup","advanced-search",!0);this.env.action||this.command("list",this.env.source);break;case "settings":this.enable_command("preferences","identities","save","folders",!0);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("add",this.env.identities_level< -2),this.enable_command("save","delete","edit","toggle-editor",!0);else if(this.env.action=="folders")this.enable_command("subscribe","unsubscribe","create-folder","rename-folder",!0);else if(this.env.action=="edit-folder"&&this.gui_objects.editform)this.enable_command("save","folder-size",!0),parent.rcmail.env.messagecount=this.env.messagecount,parent.rcmail.enable_command("purge",this.env.messagecount),$("input[type='text']").first().select();this.gui_objects.identitieslist?(this.identity_list=new rcube_list_widget(this.gui_objects.identitieslist, -{multiselect:!1,draggable:!1,keyboard:!1}),this.identity_list.addEventListener("select",function(b){a.identity_select(b)}),this.identity_list.init(),this.identity_list.focus(),this.env.iid&&this.identity_list.highlight_row(this.env.iid)):this.gui_objects.sectionslist?(this.sections_list=new rcube_list_widget(this.gui_objects.sectionslist,{multiselect:!1,draggable:!1,keyboard:!1}),this.sections_list.addEventListener("select",function(b){a.section_select(b)}),this.sections_list.init(),this.sections_list.focus()): -this.gui_objects.subscriptionlist&&this.init_subscription_list();break;case "login":b=$("#rcmloginuser"),b.bind("keyup",function(a){return rcmail.login_user_keyup(a)}),b.val()==""?b.focus():$("#rcmloginpwd").focus(),$("#rcmlogintz").val((new Date).getTimezoneOffset()/-60),$("form").submit(function(){$("input[type=submit]",this).prop("disabled",!0);rcmail.display_message("","loading")}),this.enable_command("login",!0)}bw.ie&&$("input[type=file]").keydown(function(a){a.keyCode=="13"&&a.preventDefault()}); -this.loaded=!0;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);this.triggerEvent("init",{task:this.task,action:this.env.action});for(var d in this.onloads)if(typeof this.onloads[d]==="string")eval(this.onloads[d]);else if(typeof this.onloads[d]==="function")this.onloads[d]();this.start_keepalive()}};this.log=function(a){window.console&&console.log&& -console.log(a)};this.command=function(a,b,d){d&&d.blur&&d.blur();if(this.busy)return!1;if(!this.commands[a])return this.is_framed()&&parent.rcmail.command(a,b),!1;if(this.task=="mail"&&this.env.action=="compose"&&$.inArray(a,this.env.compose_commands)<0&&this.cmp_hash!=this.compose_field_hash()&&!confirm(this.get_label("notsentwarning")))return!1;if(typeof this.command_handlers[a]==="function"){var e=this.command_handlers[a](b,d);return e!==void 0?e:d?!1:!0}else if(typeof this.command_handlers[a]=== -"string")return e=window[this.command_handlers[a]](b,d),e!==void 0?e:d?!1:!0;this.triggerEvent("actionbefore",{props:b,action:a});e=this.triggerEvent("before"+a,b);if(e!==void 0)if(e===!1)return!1;else b=e;switch(a){case "login":this.gui_objects.loginform&&this.gui_objects.loginform.submit();break;case "mail":case "addressbook":case "settings":case "logout":this.switch_task(a);break;case "permaurl":if(d&&d.href&&d.target)return!0;else if(this.env.permaurl)parent.location.href=this.env.permaurl;break; -case "menu-open":case "menu-save":return this.triggerEvent(a,{props:b}),!1;case "open":var f;if(f=this.get_single_uid())return d.href="?_task="+this.env.task+"&_action=show&_mbox="+urlencode(this.env.mailbox)+"&_uid="+f,!0;break;case "list":this.task=="mail"?((!this.env.search_request||b&&b!=this.env.mailbox)&&this.reset_qsearch(),this.list_mailbox(b),this.env.trash_mailbox&&!this.env.flag_for_deletion&&this.set_alttext("delete",this.env.mailbox!=this.env.trash_mailbox?"movemessagetotrash":"deletemessage")): -this.task=="addressbook"&&((!this.env.search_request||b!=this.env.source)&&this.reset_qsearch(),this.list_contacts(b),this.enable_command("add","import",this.env.writable_source));break;case "load-headers":this.load_headers(d);break;case "sort":var g;f=b;g=this.env.sort_col==f?this.env.sort_order=="ASC"?"DESC":"ASC":"ASC";this.set_list_sorting(f,g);this.list_mailbox("","",f+"_"+g);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":this.env.messagecount&&this.expunge_mailbox(this.env.mailbox);break;case "purge":case "empty-mailbox":this.env.messagecount&&this.purge_mailbox(this.env.mailbox);break;case "show":if(this.task=="mail"){if((f=this.get_single_uid())&&(!this.env.uid||f!=this.env.uid))this.env.mailbox==this.env.drafts_mailbox?this.goto_url("compose","_draft_uid="+f+"&_mbox="+urlencode(this.env.mailbox),!0):this.show_message(f)}else if(this.task=="addressbook"){var h= -b?b:this.get_single_cid();h&&!(this.env.action=="show"&&h==this.env.cid)&&this.load_contact(h,"show")}break;case "add":this.task=="addressbook"?this.load_contact(0,"add"):this.task=="settings"&&(this.identity_list.clear_selection(),this.load_identity(0,"add-identity"));break;case "edit":if(this.task=="addressbook"&&(h=this.get_single_cid()))this.load_contact(h,"edit");else if(this.task=="settings"&&b)this.load_identity(b,"edit-identity");else if(this.task=="mail"&&(h=this.get_single_uid()))g=this.env.mailbox== -this.env.drafts_mailbox?"_draft_uid=":"_uid=",this.goto_url("compose",g+h+"&_mbox="+urlencode(this.env.mailbox),!0);break;case "save":var k;if(g=this.gui_objects.editform){if(this.env.action!="search")if((k=$("input[name='_pagesize']",g))&&k.length&&isNaN(parseInt(k.val()))){alert(this.get_label("nopagesizewarning"));k.focus();break}else{if(b=="reload")g.action+="?_reload=1";else if(this.task=="settings"&&this.env.identities_level%2==0&&(k=$("input[name='_email']",g))&&k.length&&!rcube_check_email(k.val())){alert(this.get_label("noemailwarning")); -k.focus();break}$("input.placeholder").each(function(){if(this.value==this._placeholder)this.value=""})}if(parent.rcmail&&parent.rcmail.env.source)g.action=this.add_url(g.action,"_orig_source",parent.rcmail.env.source);g.submit()}break;case "delete":this.task=="mail"?this.delete_messages():this.task=="addressbook"?this.delete_contacts():this.task=="settings"&&this.delete_identity();break;case "move":case "moveto":this.task=="mail"?this.move_messages(b):this.task=="addressbook"&&this.drag_active&& -this.copy_contact(null,b);break;case "copy":this.task=="mail"&&this.copy_messages(b);break;case "mark":b&&this.mark_message(b);break;case "toggle_status":if(b&&!b._row)break;g="read";if(b._row.uid)f=b._row.uid,this.message_list.rows[f].deleted?g="undelete":this.message_list.rows[f].unread||(g="unread");this.mark_message(g,f);break;case "toggle_flag":if(b&&!b._row)break;g="flagged";if(b._row.uid)f=b._row.uid,this.message_list.rows[f].flagged&&(g="unflagged");this.mark_message(g,f);break;case "always-load":if(this.env.uid&& -this.env.sender){this.add_contact(urlencode(this.env.sender));window.setTimeout(function(){l.command("load-images")},300);break}case "load-images":this.env.uid&&this.show_message(this.env.uid,!0,this.env.action=="preview");break;case "load-attachment":g="_mbox="+urlencode(this.env.mailbox)+"&_uid="+this.env.uid+"&_part="+b.part;if(this.env.uid&&b.mimetype&&this.env.mimetypes&&$.inArray(b.mimetype,this.env.mimetypes)>=0&&(b.mimetype=="text/html"&&(g+="&_safe=1"),this.attachment_win=window.open(this.env.comm_path+ -"&_action=get&"+g+"&_frame=1","rcubemailattachment"))){window.setTimeout(function(){l.attachment_win.focus()},10);break}this.goto_url("get",g+"&_download=1",!1);break;case "select-all":this.select_all_mode=b?!1:!0;this.dummy_select=!0;b=="invert"?this.message_list.invert_selection():this.message_list.select_all(b=="page"?"":b);this.dummy_select=null;break;case "select-none":this.select_all_mode=!1;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":this.env.next_uid&&this.show_message(this.env.next_uid,!1,this.env.action=="preview");break;case "lastmessage":this.env.last_uid&&this.show_message(this.env.last_uid);break;case "previousmessage":this.env.prev_uid&&this.show_message(this.env.prev_uid,!1,this.env.action=="preview"); -break;case "firstmessage":this.env.first_uid&&this.show_message(this.env.first_uid);break;case "checkmail":this.check_for_recent(!0);break;case "compose":g=this.env.comm_path+"&_action=compose";if(this.task=="mail")if(g+="&_mbox="+urlencode(this.env.mailbox),this.env.mailbox==this.env.drafts_mailbox){if(f=this.get_single_uid())g+="&_draft_uid="+f}else b&&(g+="&_to="+urlencode(b));else if(this.task=="addressbook"){if(b&&b.indexOf("@")>0){g=this.get_task_url("mail",g);this.redirect(g+"&_to="+urlencode(b)); -break}h=[];if(b)h.push(b);else if(this.contact_list){k=this.contact_list.get_selection();for(g=0,f=k.length;g<f;g++)h.push(k[g])}h.length&&this.http_post("mailto",{_cid:h.join(","),_source:this.env.source},!0);break}this.redirect(g);break;case "spellcheck":window.tinyMCE&&tinyMCE.get(this.env.composebody)?tinyMCE.execCommand("mceSpellCheck",!0):this.env.spellcheck&&this.env.spellcheck.spellCheck&&this.spellcheck_ready&&(this.env.spellcheck.spellCheck(),this.set_spellcheck_state("checking"));break; -case "savedraft":self.clearTimeout(this.save_timer);if(!this.gui_objects.messageform)break;if(!this.env.drafts_mailbox||this.cmp_hash==this.compose_field_hash())break;g=this.gui_objects.messageform;f=this.set_busy(!0,"savingmessage");g.target="savetarget";g._draft.value="1";g.action=this.add_url(g.action,"_unlock",f);g.submit();break;case "send":if(!this.gui_objects.messageform)break;if(!this.check_compose_input())break;self.clearTimeout(this.save_timer);h=this.spellcheck_lang();g=this.gui_objects.messageform; -f=this.set_busy(!0,"sendingmessage");g.target="savetarget";g._draft.value="";g.action=this.add_url(g.action,"_unlock",f);g.action=this.add_url(g.action,"_lang",h);g.submit();clearTimeout(this.request_timer);break;case "send-attachment":self.clearTimeout(this.save_timer);this.upload_file(b);break;case "insert-sig":this.change_identity($("[name='_from']")[0],!0);break;case "reply-all":case "reply-list":case "reply":if(f=this.get_single_uid())g="_reply_uid="+f+"&_mbox="+urlencode(this.env.mailbox),a== -"reply-all"?g+="&_all="+(!b&&this.commands["reply-list"]?"list":"all"):a=="reply-list"&&(g+="&_all=list"),this.goto_url("compose",g,!0);break;case "forward-attachment":case "forward":if(f=this.get_single_uid()){g="_forward_uid="+f+"&_mbox="+urlencode(this.env.mailbox);if(a=="forward-attachment"||!b&&this.env.forward_attachment)g+="&_attachment=1";this.goto_url("compose",g,!0)}break;case "print":if(f=this.get_single_uid())l.printwin=window.open(this.env.comm_path+"&_action=print&_uid="+f+"&_mbox="+ -urlencode(this.env.mailbox)+(this.env.safemode?"&_safe=1":"")),this.printwin&&(window.setTimeout(function(){l.printwin.focus()},20),this.env.action!="show"&&this.mark_message("read",f));break;case "viewsource":if(f=this.get_single_uid())l.sourcewin=window.open(this.env.comm_path+"&_action=viewsource&_uid="+f+"&_mbox="+urlencode(this.env.mailbox)),this.sourcewin&&window.setTimeout(function(){l.sourcewin.focus()},20);break;case "download":(f=this.get_single_uid())&&this.goto_url("viewsource","&_uid="+ -f+"&_mbox="+urlencode(this.env.mailbox)+"&_save=1");break;case "search":if(!b&&this.gui_objects.qsearchbox)b=this.gui_objects.qsearchbox.value;if(b){this.qsearch(b);break}case "reset-search":f=this.env.search_request||this.env.qsearch;this.reset_qsearch();this.select_all_mode=!1;if(f&&this.env.mailbox)this.list_mailbox(this.env.mailbox,1);else if(f&&this.task=="addressbook"){if(this.env.source==""){for(g in this.env.address_sources)break;this.env.source=g;this.env.group=""}this.list_contacts(this.env.source, -this.env.group,1)}break;case "listgroup":this.list_contacts(b.source,b.id);break;case "import":if(this.env.action=="import"&&this.gui_objects.importform){if((g=document.getElementById("rcmimportfile"))&&!g.value){alert(this.get_label("selectimportfile"));break}this.gui_objects.importform.submit();this.set_busy(!0,"importwait");this.lock_form(this.gui_objects.importform,!0)}else this.goto_url("import",this.env.source?"_target="+urlencode(this.env.source)+"&":"");break;case "export":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(b);break;case "delete-photo":this.replace_contact_photo("-del-");break;case "preferences":case "identities":case "folders":this.goto_url("settings/"+a);break;case "undo":this.http_request("undo","",this.display_message("","loading"));break;default:if(g=a.replace(/-/g,"_"),this[g]&&typeof this[g]==="function")this[g](b)}this.triggerEvent("after"+ -a,b);this.triggerEvent("actionafter",{props:b,action:a});return d?!1:!0};this.enable_command=function(){for(var a=Array.prototype.slice.call(arguments),b=a.pop(),d,e=0;e<a.length;e++)if(d=a[e],typeof d==="string")this.commands[d]=b,this.set_button(d,b?"act":"pas");else for(var f in d)a.push(d[f])};this.set_busy=function(a,b,d){a&&b?(d=this.get_label(b),d==b&&(d="Loading..."),d=this.display_message(d,"loading")):!a&&d&&this.hide_message(d);this.busy=a;this.gui_objects.editform&&this.lock_form(this.gui_objects.editform, -a);this.request_timer&&clearTimeout(this.request_timer);if(a&&this.env.request_timeout)this.request_timer=window.setTimeout(function(){l.request_timed_out()},this.env.request_timeout*1E3);return d};this.gettext=this.get_label=function(a,b){return b&&this.labels[b+"."+a]?this.labels[b+"."+a]:this.labels[a]?this.labels[a]:a};this.switch_task=function(a){if(!(this.task===a&&a!="mail")){var b=this.get_task_url(a);a=="mail"&&(b+="&_mbox=INBOX");this.redirect(b)}};this.get_task_url=function(a,b){if(!b)b= -this.env.comm_path;return b.replace(/_task=[a-z]+/,"_task="+a)};this.request_timed_out=function(){this.set_busy(!1);this.display_message("Request timed out!","error")};this.reload=function(a){if(this.is_framed())parent.rcmail.reload(a);else if(a)window.setTimeout(function(){rcmail.reload()},a);else if(window.location)location.href=this.env.comm_path+(this.env.action?"&_action="+this.env.action:"")};this.add_url=function(a,b,d){d=urlencode(d);if(/(\?.*)$/.test(a)){var e=RegExp.$1,f=RegExp("((\\?|&)"+ -RegExp.escape(b)+"=[^&]*)");f.test(e)?e=e.replace(f,RegExp.$2+b+"="+d):e+="&"+b+"="+d;return a.replace(/(\?.*)$/,e)}else return a+"?"+b+"="+d};this.is_framed=function(){return this.env.framed&&parent.rcmail&&parent.rcmail!=this&&parent.rcmail.command};this.save_pref=function(a){var b={_name:a.name,_value:a.value};if(a.session)b._session=a.session;if(a.env)this.env[a.env]=a.value;this.http_post("save-pref",b)};this.drag_menu=function(a,b){var d=rcube_event.get_modifier(a),e=this.gui_objects.message_dragmenu; -return e&&d==SHIFT_KEY&&this.commands.copy?(d=rcube_event.get_mouse_pos(a),this.env.drag_target=b,$(e).css({top:d.y-10+"px",left:d.x-10+"px"}).show(),!0):!1};this.drag_menu_action=function(a){var b=this.gui_objects.message_dragmenu;b&&$(b).hide();this.command(a,this.env.drag_target);this.env.drag_target=null};this.drag_start=function(a){var b=this.task=="mail"?this.env.mailboxes:this.env.contactfolders;this.drag_active=!0;this.preview_timer&&clearTimeout(this.preview_timer);this.preview_read_timer&& -clearTimeout(this.preview_read_timer);if(this.gui_objects.folderlist&&b){this.initialBodyScrollTop=bw.ie?0:window.pageYOffset;this.initialListScrollTop=this.gui_objects.folderlist.parentNode.scrollTop;var d,e,a=$(this.gui_objects.folderlist);d=a.offset();this.env.folderlist_coords={x1:d.left,y1:d.top,x2:d.left+a.width(),y2:d.top+a.height()};this.env.folder_coords=[];for(var f in b)if(a=this.get_folder_li(f))if(e=a.firstChild.offsetHeight)d=$(a.firstChild).offset(),this.env.folder_coords[f]={x1:d.left, -y1:d.top,x2:d.left+a.firstChild.offsetWidth,y2:d.top+e,on:0}}};this.drag_end=function(){this.drag_active=!1;this.env.last_folder_target=null;if(this.folder_auto_timer)window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=this.folder_auto_timer=null;if(this.gui_objects.folderlist&&this.env.folder_coords)for(var a in this.env.folder_coords)this.env.folder_coords[a].on&&$(this.get_folder_li(a)).removeClass("droptarget")};this.drag_move=function(a){if(this.gui_objects.folderlist&&this.env.folder_coords){var b= --(this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop)-(bw.ie?-document.documentElement.scrollTop:this.initialBodyScrollTop),d,e,f;d="draglayernormal";this.contact_list&&this.contact_list.draglayer&&(f=this.contact_list.draglayer.attr("class"));a=rcube_event.get_mouse_pos(a);e=this.env.folderlist_coords;a.y+=b;if(a.x<e.x1||a.x>=e.x2||a.y<e.y1||a.y>=e.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}else for(var g in this.env.folder_coords)if(e=this.env.folder_coords[g],a.x>=e.x1&&a.x<e.x2&&a.y>=e.y1&&a.y<e.y2)if(b=this.check_droptarget(g)){d=this.get_folder_li(g);e=$(d.getElementsByTagName("div")[0]);if(e.hasClass("collapsed"))this.folder_auto_timer&&window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=g,this.folder_auto_timer=window.setTimeout(function(){rcmail.command("collapse-folder",rcmail.folder_auto_expand);rcmail.drag_start(null)},1E3); -else if(this.folder_auto_timer)window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=this.folder_auto_timer=null;$(d).addClass("droptarget");this.env.folder_coords[g].on=1;this.env.last_folder_target=g;d="draglayer"+(b>1?"copy":"normal")}else this.env.last_folder_target=null;else if(e.on)$(this.get_folder_li(g)).removeClass("droptarget"),this.env.folder_coords[g].on=0;d!=f&&this.contact_list&&this.contact_list.draglayer&&this.contact_list.draglayer.attr("class",d)}};this.collapse_folder= -function(a){var b=this.get_folder_li(a),d=$(b.getElementsByTagName("div")[0]);if(d&&(d.hasClass("collapsed")||d.hasClass("expanded"))){var e=$(b.getElementsByTagName("ul")[0]);d.hasClass("collapsed")?(e.show(),d.removeClass("collapsed").addClass("expanded"),this.env.collapsed_folders=this.env.collapsed_folders.replace(RegExp("&"+urlencode(a)+"&"),"")):(e.hide(),d.removeClass("expanded").addClass("collapsed"),this.env.collapsed_folders=this.env.collapsed_folders+"&"+urlencode(a)+"&",this.env.mailbox.indexOf(a+ -this.env.delimiter)==0&&this.command("list",a));if(bw.ie6||bw.ie7)if((d=b.nextSibling?b.nextSibling.getElementsByTagName("ul"):null)&&d.length&&(b=d[0])&&b.style&&b.style.display!="none")b.style.display="none",b.style.display="";this.command("save-pref",{name:"collapsed_folders",value:this.env.collapsed_folders});this.set_unread_count_display(a,!1)}};this.doc_mouse_up=function(a){var b,d,e;(d=this.message_list)?(rcube_mouse_is_over(a,d.list.parentNode)?d.focus():d.blur(),b=this.env.mailboxes):(d= -this.contact_list)?(rcube_mouse_is_over(a,d.list.parentNode)?d.focus():d.blur(),b=this.env.contactfolders):this.ksearch_value&&this.ksearch_blur();if(this.drag_active&&b&&this.env.last_folder_target)b=b[this.env.last_folder_target],$(this.get_folder_li(this.env.last_folder_target)).removeClass("droptarget"),this.env.last_folder_target=null,d.draglayer.hide(),this.drag_menu(a,b)||this.command("moveto",b);if(this.buttons_sel){for(e in this.buttons_sel)typeof e!=="function"&&this.button_out(this.buttons_sel[e], -e);this.buttons_sel={}}};this.click_on_list=function(){this.gui_objects.qsearchbox&&this.gui_objects.qsearchbox.blur();this.message_list?this.message_list.focus():this.contact_list&&this.contact_list.focus();return!0};this.msglist_select=function(a){this.preview_timer&&clearTimeout(this.preview_timer);this.preview_read_timer&&clearTimeout(this.preview_read_timer);var b=a.get_single_selection()!=null;this.enable_command(this.env.message_commands,b);b&&(this.env.mailbox==this.env.drafts_mailbox?this.enable_command("reply", -"reply-all","reply-list","forward","forward-attachment",!1):this.env.messages[a.get_single_selection()].ml||this.enable_command("reply-list",!1));this.enable_command("delete","moveto","copy","mark",a.selection.length>0?!0:!1);if(b||a.selection.length&&a.selection.length!=a.rowcount)this.select_all_mode=!1;b&&this.env.contentframe&&!a.multi_selecting&&!this.dummy_select?this.preview_timer=window.setTimeout(function(){l.msglist_get_preview()},200):this.env.contentframe&&this.show_contentframe(!1)}; -this.msglist_click=function(a){if(!a.multi_selecting&&this.env.contentframe&&a.get_single_selection()&&window.frames&&window.frames[this.env.contentframe]&&window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)>=0)this.preview_timer&&clearTimeout(this.preview_timer),this.preview_read_timer&&clearTimeout(this.preview_read_timer),this.preview_timer=window.setTimeout(function(){l.msglist_get_preview()},200)};this.msglist_dbl_click=function(a){this.preview_timer&&clearTimeout(this.preview_timer); -this.preview_read_timer&&clearTimeout(this.preview_read_timer);(a=a.get_single_selection())&&this.env.mailbox==this.env.drafts_mailbox?this.goto_url("compose","_draft_uid="+a+"&_mbox="+urlencode(this.env.mailbox),!0):a&&this.show_message(a,!1,!1)};this.msglist_keypress=function(a){a.key_pressed==a.ENTER_KEY?this.command("show"):a.key_pressed==a.DELETE_KEY?this.command("delete"):a.key_pressed==a.BACKSPACE_KEY?this.command("delete"):a.key_pressed==33?this.command("previouspage"):a.key_pressed==34&& -this.command("nextpage")};this.msglist_get_preview=function(){var a=this.get_single_uid();a&&this.env.contentframe&&!this.drag_active?this.show_message(a,!1,!0):this.env.contentframe&&this.show_contentframe(!1)};this.msglist_expand=function(a){if(this.env.messages[a.uid])this.env.messages[a.uid].expanded=a.expanded};this.msglist_set_coltypes=function(a){var b,d=a.list.tHead.rows[0].cells;this.env.coltypes=[];for(a=0;a<d.length;a++)d[a].id&&d[a].id.match(/^rcm/)&&(b=d[a].id.replace(/^rcm/,""),this.env.coltypes.push(b== -"to"?"from":b));if((a=$.inArray("flag",this.env.coltypes))>=0)this.env.flagged_col=a;if((a=$.inArray("subject",this.env.coltypes))>=0)this.env.subject_col=a;this.command("save-pref",{name:"list_cols",value:this.env.coltypes,session:"list_attrib/columns"})};this.check_droptarget=function(a){var b=!1,d=!1;if(this.task=="mail")b=this.env.mailboxes[a]&&this.env.mailboxes[a].id!=this.env.mailbox&&!this.env.mailboxes[a].virtual;else if(this.task=="settings")b=a!=this.env.mailbox;else if(this.task=="addressbook"&& -a!=this.env.source&&this.env.contactfolders[a])this.env.contactfolders[a].type=="group"?(d=this.env.contactfolders[a].source,b=this.env.contactfolders[a].id!=this.env.group&&!this.env.contactfolders[d].readonly,d=d!=this.env.source):(b=!this.env.contactfolders[a].readonly,d=!0);return b?d?2:1:0};this.init_message_row=function(a){var b,d=this,e=a.uid,f=(this.env.status_col!=null?"status":"msg")+"icn"+a.uid;e&&this.env.messages[e]&&$.extend(a,this.env.messages[e]);if(a.icon=document.getElementById(f))a.icon._row= -a.obj,a.icon.onmousedown=function(a){d.command("toggle_status",this);rcube_event.cancel(a)};a.msgicon=this.env.status_col!=null?document.getElementById("msgicn"+a.uid):a.icon;if(this.env.flagged_col!=null&&(a.flagicon=document.getElementById("flagicn"+a.uid)))a.flagicon._row=a.obj,a.flagicon.onmousedown=function(a){d.command("toggle_flag",this);rcube_event.cancel(a)};if(!a.depth&&a.has_children&&(b=document.getElementById("rcmexpando"+a.uid)))a.expando=b,b.onmousedown=function(a){return d.expand_message_row(a, -e)};this.triggerEvent("insertrow",{uid:e,row:a})};this.add_message_row=function(a,b,d,e){if(!this.gui_objects.messagelist||!this.message_list)return!1;this.env.messages[a]||(this.env.messages[a]={});$.extend(this.env.messages[a],{deleted:d.deleted?1:0,replied:d.replied?1:0,unread:d.unread?1:0,forwarded:d.forwarded?1:0,flagged:d.flagged?1:0,has_children:d.has_children?1:0,depth:d.depth?d.depth:0,unread_children:d.unread_children?d.unread_children:0,parent_uid:d.parent_uid?d.parent_uid:0,selected:this.select_all_mode|| -this.message_list.in_selection(a),ml:d.ml?1:0,ctype:d.ctype,flags:d.extra_flags});var f,g=expando="",h=this.message_list,k=h.rows;f=this.env.messages[a];var j="message"+(this.gui_objects.messagelist.tBodies[0].rows.length%2?" even":" odd")+(d.unread?" unread":"")+(d.deleted?" deleted":"")+(d.flagged?" flagged":"")+(d.unread_children&&!d.unread&&!this.env.autoexpand_threads?" unroot":"")+(f.selected?" selected":""),l=document.createElement("tr"),m=document.createElement("td");l.id="rcmrow"+a;l.className= -j;j="msgicon";this.env.status_col===null&&(j+=" status",d.deleted?j+=" deleted":d.unread?j+=" unread":d.unread_children>0&&(j+=" unreadchildren"));d.replied&&(j+=" replied");d.forwarded&&(j+=" forwarded");f.selected&&!h.in_selection(a)&&h.selection.push(a);if(this.env.threading){m=f.depth*15;if(f.depth)k[f.parent_uid]&&k[f.parent_uid].expanded===!1||(this.env.autoexpand_threads==0||this.env.autoexpand_threads==2)&&(!k[f.parent_uid]||!k[f.parent_uid].expanded)?(l.style.display="none",f.expanded=!1): -f.expanded=!0;else if(f.has_children&&f.expanded===void 0&&(this.env.autoexpand_threads==1||this.env.autoexpand_threads==2&&f.unread_children))f.expanded=!0;m&&(g+='<span id="rcmtab'+a+'" class="branch" style="width:'+m+'px;"> </span>');f.has_children&&!f.depth&&(expando='<div id="rcmexpando'+a+'" class="'+(f.expanded?"expanded":"collapsed")+'"> </div>')}g+='<span id="msgicn'+a+'" class="'+j+'"> </span>';if(!bw.ie&&b.subject)m=d.mbox==this.env.drafts_mailbox?"_draft_uid": -"_uid",b.subject='<a href="./?_task=mail&_action='+(d.mbox==this.env.drafts_mailbox?"compose":"show")+"&_mbox="+urlencode(d.mbox)+"&"+m+"="+a+'" onclick="return rcube_event.cancel(event)" onmouseover="rcube_webmail.long_subject_title(this,'+(f.depth+1)+')">'+b.subject+"</a>";for(var n in this.env.coltypes)f=this.env.coltypes[n],m=document.createElement("td"),m.className=String(f).toLowerCase(),f=="flag"?(j=d.flagged?"flagged":"unflagged",f='<span id="flagicn'+a+'" class="'+j+'"> </span>'):f== -"attachment"?f=/application\/|multipart\/m/.test(d.ctype)?'<span class="attachment"> </span>':/multipart\/report/.test(d.ctype)?'<span class="report"> </span>':" ":f=="status"?(j=d.deleted?"deleted":d.unread?"unread":d.unread_children>0?"unreadchildren":"msgicon",f='<span id="statusicn'+a+'" class="'+j+'"> </span>'):f=f=="threads"?expando:f=="subject"?g+b[f]:b[f],m.innerHTML=f,l.appendChild(m);h.insert_row(l,e);e&&this.env.pagesize&&h.rowcount>this.env.pagesize&&(a=h.get_last_row(), -h.remove_row(a),h.clear_selection(a))};this.set_list_sorting=function(a,b){$("#rcm"+this.env.sort_col).removeClass("sorted"+this.env.sort_order.toUpperCase());a&&$("#rcm"+a).addClass("sorted"+b);this.env.sort_col=a;this.env.sort_order=b};this.set_list_options=function(a,b,d,e){var f,g="";if(b===void 0)b=this.env.sort_col;if(!d)d=this.env.sort_order;if(this.env.sort_col!=b||this.env.sort_order!=d)f=1,this.set_list_sorting(b,d);this.env.threading!=e&&(f=1,g+="&_threads="+e);if(a&&a.length){for(var h, -k,j=[],l=this.env.coltypes,e=0;e<l.length;e++)k=l[e]=="to"?"from":l[e],h=$.inArray(k,a),h!=-1&&(j.push(k),delete a[h]);for(e=0;e<a.length;e++)a[e]&&j.push(a[e]);j.join()!=l.join()&&(f=1,g+="&_cols="+j.join(","))}f&&this.list_mailbox("","",b+"_"+d,g)};this.show_message=function(a,b,d){if(a){var e=window,f=d?"preview":"show",g="&_action="+f+"&_uid="+a+"&_mbox="+urlencode(this.env.mailbox);d&&this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(e=window.frames[this.env.contentframe], -g+="&_framed=1");b&&(g+="&_safe=1");this.env.search_request&&(g+="&_search="+this.env.search_request);if(f=="preview"&&String(e.location.href).indexOf(g)>=0)this.show_contentframe(!0);else if(this.location_href(this.env.comm_path+g,e,!0),f=="preview"&&this.message_list&&this.message_list.rows[a]&&this.message_list.rows[a].unread&&this.env.preview_pane_mark_read>=0)this.preview_read_timer=window.setTimeout(function(){l.set_message(a,"unread",!1);l.update_thread_root(a,"read");l.env.unread_counts[l.env.mailbox]&& -(l.env.unread_counts[l.env.mailbox]-=1,l.set_unread_count(l.env.mailbox,l.env.unread_counts[l.env.mailbox],l.env.mailbox=="INBOX"));l.env.preview_pane_mark_read>0&&l.http_post("mark","_uid="+a+"&_flag=read&_quiet=1")},this.env.preview_pane_mark_read*1E3)}};this.show_contentframe=function(a){var b,d;if(this.env.contentframe&&(b=$("#"+this.env.contentframe))&&b.length)if(!a&&(d=window.frames[this.env.contentframe])){if(d.location&&d.location.href.indexOf(this.env.blankpage)<0)d.location.href=this.env.blankpage}else if(!bw.safari&& -!bw.konq)b[a?"show":"hide"]();!a&&this.busy&&this.set_busy(!1,null,this.env.frame_lock)};this.lock_frame=function(){if(!this.env.frame_lock)(this.is_framed()?parent.rcmail:this).env.frame_lock=this.set_busy(!0,"loading")};this.list_page=function(a){a=="next"?a=this.env.current_page+1:a=="last"?a=this.env.pagecount:a=="prev"&&this.env.current_page>1?a=this.env.current_page-1:a=="first"&&this.env.current_page>1&&(a=1);if(a>0&&a<=this.env.pagecount)this.env.current_page=a,this.task=="mail"?this.list_mailbox(this.env.mailbox, -a):this.task=="addressbook"&&this.list_contacts(this.env.source,this.env.group,a)};this.filter_mailbox=function(a){var b,d=this.set_busy(!0,"searching");if(this.gui_objects.qsearchbox)b=this.gui_objects.qsearchbox.value;this.clear_message_list();this.env.current_page=1;this.http_request("search","_filter="+a+(b?"&_q="+urlencode(b):"")+(this.env.mailbox?"&_mbox="+urlencode(this.env.mailbox):""),d)};this.list_mailbox=function(a,b,d,e){var f="",g=window;a||(a=this.env.mailbox?this.env.mailbox:"INBOX"); -e&&(f+=e);d&&(f+="&_sort="+d);this.env.search_request&&(f+="&_search="+this.env.search_request);if(this.env.mailbox!=a)b=1,this.env.current_page=b,this.select_all_mode=!1;this.clear_message_list();if(a!=this.env.mailbox||a==this.env.mailbox&&!b&&!d)f+="&_refresh=1";this.select_folder(a,this.env.mailbox);this.env.mailbox=a;this.gui_objects.messagelist?this.list_mailbox_remote(a,b,f):(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(g=window.frames[this.env.contentframe], -f+="&_framed=1"),a&&(this.set_busy(!0,"loading"),this.location_href(this.env.comm_path+"&_mbox="+urlencode(a)+(b?"&_page="+b:"")+f,g)))};this.clear_message_list=function(){this.env.messages={};this.last_selected=0;this.show_contentframe(!1);this.message_list&&this.message_list.clear(!0)};this.list_mailbox_remote=function(a,b,d){this.message_list.clear();a="_mbox="+urlencode(a)+(b?"&_page="+b:"");b=this.set_busy(!0,"loading");this.http_request("list",a+d,b)};this.update_selection=function(){var a= -this.message_list.selection,b=this.message_list.rows,d,e=[];for(d in a)b[a[d]]&&e.push(a[d]);this.message_list.selection=e};this.expand_unread=function(){for(var a,b=this.gui_objects.messagelist.tBodies[0].firstChild;b;){if(b.nodeType==1&&(a=this.message_list.rows[b.uid])&&a.unread_children)this.message_list.expand_all(a),this.set_unread_children(a.uid);b=b.nextSibling}return!1};this.expand_message_row=function(a,b){var d=this.message_list.rows[b];d.expanded=!d.expanded;this.set_unread_children(b); -d.expanded=!d.expanded;this.message_list.expand_row(a,b)};this.expand_threads=function(){if(this.env.threading&&this.env.autoexpand_threads&&this.message_list)switch(this.env.autoexpand_threads){case 2:this.expand_unread();break;case 1:this.message_list.expand_all()}};this.init_threads=function(a){for(var b=0,d=a.length;b<d;b++)this.add_tree_icons(a[b]);this.expand_threads()};this.add_tree_icons=function(a){var b,d,e,f,g=[],h=[],k,j=this.message_list.rows;for(k=a?j[a]?j[a].obj:null:this.message_list.list.tBodies[0].firstChild;k;){if(k.nodeType== -1&&(d=j[k.uid]))if(d.depth){for(b=g.length-1;b>=0;b--)if(e=g[b].length,e>d.depth?(f=e-d.depth,g[b][f]&2||(g[b][f]=g[b][f]?g[b][f]+2:2)):e==d.depth&&(g[b][0]&2||(g[b][0]+=2)),d.depth>e)break;g.push(Array(d.depth));g[g.length-1][0]=1;h.push(d.uid)}else{if(g.length){for(b in g)this.set_tree_icons(h[b],g[b]);g=[];h=[]}if(a&&k!=j[a].obj)break}k=k.nextSibling}if(g.length)for(b in g)this.set_tree_icons(h[b],g[b])};this.set_tree_icons=function(a,b){var d,e=[],f="",g=b.length;for(d=0;d<g;d++)b[d]>2?e.push({"class":"l3", -width:15}):b[d]>1?e.push({"class":"l2",width:15}):b[d]>0?e.push({"class":"l1",width:15}):e.length&&!e[e.length-1]["class"]?e[e.length-1].width+=15:e.push({"class":null,width:15});for(d=e.length-1;d>=0;d--)f+=e[d]["class"]?'<div class="tree '+e[d]["class"]+'" />':'<div style="width:'+e[d].width+'px" />';f&&$("#rcmtab"+a).html(f)};this.update_thread_root=function(a,b){if(this.env.threading){var d=this.message_list.find_root(a);if(a!=d){var e=this.message_list.rows[d];if(b=="read"&&e.unread_children)e.unread_children--; -else if(b=="unread"&&e.has_children)e.unread_children=e.unread_children?e.unread_children+1:1;else return;this.set_message_icon(d);this.set_unread_children(d)}}};this.update_thread=function(a){if(!this.env.threading)return 0;var b,d=0,e=this.message_list.rows,f=e[a],g=e[a].depth,h=[];f.depth?f.unread&&(a=this.message_list.find_root(a),e[a].unread_children--,this.set_unread_children(a)):d--;a=f.parent_uid;for(f=f.obj.nextSibling;f;){if(f.nodeType==1&&(b=e[f.uid])){if(!b.depth||b.depth<=g)break;b.depth--; -$("#rcmtab"+b.uid).width(b.depth*15).html("");if(b.depth){if(b.depth==g)b.parent_uid=a;b.unread&&h.length&&h[h.length-1].unread_children++}else{d++;b.parent_uid=0;if(b.has_children)$("#rcmrow"+b.uid+" .leaf:first").attr("id","rcmexpando"+b.uid).attr("class",b.obj.style.display!="none"?"expanded":"collapsed").bind("mousedown",{uid:b.uid,p:this},function(a){return a.data.p.expand_message_row(a,a.data.uid)}),b.unread_children=0,h.push(b);b.obj.style.display=="none"&&$(b.obj).show()}}f=f.nextSibling}for(b= -0;b<h.length;b++)this.set_unread_children(h[b].uid);return d};this.delete_excessive_thread_rows=function(){for(var a=this.message_list.rows,b=this.message_list.list.tBodies[0].firstChild,d=this.env.pagesize+1;b;){if(b.nodeType==1&&(r=a[b.uid]))!r.depth&&d&&d--,d||this.message_list.remove_row(b.uid);b=b.nextSibling}};this.set_message_icon=function(a){var b=this.message_list.rows[a];if(!b)return!1;if(b.icon)a="msgicon",b.deleted?a+=" deleted":b.unread?a+=" unread":b.unread_children&&(a+=" unreadchildren"), -b.msgicon==b.icon&&(b.replied&&(a+=" replied"),b.forwarded&&(a+=" forwarded"),a+=" status"),b.icon.className=a;if(b.msgicon&&b.msgicon!=b.icon)a="msgicon",!b.unread&&b.unread_children&&(a+=" unreadchildren"),b.replied&&(a+=" replied"),b.forwarded&&(a+=" forwarded"),b.msgicon.className=a;if(b.flagicon)a=b.flagged?"flagged":"unflagged",b.flagicon.className=a};this.set_message_status=function(a,b,d){a=this.message_list.rows[a];if(!a)return!1;if(b=="unread")a.unread=d;else if(b=="deleted")a.deleted=d; -else if(b=="replied")a.replied=d;else if(b=="forwarded")a.forwarded=d;else if(b=="flagged")a.flagged=d};this.set_message=function(a,b,d){var e=this.message_list.rows[a];if(!e)return!1;b&&this.set_message_status(a,b,d);b=$(e.obj);e.unread&&!b.hasClass("unread")?b.addClass("unread"):!e.unread&&b.hasClass("unread")&&b.removeClass("unread");e.deleted&&!b.hasClass("deleted")?b.addClass("deleted"):!e.deleted&&b.hasClass("deleted")&&b.removeClass("deleted");e.flagged&&!b.hasClass("flagged")?b.addClass("flagged"): -!e.flagged&&b.hasClass("flagged")&&b.removeClass("flagged");this.set_unread_children(a);this.set_message_icon(a)};this.set_unread_children=function(a){a=this.message_list.rows[a];a.parent_uid||(!a.unread&&a.unread_children&&!a.expanded?$(a.obj).addClass("unroot"):$(a.obj).removeClass("unroot"))};this.copy_messages=function(a){if(a&&typeof a==="object")a=a.id;if(a&&!(a==this.env.mailbox||!this.env.uid&&(!this.message_list||!this.message_list.get_selection().length))){var b=[],d=this.display_message(this.get_label("copyingmessage"), -"loading"),a="&_target_mbox="+urlencode(a)+"&_from="+(this.env.action?this.env.action:"");if(this.env.uid)b[0]=this.env.uid;else{var e=this.message_list.get_selection(),f;for(f in e)b.push(e[f])}a+="&_uid="+this.uids_to_list(b);this.http_post("copy","_mbox="+urlencode(this.env.mailbox)+a,d)}};this.move_messages=function(a){if(a&&typeof a==="object")a=a.id;if(a&&!(a==this.env.mailbox||!this.env.uid&&(!this.message_list||!this.message_list.get_selection().length))){var b=!1,a="&_target_mbox="+urlencode(a)+ -"&_from="+(this.env.action?this.env.action:"");this.env.action=="show"?b=this.set_busy(!0,"movingmessage"):this.show_contentframe(!1);this.enable_command(this.env.message_commands,!1);this._with_selected_messages("moveto",b,a)}};this.delete_messages=function(){var a,b,d,e=this.env.trash_mailbox,f=this.message_list,g=f?$.merge([],f.get_selection()):[];if(this.env.uid||g.length){for(b=0,d=g.length;b<d;b++)a=g[b],f.rows[a].has_children&&!f.rows[a].expanded&&f.select_childs(a);if(this.env.flag_for_deletion)return this.mark_message("delete"), -!1;else!e||this.env.mailbox==e?this.permanently_remove_messages():f&&f.shiftkey?confirm(this.get_label("deletemessagesconfirm"))&&this.permanently_remove_messages():this.move_messages(e);return!0}};this.permanently_remove_messages=function(){if(this.env.uid||this.message_list&&this.message_list.get_selection().length)this.show_contentframe(!1),this._with_selected_messages("delete",!1,"&_from="+(this.env.action?this.env.action:""))};this._with_selected_messages=function(a,b,d){var e=[],f=0;if(this.env.uid)e[0]= -this.env.uid;else{var g,h,k,j=[],l=this.message_list.get_selection();for(g=0,len=l.length;g<len;g++)h=l[g],e.push(h),this.env.threading&&(f+=this.update_thread(h),k=this.message_list.find_root(h),k!=h&&$.inArray(k,j)<0&&j.push(k)),this.message_list.remove_row(h,this.env.display_next&&g==l.length-1);this.env.display_next||this.message_list.clear_selection();for(g=0,len=j.length;g<len;g++)this.add_tree_icons(j[g])}this.env.search_request&&(d+="&_search="+this.env.search_request);this.env.display_next&& -this.env.next_uid&&(d+="&_next_uid="+this.env.next_uid);f<0?d+="&_count="+f*-1:f>0&&this.delete_excessive_thread_rows();d+="&_uid="+this.uids_to_list(e);b||(b=this.display_message(this.get_label(a=="moveto"?"movingmessage":"deletingmessage"),"loading"));this.http_post(a,"_mbox="+urlencode(this.env.mailbox)+d,b)};this.mark_message=function(a,b){var d=[],e=[],f,g,h;h=this.message_list?this.message_list.get_selection():[];if(b)d[0]=b;else if(this.env.uid)d[0]=this.env.uid;else if(this.message_list)for(g= -0,f=h.length;g<f;g++)d.push(h[g]);if(this.message_list)for(g=0,f=d.length;g<f;g++)h=d[g],(a=="read"&&this.message_list.rows[h].unread||a=="unread"&&!this.message_list.rows[h].unread||a=="delete"&&!this.message_list.rows[h].deleted||a=="undelete"&&this.message_list.rows[h].deleted||a=="flagged"&&!this.message_list.rows[h].flagged||a=="unflagged"&&this.message_list.rows[h].flagged)&&e.push(h);else e=d;if(e.length||this.select_all_mode)switch(a){case "read":case "unread":this.toggle_read_status(a,e); -break;case "delete":case "undelete":this.toggle_delete_status(e);break;case "flagged":case "unflagged":this.toggle_flagged_status(a,d)}};this.toggle_read_status=function(a,b){var d,e=b.length,f="_uid="+this.uids_to_list(b)+"&_flag="+a,g=this.display_message(this.get_label("markingmessage"),"loading");for(d=0;d<e;d++)this.set_message(b[d],"unread",a=="unread"?!0:!1);this.env.search_request&&(f+="&_search="+this.env.search_request);this.http_post("mark",f,g);for(d=0;d<e;d++)this.update_thread_root(b[d], -a)};this.toggle_flagged_status=function(a,b){var d,e=b.length,f="_uid="+this.uids_to_list(b)+"&_flag="+a,g=this.display_message(this.get_label("markingmessage"),"loading");for(d=0;d<e;d++)this.set_message(b[d],"flagged",a=="flagged"?!0:!1);this.env.search_request&&(f+="&_search="+this.env.search_request);this.http_post("mark",f,g)};this.toggle_delete_status=function(a){var b=a.length,d,e,f=!0,g=this.message_list?this.message_list.rows:[];if(b==1)return!g.length||g[a[0]]&&!g[a[0]].deleted?this.flag_as_deleted(a): -this.flag_as_undeleted(a),!0;for(d=0;d<b;d++)if(e=a[d],g[e]&&!g[e].deleted){f=!1;break}f?this.flag_as_undeleted(a):this.flag_as_deleted(a);return!0};this.flag_as_undeleted=function(a){var b,d=a.length,e="_uid="+this.uids_to_list(a)+"&_flag=undelete",f=this.display_message(this.get_label("markingmessage"),"loading");for(b=0;b<d;b++)this.set_message(a[b],"deleted",!1);this.env.search_request&&(e+="&_search="+this.env.search_request);this.http_post("mark",e,f);return!0};this.flag_as_deleted=function(a){for(var b= -"",d=[],b=this.message_list?this.message_list.rows:[],e=0,f=0,g=a.length;f<g;f++)uid=a[f],b[uid]&&(b[uid].unread&&(d[d.length]=uid),this.env.skip_deleted?(e+=this.update_thread(uid),this.message_list.remove_row(uid,this.env.display_next&&f==this.message_list.selection.length-1)):this.set_message(uid,"deleted",!0));this.env.skip_deleted&&this.message_list&&(this.env.display_next||this.message_list.clear_selection(),e<0||e>0&&this.delete_excessive_thread_rows());b="&_from="+(this.env.action?this.env.action: -"");lock=this.display_message(this.get_label("markingmessage"),"loading");d.length&&(b+="&_ruid="+this.uids_to_list(d));this.env.skip_deleted&&this.env.display_next&&this.env.next_uid&&(b+="&_next_uid="+this.env.next_uid);this.env.search_request&&(b+="&_search="+this.env.search_request);this.http_post("mark","_uid="+this.uids_to_list(a)+"&_flag=delete"+b,lock);return!0};this.flag_deleted_as_read=function(a){var b,d,e,f=this.message_list?this.message_list.rows:[],a=String(a).split(",");for(d=0,e=a.length;d< -e;d++)b=a[d],f[b]&&this.set_message(b,"unread",!1)};this.uids_to_list=function(a){return this.select_all_mode?"*":a.join(",")};this.expunge_mailbox=function(a){var b,d="_mbox="+urlencode(a);a==this.env.mailbox&&(b=this.set_busy(!0,"loading"),d+="&_reload=1",this.env.search_request&&(d+="&_search="+this.env.search_request));this.http_post("expunge",d,b)};this.purge_mailbox=function(a){var b=!1,d="_mbox="+urlencode(a);if(!confirm(this.get_label("purgefolderconfirm")))return!1;a==this.env.mailbox&&(b= -this.set_busy(!0,"loading"),d+="&_reload=1");this.http_post("purge",d,b)};this.purge_mailbox_test=function(){return this.env.messagecount&&(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(a){var b=rcube_event.get_keycode(a),d=$("#rcmloginpwd"); -return b==13&&d.length&&!d.val()?(d.focus(),rcube_event.cancel(a)):!0};this.init_messageform=function(){if(!this.gui_objects.messageform)return!1;var a=$("[name='_from']"),b=$("[name='_to']"),d=$("input[name='_subject']"),e=$("[name='_message']").get(0),f=$("input[name='_is_html']").val()=="1",g=["cc","bcc","replyto","followupto"],h;this.env.autocomplete_threads>0&&(h={threads:this.env.autocomplete_threads,sources:this.env.autocomplete_sources});this.init_address_input_events(b,h);for(var k in g)this.init_address_input_events($("[name='_"+ -g[k]+"']"),h);f||(this.set_caret_pos(e,this.env.top_posting?0:$(e).val().length),a.prop("type")=="select-one"&&$("input[name='_draft_saveid']").val()==""&&this.change_identity(a[0]));b.val()==""?b.focus():d.val()==""?d.focus():e&&e.focus();this.env.compose_focus_elem=document.activeElement;this.compose_field_hash(!0);this.auto_save_start()};this.init_address_input_events=function(a,b){a[bw.ie||bw.safari||bw.chrome?"keydown":"keypress"](function(a){return l.ksearch_keydown(a,this,b)}).attr("autocomplete", -"off")};this.check_compose_input=function(){var a,b=$("[name='_to']"),d=$("[name='_cc']"),e=$("[name='_bcc']"),f=$("[name='_from']"),g=$("[name='_subject']"),h=$("[name='_message']");if(f.prop("type")=="text"&&!rcube_check_email(f.val(),!0))return alert(this.get_label("nosenderwarning")),f.focus(),!1;d=b.val()?b.val():d.val()?d.val():e.val();if(!rcube_check_email(d.replace(/^\s+/,"").replace(/[\s,;]+$/,""),!0))return alert(this.get_label("norecipientwarning")),b.focus(),!1;for(var k in this.env.attachments)if(typeof this.env.attachments[k]=== -"object"&&!this.env.attachments[k].complete)return alert(this.get_label("notuploadedwarning")),!1;if(g.val()=="")if(b=prompt(this.get_label("nosubjectwarning"),this.get_label("nosubject")),!b&&b!=="")return g.focus(),!1;else g.val(b?b:this.get_label("nosubject"));this.stop_spellchecking();window.tinyMCE&&(a=tinyMCE.get(this.env.composebody));if(!a&&h.val()==""&&!confirm(this.get_label("nobodywarning")))return h.focus(),!1;else if(a){if(!a.getContent()&&!confirm(this.get_label("nobodywarning")))return a.focus(), -!1;tinyMCE.triggerSave()}return!0};this.toggle_editor=function(a){if(a.mode=="html")this.display_spellcheck_controls(!1),this.plain2html($("#"+a.id).val(),a.id),tinyMCE.execCommand("mceAddControl",!1,a.id);else{var b=tinyMCE.get(a.id);b.plugins.spellchecker&&b.plugins.spellchecker.active&&b.execCommand("mceSpellCheck",!1);if(b=b.getContent()){if(!confirm(this.get_label("editorwarning")))return!1;this.html2plain(b,a.id)}tinyMCE.execCommand("mceRemoveControl",!1,a.id);this.display_spellcheck_controls(!0)}return!0}; -this.stop_spellchecking=function(){var a;if(window.tinyMCE&&(a=tinyMCE.get(this.env.composebody)))a.plugins.spellchecker&&a.plugins.spellchecker.active&&a.execCommand("mceSpellCheck");else if((a=this.env.spellcheck)&&!this.spellcheck_ready)$(a.spell_span).trigger("click"),this.set_spellcheck_state("ready")};this.display_spellcheck_controls=function(a){this.env.spellcheck&&(a||this.stop_spellchecking(),$(this.env.spellcheck.spell_container).css("visibility",a?"visible":"hidden"))};this.set_spellcheck_state= -function(a){this.spellcheck_ready=a=="ready"||a=="no_error_found";this.enable_command("spellcheck",this.spellcheck_ready)};this.spellcheck_lang=function(){var a;if(window.tinyMCE&&(a=tinyMCE.get(this.env.composebody))&&a.plugins.spellchecker)return a.plugins.spellchecker.selectedLang;else if(this.env.spellcheck)return GOOGIE_CUR_LANG};this.spellcheck_resume=function(a,b){if(a){var d=tinyMCE.get(this.env.composebody),e=d.plugins.spellchecker;e.active=1;e._markWords(b);d.nodeChanged()}else{var e=this.env.spellcheck; -e.prepare(!1,!0);e.processData(b)}};this.set_draft_id=function(a){$("input[name='_draft_saveid']").val(a)};this.auto_save_start=function(){if(this.env.draft_autosave)this.save_timer=self.setTimeout(function(){l.command("savedraft")},this.env.draft_autosave*1E3);this.busy=!1};this.compose_field_hash=function(a){var b,d="",e=$("[name='_to']").val(),f=$("[name='_cc']").val(),g=$("[name='_bcc']").val(),h=$("[name='_subject']").val();e&&(d+=e+":");f&&(d+=f+":");g&&(d+=g+":");h&&(d+=h+":");d+=window.tinyMCE&& -(b=tinyMCE.get(this.env.composebody))?b.getContent():$("[name='_message']").val();if(this.env.attachments)for(var k in this.env.attachments)d+=k;if(a)this.cmp_hash=d;return d};this.change_identity=function(a,b){if(!a||!a.options)return!1;if(!b)b=this.env.show_sig;var d,e=-1,f=a.options[a.selectedIndex].value,g=$("[name='_message']"),h=g.val(),k=$("input[name='_is_html']").val()=="1",j=this.env.identity;d=this.env.sig_above&&(this.env.compose_mode=="reply"||this.env.compose_mode=="forward")?"---": -"-- ";this.env.signatures&&this.env.signatures[f]?(this.enable_command("insert-sig",!0),this.env.compose_commands.push("insert-sig")):this.enable_command("insert-sig",!1);if(k){if(b&&this.env.signatures&&(e=tinyMCE.get(this.env.composebody),g=e.dom.get("_rc_sig"),g||(j=e.getBody(),h=e.getDoc(),g=h.createElement("div"),g.setAttribute("id","_rc_sig"),this.env.sig_above?(e.getWin().focus(),e=e.selection.getNode(),e.nodeName=="BODY"?(j.insertBefore(g,j.firstChild),j.insertBefore(h.createElement("br"), -j.firstChild)):(j.insertBefore(g,e.nextSibling),j.insertBefore(h.createElement("br"),e.nextSibling))):(bw.ie&&j.appendChild(h.createElement("br")),j.appendChild(g))),this.env.signatures[f]))this.env.signatures[f].is_html?(j=this.env.signatures[f].text,this.env.signatures[f].plain_text.match(/^--[ -]\r?\n/)||(j=d+"<br />"+j)):(j=this.env.signatures[f].text,j.match(/^--[ -]\r?\n/)||(j=d+"\n"+j),j="<pre>"+j+"</pre>"),g.innerHTML=j}else b&&j&&this.env.signatures&&this.env.signatures[j]&&(j=this.env.signatures[j].is_html? -this.env.signatures[j].plain_text:this.env.signatures[j].text,j=j.replace(/\r\n/g,"\n"),j.match(/^--[ -]\n/)||(j=d+"\n"+j),e=this.env.sig_above?h.indexOf(j):h.lastIndexOf(j),e>=0&&(h=h.substring(0,e)+h.substring(e+j.length,h.length))),b&&this.env.signatures&&this.env.signatures[f]?(j=this.env.signatures[f].is_html?this.env.signatures[f].plain_text:this.env.signatures[f].text,j=j.replace(/\r\n/g,"\n"),j.match(/^--[ -]\n/)||(j=d+"\n"+j),this.env.sig_above?e>=0?(h=h.substring(0,e)+j+h.substring(e,h.length), -d=e-1):(pos=this.get_caret_pos(g.get(0)))?(h=h.substring(0,pos)+"\n"+j+"\n\n"+h.substring(pos,h.length),d=pos):(d=0,h="\n\n"+j+"\n\n"+h.replace(/^[\r\n]+/,"")):(h=h.replace(/[\r\n]+$/,""),d=!this.env.top_posting&&h.length?h.length+1:0,h+="\n\n"+j)):d=this.env.top_posting?0:h.length,g.val(h),this.set_caret_pos(g.get(0),d);this.env.identity=f;return!0};this.upload_file=function(a){if(!a)return!1;var b,d=0,e=$("input[type=file]",a).get(0),f=e.files?e.files.length:e.value?1:0;if(f){if(e.files&&this.env.max_filesize&& -this.env.filesizeerror){for(b=0;b<f;b++)d+=e.files[b].size;if(d&&d>this.env.max_filesize){this.display_message(this.env.filesizeerror,"error");return}}b=this.async_upload_form(a,"upload",function(a){var b,d="";try{if(this.contentDocument)b=this.contentDocument;else if(this.contentWindow)b=this.contentWindow.document;d=b.childNodes[0].innerHTML}catch(e){}if(!d.match(/add2attachment/)&&(!bw.opera||rcmail.env.uploadframe&&rcmail.env.uploadframe==a.data.ts))d.match(/display_message/)||rcmail.display_message(rcmail.get_label("fileuploaderror"), -"error"),rcmail.remove_from_attachment_list(a.data.ts);if(bw.opera)rcmail.env.uploadframe=a.data.ts});f="<span>"+this.get_label("uploading"+(f>1?"many":""))+"</span>";d=b.replace(/^rcmupload/,"");this.env.loadingicon&&(f='<img src="'+this.env.loadingicon+'" alt="" />'+f);this.env.cancelicon&&(f='<a title="'+this.get_label("cancel")+'" onclick="return rcmail.cancel_attachment_upload(\''+d+"', '"+b+'\');" href="#cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+f);this.add2attachment_list(d, -{name:"",html:f,complete:!1});this.env.upload_progress_time&&this.upload_progress_start("upload",d)}this.gui_objects.attachmentform=a;return!0};this.add2attachment_list=function(a,b,d){if(!this.gui_objects.attachmentlist)return!1;var e,f=$("<li>").attr("id",a).html(b.html);d&&(e=document.getElementById(d))?f.replaceAll(e):f.appendTo(this.gui_objects.attachmentlist);d&&this.env.attachments[d]&&delete this.env.attachments[d];this.env.attachments[a]=b;return!0};this.remove_from_attachment_list=function(a){this.env.attachments[a]&& -delete this.env.attachments[a];if(!this.gui_objects.attachmentlist)return!1;var b=this.gui_objects.attachmentlist.getElementsByTagName("li");for(i=0;i<b.length;i++)b[i].id==a&&this.gui_objects.attachmentlist.removeChild(b[i])};this.remove_attachment=function(a){a&&this.env.attachments[a]&&this.http_post("remove-attachment",{_id:this.env.compose_id,_file:a});return!0};this.cancel_attachment_upload=function(a,b){if(!a||!b)return!1;this.remove_from_attachment_list(a);$("iframe[name='"+b+"']").remove(); -return!1};this.upload_progress_start=function(a,b){window.setTimeout(function(){rcmail.http_request(a,{_progress:b})},this.env.upload_progress_time*1E3)};this.upload_progress_update=function(a){var b=$("#"+a.name+"> span");b.length&&a.text&&(b.text(a.text),a.done||this.upload_progress_start(a.action,a.name))};this.add_contact=function(a){a&&this.http_post("addcontact","_address="+a);return!0};this.qsearch=function(a){if(a!=""){var b,d="",e=[],f=this.env.search_mods,g=this.env.mailbox,h=this.set_busy(!0, -"searching");this.message_list?(this.clear_message_list(),f&&(f=f[g]?f[g]:f["*"])):this.contact_list&&this.list_contacts_clear();if(f){for(b in f)e.push(b);d+="&_headers="+e.join(",")}this.gui_objects.search_filter&&(d+="&_filter="+this.gui_objects.search_filter.value);this.env.current_page=1;a=this.http_request("search","_q="+urlencode(a)+(g?"&_mbox="+urlencode(g):"")+(this.env.source?"&_source="+urlencode(this.env.source):"")+(this.env.group?"&_gid="+urlencode(this.env.group):"")+(d?d:""),h);this.env.qsearch= -{lock:h,request:a}}};this.reset_qsearch=function(){if(this.gui_objects.qsearchbox)this.gui_objects.qsearchbox.value="";this.env.qsearch&&this.abort_request(this.env.qsearch);this.env.qsearch=null;this.env.search_request=null};this.sent_successfully=function(a,b){this.display_message(b,a);window.setTimeout(function(){l.list_mailbox()},500)};this.ksearch_keydown=function(a,b,d){this.ksearch_timer&&clearTimeout(this.ksearch_timer);var e=rcube_event.get_keycode(a),f=rcube_event.get_modifier(a);switch(e){case 38:case 40:if(!this.ksearch_pane)break; -e=e==38?1:0;b=document.getElementById("rcmksearchSelected");if(!b)b=this.ksearch_pane.__ul.firstChild;b&&this.ksearch_select(e?b.previousSibling:b.nextSibling);return rcube_event.cancel(a);case 9:if(f==SHIFT_KEY||!this.ksearch_visible()){this.ksearch_hide();return}case 13:if(!this.ksearch_visible())return!1;this.insert_recipient(this.ksearch_selected);this.ksearch_hide();return rcube_event.cancel(a);case 27:this.ksearch_hide();return;case 37:case 39:if(f!=SHIFT_KEY)return}this.ksearch_timer=window.setTimeout(function(){l.ksearch_get_results(d)}, -200);this.ksearch_input=b;return!0};this.ksearch_visible=function(){return this.ksearch_selected!==null&&this.ksearch_selected!==void 0&&this.ksearch_value};this.ksearch_select=function(a){var b=$("#rcmksearchSelected");b[0]&&a&&b.removeAttr("id").removeClass("selected");if(a)$(a).attr("id","rcmksearchSelected").addClass("selected"),this.ksearch_selected=a._rcm_id};this.insert_recipient=function(a){if(this.env.contacts[a]&&this.ksearch_input){var b=this.ksearch_input.value,d=this.get_caret_pos(this.ksearch_input), -d=b.lastIndexOf(this.ksearch_value,d),e=!1,f="",g=b.substring(0,d),b=b.substring(d+this.ksearch_value.length,b.length);this.ksearch_destroy();typeof this.env.contacts[a]==="object"&&this.env.contacts[a].id?(f+=this.env.contacts[a].name+", ",this.group2expand=$.extend({},this.env.contacts[a]),this.group2expand.input=this.ksearch_input,this.http_request("mail/group-expand","_source="+urlencode(this.env.contacts[a].source)+"&_gid="+urlencode(this.env.contacts[a].id),!1)):typeof this.env.contacts[a]=== -"string"&&(f=this.env.contacts[a]+", ",e=!0);this.ksearch_input.value=g+f+b;d+=f.length;this.ksearch_input.setSelectionRange&&this.ksearch_input.setSelectionRange(d,d);e&&this.triggerEvent("autocomplete_insert",{field:this.ksearch_input,insert:f})}};this.replace_group_recipients=function(a,b){if(this.group2expand&&this.group2expand.id==a)this.group2expand.input.value=this.group2expand.input.value.replace(this.group2expand.name,b),this.triggerEvent("autocomplete_insert",{field:this.group2expand.input, -insert:b}),this.group2expand=null};this.ksearch_get_results=function(a){var b=this.ksearch_input?this.ksearch_input.value:null;if(b!==null){this.ksearch_pane&&this.ksearch_pane.is(":visible")&&this.ksearch_pane.hide();var d=this.get_caret_pos(this.ksearch_input),e=b.lastIndexOf(",",d-1),b=b.substring(e+1,d),e=this.env.autocomplete_min_length,d=this.ksearch_data,b=$.trim(b);if(b!=this.ksearch_value)if(b.length&&b.length<e){if(!this.env.acinfo)this.env.acinfo=this.display_message(this.get_label("autocompletechars").replace("$min", -e))}else if(this.env.acinfo&&this.hide_message(this.env.acinfo),e=this.ksearch_value,this.ksearch_value=b,this.ksearch_destroy(),b.length&&(!e||!e.length||!(b.indexOf(e)==0&&(!d||!d.num)&&this.env.contacts&&!this.env.contacts.length))){var f,g,h,d=(new Date).getTime(),e=a&&a.threads?a.threads:1;f=a&&a.sources?a.sources:[];a=a&&a.action?a.action:"mail/autocomplete";this.ksearch_data={id:d,sources:f.slice(),action:a,locks:[],requests:[],num:f.length};for(f=0;f<e;f++){h=this.ksearch_data.sources.shift(); -if(e>1&&h===null)break;g=this.display_message(this.get_label("searching"),"loading");h=this.http_post(a,"_search="+urlencode(b)+"&_id="+d+(h?"&_source="+urlencode(h):""),g);this.ksearch_data.locks.push(g);this.ksearch_data.requests.push(h)}}}};this.ksearch_query_results=function(a,b,d){if(this.ksearch_value&&!(this.ksearch_input&&b!=this.ksearch_value)){var e,f,g,b=this.ksearch_value,h=this.env.autocomplete_max?this.env.autocomplete_max:15;if(!this.ksearch_pane)e=$("<ul>"),this.ksearch_pane=$("<div>").attr("id", -"rcmKSearchpane").css({position:"absolute","z-index":3E4}).append(e).appendTo(document.body),this.ksearch_pane.__ul=e[0];e=this.ksearch_pane.__ul;d&&this.ksearch_pane.data("reqid")==d?h-=e.childNodes.length:(this.ksearch_pane.data("reqid",d),e.innerHTML="",this.env.contacts=[],f=$(this.ksearch_input).offset(),this.ksearch_pane.css({left:f.left+"px",top:f.top+this.ksearch_input.offsetHeight+"px",display:"none"}));if(a&&a.length)for(i=0;i<a.length&&h>0;i++)g=typeof a[i]==="object"?a[i].name:a[i],f= -document.createElement("LI"),f.innerHTML=g.replace(RegExp("("+RegExp.escape(b)+")","ig"),"##$1%%").replace(/</g,"<").replace(/>/g,">").replace(/##([^%]+)%%/g,"<b>$1</b>"),f.onmouseover=function(){l.ksearch_select(this)},f.onmouseup=function(){l.ksearch_click(this)},f._rcm_id=this.env.contacts.length+i,e.appendChild(f),h-=1;if(e.childNodes.length&&(this.ksearch_pane.show(),!this.env.contacts.length))$("li:first",e).attr("id","rcmksearchSelected").addClass("selected"),this.ksearch_selected=0; -if(a&&a.length)this.env.contacts=this.env.contacts.concat(a);if(h>0&&this.ksearch_data.id==d&&this.ksearch_data.sources.length&&(e=this.ksearch_data,h=e.sources.shift()))data.num--,a=this.display_message(this.get_label("searching"),"loading"),d=this.http_post(e.action,"_search="+urlencode(b)+"&_id="+d+"&_source="+urlencode(h),a),this.ksearch_data.locks.push(a),this.ksearch_data.requests.push(d)}};this.ksearch_click=function(a){this.ksearch_input&&this.ksearch_input.focus();this.insert_recipient(a._rcm_id); -this.ksearch_hide()};this.ksearch_blur=function(){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="";this.ksearch_pane&&this.ksearch_pane.hide();this.ksearch_destroy()};this.ksearch_destroy=function(){var a,b,d=this.ksearch_data;if(d){for(a=0,b=d.locks.length;a<b;a++)this.abort_request({request:d.requests[a],lock:d.locks[a]});this.ksearch_data=null}};this.contactlist_keypress= -function(a){a.key_pressed==a.DELETE_KEY&&this.command("delete")};this.contactlist_select=function(a){this.preview_timer&&clearTimeout(this.preview_timer);var b,d,e,f=this,g=!1;e=this.env.source?this.env.address_sources[this.env.source]:null;(d=a.get_single_selection())?this.preview_timer=window.setTimeout(function(){f.load_contact(d,"show")},200):this.env.contentframe&&this.show_contentframe(!1);if(a.selection.length)if(e)g=!e.readonly;else for(b in a.selection)if((e=String(a.selection[b]).replace(/^[^-]+-/, -""))&&this.env.address_sources[e]&&!this.env.address_sources[e].readonly){g=!0;break}this.enable_command("compose",a.selection.length>0);this.enable_command("edit",d&&g);this.enable_command("delete",a.selection.length&&g);return!1};this.list_contacts=function(a,b,d){var e="",f=window;if(!a)a=this.env.source;if(d&&this.current_page==d&&a==this.env.source&&b==this.env.group)return!1;if(a!=this.env.source)d=this.env.current_page=1,this.reset_qsearch();else if(b!=this.env.group)d=this.env.current_page= -1;this.select_folder(b?"G"+a+b:a,this.env.group?"G"+this.env.source+this.env.group:this.env.source);this.env.source=a;this.env.group=b;this.gui_objects.contactslist?this.list_contacts_remote(a,b,d):(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(f=window.frames[this.env.contentframe],e="&_framed=1"),b&&(e+="&_gid="+b),d&&(e+="&_page="+d),this.env.search_request&&(e+="&_search="+this.env.search_request),this.set_busy(!0,"loading"),this.location_href(this.env.comm_path+ -(a?"&_source="+urlencode(a):"")+e,f))};this.list_contacts_remote=function(a,b,d){this.list_contacts_clear();var d=(a?"_source="+urlencode(a):"")+(d?(a?"&":"")+"_page="+d:""),e=this.set_busy(!0,"loading");this.env.source=a;(this.env.group=b)&&(d+="&_gid="+b);this.env.search_request&&(d+="&_search="+this.env.search_request);this.http_request("list",d,e)};this.list_contacts_clear=function(){this.contact_list.clear(!0);this.show_contentframe(!1);this.enable_command("delete","compose",!1)};this.load_contact= -function(a,b,d){var e="",f=window;if(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe])e="&_framed=1",f=window.frames[this.env.contentframe],this.show_contentframe(!0),a||(this.contact_list.clear_selection(),this.enable_command("delete","compose",!1));else if(d)return!1;if(b&&(a||b=="add")&&!this.drag_active)this.env.group&&(e+="&_gid="+urlencode(this.env.group)),this.location_href(this.env.comm_path+"&_action="+b+"&_source="+urlencode(this.env.source)+"&_cid="+urlencode(a)+ -e,f,!0);return!0};this.group_member_change=function(a,b,d,e){var a=a=="add"?"add":"del",f=this.display_message(this.get_label(a=="add"?"addingmember":"removingmember"),"loading");this.http_post("group-"+a+"members","_cid="+urlencode(b)+"&_source="+urlencode(d)+"&_gid="+urlencode(e),f)};this.copy_contact=function(a,b){a||(a=this.contact_list.get_selection().join(","));if(b.type=="group"&&b.source==this.env.source)this.group_member_change("add",a,b.source,b.id);else if(b.type=="group"&&!this.env.address_sources[b.source].readonly){var d= -this.display_message(this.get_label("copyingcontact"),"loading");this.http_post("copy","_cid="+urlencode(a)+"&_source="+urlencode(this.env.source)+"&_to="+urlencode(b.source)+"&_togid="+urlencode(b.id)+(this.env.group?"&_gid="+urlencode(this.env.group):""),d)}else b.id!=this.env.source&&a&&this.env.address_sources[b.id]&&!this.env.address_sources[b.id].readonly&&(d=this.display_message(this.get_label("copyingcontact"),"loading"),this.http_post("copy","_cid="+urlencode(a)+"&_source="+urlencode(this.env.source)+ -"&_to="+urlencode(b.id)+(this.env.group?"&_gid="+urlencode(this.env.group):""),d))};this.delete_contacts=function(){var a=this.contact_list.get_selection();if((a.length||this.env.cid)&&confirm(this.get_label("deletecontactconfirm"))){var b,d,e=[],f="";if(this.env.cid)e.push(this.env.cid);else{for(d=0;d<a.length;d++)b=a[d],e.push(b),this.contact_list.remove_row(b,d==a.length-1);a.length==1&&this.show_contentframe(!1)}this.env.group&&(f+="&_gid="+urlencode(this.env.group));this.env.search_request&& -(f+="&_search="+this.env.search_request);this.http_post("delete","_cid="+urlencode(e.join(","))+"&_source="+urlencode(this.env.source)+"&_from="+(this.env.action?this.env.action:"")+f);return!0}};this.update_contact_row=function(a,b,d,e){var f,g=this.contact_list,a=String(a).replace(this.identifier_expr,"_");g.rows[a]||(a=a+"-"+e,d&&(d=d+"-"+e));if(g.rows[a]&&(f=g.rows[a].obj)){for(e=0;e<b.length;e++)f.cells[e]&&$(f.cells[e]).html(b[e]);if(d)d=String(d).replace(this.identifier_expr,"_"),f.id="rcmrow"+ -d,g.remove_row(a),g.init_row(f),g.selection[0]=d,f.style.display=""}};this.add_contact_row=function(a,b){if(!this.gui_objects.contactslist||!this.gui_objects.contactslist.tBodies[0])return!1;var d=this.gui_objects.contactslist.tBodies[0].rows.length%2,e=document.createElement("tr");e.id="rcmrow"+String(a).replace(this.identifier_expr,"_");e.className="contact "+(d?"even":"odd");this.contact_list.in_selection(a)&&(e.className+=" selected");for(var f in b)col=document.createElement("td"),col.className= -String(f).toLowerCase(),col.innerHTML=b[f],e.appendChild(col);this.contact_list.insert_row(e);this.enable_command("export",this.contact_list.rowcount>0)};this.init_contact_form=function(){var a=this,b;this.set_photo_actions($("#ff_photo").val());for(b in this.env.coltypes)this.init_edit_field(b,null);$(".contactfieldgroup .row a.deletebutton").click(function(){a.delete_edit_field(this);return!1});$("select.addfieldmenu").change(function(){a.insert_edit_field($(this).val(),$(this).attr("rel"),this); -this.selectedIndex=0});$("input[type='text']:visible").first().focus()};this.group_create=function(){if(this.gui_objects.folderlist){if(!this.name_input)this.name_input=$("<input>").attr("type","text"),this.name_input.bind("keydown",function(a){return rcmail.add_input_keydown(a)}),this.name_input_li=$("<li>").addClass("contactgroup").append(this.name_input),this.name_input_li.insertAfter(this.get_folder_li(this.env.source));this.name_input.select().focus()}};this.group_rename=function(){if(this.env.group&& -this.gui_objects.folderlist){if(!this.name_input){this.enable_command("list","listgroup",!1);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(a){return rcmail.add_input_keydown(a)});this.env.group_renaming=!0;var a,b=this.get_folder_li(this.env.source+this.env.group,"rcmliG");b&&(a=b.firstChild)&&$(a).hide().before(this.name_input)}this.name_input.select().focus()}};this.group_delete=function(){if(this.env.group&& -confirm(this.get_label("deletegroupconfirm"))){var a=this.set_busy(!0,"groupdeleting");this.http_post("group-delete","_source="+urlencode(this.env.source)+"&_gid="+urlencode(this.env.group),a)}};this.remove_group_item=function(a){var b,d="G"+a.source+a.id;if(b=this.get_folder_li(d))this.triggerEvent("group_delete",{source:a.source,id:a.id,li:b}),b.parentNode.removeChild(b),delete this.env.contactfolders[d],delete this.env.contactgroups[d];this.list_contacts(a.source,0)};this.add_input_keydown=function(a){a= -rcube_event.get_keycode(a);if(a==13){if(a=this.name_input.val()){var b=this.set_busy(!0,"loading");this.env.group_renaming?this.http_post("group-rename","_source="+urlencode(this.env.source)+"&_gid="+urlencode(this.env.group)+"&_name="+urlencode(a),b):this.http_post("group-create","_source="+urlencode(this.env.source)+"&_name="+urlencode(a),b)}return!1}else a==27&&this.reset_add_input();return!0};this.reset_add_input=function(){if(this.name_input){if(this.env.group_renaming)this.name_input.parent().children().last().show(), -this.env.group_renaming=!1;this.name_input.remove();this.name_input_li&&this.name_input_li.remove();this.name_input=this.name_input_li=null}this.enable_command("list","listgroup",!0)};this.insert_contact_group=function(a){this.reset_add_input();a.type="group";var b="G"+a.source+a.id,d=$("<a>").attr("href","#").attr("rel",a.source+":"+a.id).click(function(){return rcmail.command("listgroup",a,this)}).html(a.name),d=$("<li>").attr({id:"rcmli"+b.replace(this.identifier_expr,"_"),"class":"contactgroup"}).append(d); -this.env.contactfolders[b]=this.env.contactgroups[b]=a;this.add_contact_group_row(a,d);this.triggerEvent("group_insert",{id:a.id,source:a.source,name:a.name,li:d[0]})};this.update_contact_group=function(a){this.reset_add_input();var b="G"+a.source+a.id,d=this.get_folder_li(b),e;if(d&&a.newid){e="G"+a.source+a.newid;var f=$.extend({},a);d.id=String("rcmli"+e).replace(this.identifier_expr,"_");this.env.contactfolders[e]=this.env.contactfolders[b];this.env.contactfolders[e].id=a.newid;this.env.group= -a.newid;delete this.env.contactfolders[b];delete this.env.contactgroups[b];f.id=a.newid;f.type="group";e=$("<a>").attr("href","#").attr("rel",a.source+":"+a.newid).click(function(){return rcmail.command("listgroup",f,this)}).html(a.name);$(d).children().replaceWith(e)}else if(d&&(e=d.firstChild)&&e.tagName.toLowerCase()=="a")e.innerHTML=a.name;this.env.contactfolders[b].name=this.env.contactgroups[b].name=a.name;this.add_contact_group_row(a,$(d),!0);this.triggerEvent("group_update",{id:a.id,source:a.source, -name:a.name,li:d[0],newid:a.newid})};this.add_contact_group_row=function(a,b,d){var e=a.name.toUpperCase(),f=this.get_folder_li(a.source),a="rcmliG"+a.source.replace(this.identifier_expr,"_");d?(d=b.clone(!0),b.remove()):d=b;$('li[id^="'+a+'"]',this.gui_objects.folderlist).each(function(a,b){if(e>=$(this).text().toUpperCase())f=b;else return!1});d.insertAfter(f)};this.update_group_commands=function(){var a=this.env.source!=""?this.env.address_sources[this.env.source]:null;this.enable_command("group-create", -a&&a.groups&&!a.readonly);this.enable_command("group-rename","group-delete",a&&a.groups&&this.env.group&&!a.readonly)};this.init_edit_field=function(a,b){b||(b=$(".ff_"+a));b.focus(function(){l.focus_textfield(this)}).blur(function(){l.blur_textfield(this)}).each(function(){this._placeholder=this.title=l.env.coltypes[a].label;l.blur_textfield(this)})};this.insert_edit_field=function(a,b,d){var e=$("#ff_"+a);if(e.length)e.show().focus(),$(d).children('option[value="'+a+'"]').prop("disabled",!0);else if($(".ff_"+ -a),e=$("#contactsection"+b+" .contactcontroller"+a),e.length||(e=$("<fieldset>").addClass("contactfieldgroup contactcontroller"+a).insertAfter($("#contactsection"+b+" .contactfieldgroup").last())),e.length&&e.get(0).nodeName=="FIELDSET"){var f,b=this.env.coltypes[a],g=$("<div>").addClass("row"),h=$("<div>").addClass("contactfieldcontent data"),k=$("<div>").addClass("contactfieldlabel label");b.subtypes_select?k.html(b.subtypes_select):k.html(b.label);var j=b.limit!=1?"[]":"";if(b.type=="text"||b.type== -"date")f=$("<input>").addClass("ff_"+a).attr({type:"text",name:"_"+a+j,size:b.size}).appendTo(h),this.init_edit_field(a,f);else if(b.type=="composite"){var o,m,n=[],p=[];if(f=this.env[a+"_template"])for(o=0;o<f.length;o++)n.push(f[o][1]),p.push(f[o][2]);else for(o in b.childs)n.push(o);for(var q=0;q<n.length;q++)o=n[q],f=b.childs[o],f=$("<input>").addClass("ff_"+o).attr({type:"text",name:"_"+o+j,size:f.size}).appendTo(h),h.append(p[q]||" "),this.init_edit_field(o,f),m||(m=f);f=m}else if(b.type=="select"){f= -$("<select>").addClass("ff_"+a).attr("name","_"+a+j).appendTo(h);var s=f.attr("options");s[s.length]=new Option("---","");b.options&&$.each(b.options,function(a,b){s[s.length]=new Option(b,a)})}if(f){$('<a href="#del"></a>').addClass("contactfieldbutton deletebutton").attr({title:this.get_label("delete"),rel:a}).html(this.env.delbutton).click(function(){l.delete_edit_field(this);return!1}).appendTo(h);g.append(k).append(h).appendTo(e.show());f.first().focus();if(!b.count)b.count=0;++b.count==b.limit&& -b.limit&&$(d).children('option[value="'+a+'"]').prop("disabled",!0)}}};this.delete_edit_field=function(a){var b=$(a).attr("rel"),d=this.env.coltypes[b],e=$(a).parents("fieldset.contactfieldgroup"),f=e.parent().find("select.addfieldmenu");--d.count<=0&&d.visible?$(a).parent().children("input").val("").blur():($(a).parents("div.row").remove(),e.children("div.row").length||e.hide());f.length&&(a=f.children('option[value="'+b+'"]'),a.length?a.prop("disabled",!1):$("<option>").attr("value",b).html(d.label).appendTo(f), -f.show())};this.upload_contact_photo=function(a){if(a&&a.elements._photo.value)this.async_upload_form(a,"upload-photo",function(){rcmail.set_busy(!1,null,rcmail.photo_upload_id)}),this.photo_upload_id=this.set_busy(!0,"uploading")};this.replace_contact_photo=function(a){var b=a=="-del-"?this.env.photo_placeholder:this.env.comm_path+"&_action=photo&_source="+this.env.source+"&_cid="+this.env.cid+"&_photo="+a;this.set_photo_actions(a);$(this.gui_objects.contactphoto).children("img").attr("src",b)}; -this.photo_upload_end=function(){this.set_busy(!1,null,this.photo_upload_id);delete this.photo_upload_id};this.set_photo_actions=function(a){var b,d=this.buttons["upload-photo"];for(b=0;d&&b<d.length;b++)$("#"+d[b].id).html(this.get_label(a=="-del-"?"addphoto":"replacephoto"));$("#ff_photo").val(a);this.enable_command("upload-photo",this.env.coltypes.photo?!0:!1);this.enable_command("delete-photo",this.env.coltypes.photo&&a!="-del-")};this.advanced_search=function(){var a="&_form=1",b=window;this.env.contentframe&& -window.frames&&window.frames[this.env.contentframe]&&(a+="&_framed=1",b=window.frames[this.env.contentframe],this.contact_list.clear_selection());this.location_href(this.env.comm_path+"&_action=search"+a,b,!0);return!0};this.unselect_directory=function(){if(this.env.address_sources.length>1||this.env.group!="")this.select_folder("",this.env.group?"G"+this.env.source+this.env.group:this.env.source),this.env.group="",this.env.source=""};this.section_select=function(a){var a=a.get_single_selection(), -b="",d=window;a&&(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(b="&_framed=1",d=window.frames[this.env.contentframe]),this.location_href(this.env.comm_path+"&_action=edit-prefs&_section="+a+b,d,!0));return!0};this.identity_select=function(a){var b;(b=a.get_single_selection())&&this.load_identity(b,"edit-identity")};this.load_identity=function(a,b){if(b=="edit-identity"&&(!a||a==this.env.iid))return!1;var d="",e=window;if(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe])d= -"&_framed=1",e=window.frames[this.env.contentframe],document.getElementById(this.env.contentframe).style.visibility="inherit";if(b&&(a||b=="add-identity"))this.set_busy(!0),this.location_href(this.env.comm_path+"&_action="+b+"&_iid="+a+d,e);return!0};this.delete_identity=function(a){var b=this.identity_list.get_selection();if(b.length||this.env.iid)return a||(a=this.env.iid?this.env.iid:b[0]),this.goto_url("delete-identity","_iid="+a+"&_token="+this.env.request_token,!0),!0};this.init_subscription_list= -function(){var a=this;this.subscription_list=new rcube_list_widget(this.gui_objects.subscriptionlist,{multiselect:!1,draggable:!0,keyboard:!1,toggleselect:!0});this.subscription_list.addEventListener("select",function(b){a.subscription_select(b)});this.subscription_list.addEventListener("dragstart",function(){a.drag_active=!0});this.subscription_list.addEventListener("dragend",function(b){a.subscription_move_folder(b)});this.subscription_list.row_init=function(b){b.obj.onmouseover=function(){a.focus_subscription(b.id)}; -b.obj.onmouseout=function(){a.unfocus_subscription(b.id)}};this.subscription_list.init();$("#mailboxroot").mouseover(function(){a.focus_subscription(this.id)}).mouseout(function(){a.unfocus_subscription(this.id)})};this.focus_subscription=function(a){var b,d,e=RegExp.escape(this.env.delimiter),e=RegExp("["+e+"]?[^"+e+"]+$");if(this.drag_active&&this.env.mailbox&&(b=document.getElementById(a)))if(this.env.subscriptionrows[a]&&(d=this.env.subscriptionrows[a][0])!==null&&this.check_droptarget(d)&&!this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2]&& -d!=this.env.mailbox.replace(e,"")&&!d.match(RegExp("^"+RegExp.escape(this.env.mailbox+this.env.delimiter))))this.env.dstfolder=d,$(b).addClass("droptarget")};this.unfocus_subscription=function(a){var b=$("#"+a);this.env.dstfolder=null;this.env.subscriptionrows[a]&&b[0]?b.removeClass("droptarget"):$(this.subscription_list.frame).removeClass("droptarget")};this.subscription_select=function(a){var b,d;a&&(b=a.get_single_selection())&&(d=this.env.subscriptionrows["rcmrow"+b])?(this.env.mailbox=d[0],this.show_folder(d[0]), -this.enable_command("delete-folder",!d[2])):(this.env.mailbox=null,this.show_contentframe(!1),this.enable_command("delete-folder","purge",!1))};this.subscription_move_folder=function(){var a=RegExp.escape(this.env.delimiter);this.env.mailbox&&this.env.dstfolder!==null&&this.env.dstfolder!=this.env.mailbox&&this.env.dstfolder!=this.env.mailbox.replace(RegExp("["+a+"]?[^"+a+"]+$"),"")&&(a=this.env.mailbox.replace(RegExp("[^"+a+"]*["+a+"]","g"),""),a=this.env.dstfolder===""?a:this.env.dstfolder+this.env.delimiter+ -a,a!=this.env.mailbox&&(this.http_post("rename-folder","_folder_oldname="+urlencode(this.env.mailbox)+"&_folder_newname="+urlencode(a),this.set_busy(!0,"foldermoving")),this.subscription_list.draglayer.hide()));this.drag_active=!1;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(a){if((a=this.env.subscriptionrows[this.get_folder_row_id(a?a:this.env.mailbox)][0])&&confirm(this.get_label("deletefolderconfirm"))){var b= -this.set_busy(!0,"folderdeleting");this.http_post("delete-folder","_mbox="+urlencode(a),b)}};this.add_folder_row=function(a,b,d,e,f,g){if(!this.gui_objects.subscriptionlist)return!1;var h,k,j,l,m,n=[],p=[],q=this.gui_objects.subscriptionlist.tBodies[0];h=$("tr",q).get(1);var s="rcmrow"+(new Date).getTime();if(!h)return this.goto_url("folders"),!1;h=$(h).clone(!0);h.attr("id",s);h.attr("class",g);h.find("td:first").html(b);$('input[name="_subscribed[]"]',h).val(a).prop({checked:e?!0:!1,disabled:d? -!0:!1});this.env.subscriptionrows[s]=[a,b,0];l=[];$.each(this.env.subscriptionrows,function(a,b){l.push(b)});l.sort(function(a,b){return a[0]<b[0]?-1:a[0]>b[0]?1:0});for(k in l)l[k][2]?(p.push(l[k][0]),j=l[k][0]+this.env.delimiter):j&&l[k][0].indexOf(j)==0?p.push(l[k][0]):(n.push(l[k][0]),j=null);for(k=0;k<p.length;k++)a.indexOf(p[k]+this.env.delimiter)==0&&(m=this.get_folder_row_id(p[k]));for(k=0;!m&&k<n.length;k++)k&&n[k]==a&&(m=this.get_folder_row_id(n[k-1]));m?$("#"+m).after(h):h.appendTo(q); -this.subscription_list.clear_selection();f||this.init_subscription_list();h=h.get(0);h.scrollIntoView&&h.scrollIntoView();return h};this.replace_folder_row=function(a,b,d,e,f){if(!this.gui_objects.subscriptionlist)return!1;var g,h,k,j,l=this.get_folder_row_id(a),m=RegExp("^"+RegExp.escape(a));g=$('input[name="_subscribed[]"]',$("#"+l)).prop("checked");var n=this.get_subfolders(a);this._remove_folder_row(l);e=$(this.add_folder_row(b,d,e,g,!0,f));if(d=n.length)j=a.split(this.env.delimiter).length-b.split(this.env.delimiter).length; -for(a=0;a<d;a++)if(l=n[a],g=this.env.subscriptionrows[l][0],f=this.env.subscriptionrows[l][1],h=$("#"+l),k=h.clone(!0),h.remove(),e.after(k),e=k,g=g.replace(m,b),$('input[name="_subscribed[]"]',e).val(g),this.env.subscriptionrows[l][0]=g,j!=0){if(j>0)for(g=j;g>0;g--)f=f.replace(/^ /,"");else for(g=j;g<0;g++)f=" "+f;e.find("td:first").html(f);this.env.subscriptionrows[l][1]=f}this.init_subscription_list()};this.remove_folder_row=function(a,b){var d,e,f= -[];d=this.get_folder_row_id(a);b&&(f=this.get_subfolders(a));this._remove_folder_row(d);for(d=0,e=f.length;d<e;d++)this._remove_folder_row(f[d])};this._remove_folder_row=function(a){this.subscription_list.remove_row(a.replace(/^rcmrow/,""));$("#"+a).remove();delete this.env.subscriptionrows[a]};this.get_subfolders=function(a){for(var b=[],d=RegExp("^"+RegExp.escape(a)+RegExp.escape(this.env.delimiter)),e=$("#"+this.get_folder_row_id(a)).get(0);e=e.nextSibling;)if(e.id)if(a=this.env.subscriptionrows[e.id][0], -d.test(a))b.push(e.id);else break;return b};this.subscribe=function(a){if(a){var b=this.display_message(this.get_label("foldersubscribing"),"loading");this.http_post("subscribe","_mbox="+urlencode(a),b)}};this.unsubscribe=function(a){if(a){var b=this.display_message(this.get_label("folderunsubscribing"),"loading");this.http_post("unsubscribe","_mbox="+urlencode(a),b)}};this.get_folder_row_id=function(a){var b,d=this.env.subscriptionrows;for(b in d)if(d[b]&&d[b][0]==a)break;return b};this.show_folder= -function(a,b,d){var e=window,a="&_action=edit-folder&_mbox="+urlencode(a);b&&(a+="&_path="+urlencode(b));this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(e=window.frames[this.env.contentframe],a+="&_framed=1");String(e.location.href).indexOf(a)>=0&&!d?this.show_contentframe(!0):this.location_href(this.env.comm_path+a,e,!0)};this.disable_subscription=function(a){(a=this.get_folder_row_id(a))&&$('input[name="_subscribed[]"]',$("#"+a)).prop("disabled",!0)};this.folder_size= -function(a){var b=this.set_busy(!0,"loading");this.http_post("folder-size","_mbox="+urlencode(a),b)};this.folder_size_update=function(a){$("#folder-size").replaceWith(a)};var t=function(a,b){var d=document.getElementById(b.id);if(d){var e=!1;if(b.type=="image")d=d.parentNode,e=!0;d._command=a;d._id=b.id;if(b.sel&&(d.onmousedown=function(){return rcmail.button_sel(this._command,this._id)},d.onmouseup=function(){return rcmail.button_out(this._command,this._id)},e))(new Image).src=b.sel;if(b.over&&(d.onmouseover= -function(){return rcmail.button_over(this._command,this._id)},d.onmouseout=function(){return rcmail.button_out(this._command,this._id)},e))(new Image).src=b.over}};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.init_buttons=function(){for(var a in this.buttons)if(typeof a==="string")for(var b=0;b<this.buttons[a].length;b++)t(a,this.buttons[a][b])};this.set_button= -function(a,b){var d,e,f=this.buttons[a];if(!f||!f.length)return!1;for(var g=0;g<f.length;g++){d=f[g];if((e=document.getElementById(d.id))&&d.type=="image"&&!d.status){if(d.pas=e._original_src?e._original_src:e.src,e.runtimeStyle&&e.runtimeStyle.filter&&e.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/))d.pas=RegExp.$1}else if(e&&!d.status)d.pas=String(e.className);if(e&&d.type=="image"&&d[b])d.status=b,e.src=d[b];else if(e&&d[b]!==void 0)d.status=b,e.className=d[b];if(e&&d.type=="input")d.status= -b,e.disabled=!b}};this.set_alttext=function(a,b){if(this.buttons[a]&&this.buttons[a].length)for(var d,e,f,g=0;g<this.buttons[a].length;g++)d=this.buttons[a][g],e=document.getElementById(d.id),d.type=="image"&&e?(e.setAttribute("alt",this.get_label(b)),(f=e.parentNode)&&f.tagName.toLowerCase()=="a"&&f.setAttribute("title",this.get_label(b))):e&&e.setAttribute("title",this.get_label(b))};this.button_over=function(a,b){var d,e,f=this.buttons[a];if(!f||!f.length)return!1;for(var g=0;g<f.length;g++)if(d= -f[g],d.id==b&&d.status=="act"&&(e=document.getElementById(d.id))&&d.over)d.type=="image"?e.src=d.over:e.className=d.over};this.button_sel=function(a,b){var d,e,f=this.buttons[a];if(f&&f.length)for(var g=0;g<f.length;g++)if(d=f[g],d.id==b&&d.status=="act"){if((e=document.getElementById(d.id))&&d.sel)d.type=="image"?e.src=d.sel:e.className=d.sel;this.buttons_sel[b]=a}};this.button_out=function(a,b){var d,e,f=this.buttons[a];if(f&&f.length)for(var g=0;g<f.length;g++)if(d=f[g],d.id==b&&d.status=="act"&& -(e=document.getElementById(d.id))&&d.act)d.type=="image"?e.src=d.act:e.className=d.act};this.focus_textfield=function(a){a._hasfocus=!0;var b=$(a);(b.hasClass("placeholder")||b.val()==a._placeholder)&&b.val("").removeClass("placeholder").attr("spellcheck",!0)};this.blur_textfield=function(a){a._hasfocus=!1;var b=$(a);a._placeholder&&(!b.val()||b.val()==a._placeholder)&&b.addClass("placeholder").attr("spellcheck",!1).val(a._placeholder)};this.set_pagetitle=function(a){if(a&&document.title)document.title= -a};this.display_message=function(a,b,d){if(this.is_framed())return parent.rcmail.display_message(a,b,d);if(!this.gui_objects.message){if(b!="loading")this.pending_message=[a,b,d];return!1}var b=b?b:"notice",e=this,f=String(a).replace(this.identifier_expr,"_"),g=b+(new Date).getTime();d||(d=this.message_time*(b=="error"||b=="warning"?2:1));b=="loading"&&(f="loading",d=this.env.request_timeout*1E3,a||(a=this.get_label("loading")));if(this.messages[f])return this.messages[f].obj&&this.messages[f].obj.html(a), -b=="loading"&&this.messages[f].labels.push({id:g,msg:a}),this.messages[f].elements.push(g),window.setTimeout(function(){e.hide_message(g,b=="loading")},d),g;var h=$("<div>").addClass(b).html(a).data("key",f);$(this.gui_objects.message).append(h).show();this.messages[f]={obj:h,elements:[g]};b=="loading"?this.messages[f].labels=[{id:g,msg:a}]:h.click(function(){return e.hide_message(h)});d>0&&window.setTimeout(function(){e.hide_message(g,b=="loading")},d);return g};this.hide_message=function(a,b){if(this.is_framed())return parent.rcmail.hide_message(a, -b);var d,e,f,g,h=this.messages;if(typeof a==="object")$(a)[b?"fadeOut":"hide"](),g=$(a).data("key"),this.messages[g]&&delete this.messages[g];else for(d in h)for(e in h[d].elements)if(h[d]&&h[d].elements[e]==a)if(h[d].elements.splice(e,1),h[d].elements.length){if(d=="loading")for(f in h[d].labels)h[d].labels[f].id==a?delete h[d].labels[f]:g=h[d].labels[f].msg,h[d].obj.html(g)}else h[d].obj[b?"fadeOut":"hide"](),delete h[d]};this.select_folder=function(a,b,d){if(this.gui_objects.folderlist){var e, -f;(e=this.get_folder_li(b,d))&&$(e).removeClass("selected").addClass("unfocused");(f=this.get_folder_li(a,d))&&$(f).removeClass("unfocused").addClass("selected");this.triggerEvent("selectfolder",{folder:a,old:b,prefix:d})}};this.get_folder_li=function(a,b){b||(b="rcmli");return this.gui_objects.folderlist?(a=String(a).replace(this.identifier_expr,"_"),document.getElementById(b+a)):null};this.set_message_coltypes=function(a,b){var d=this.message_list,e=d?d.list.tHead:null,f,g,h,k;this.env.coltypes= -a;if(e){if(b){g=document.createElement("thead");h=document.createElement("tr");for(c=0,k=b.length;c<k;c++){f=document.createElement("td");f.innerHTML=b[c].html;if(b[c].id)f.id=b[c].id;if(b[c].className)f.className=b[c].className;h.appendChild(f)}g.appendChild(h);e.parentNode.replaceChild(g,e);e=g}for(h=0,k=this.env.coltypes.length;h<k;h++)if(g=this.env.coltypes[h],(f=e.rows[0].cells[h])&&(g=="from"||g=="to")){f.id="rcm"+g;if(f.firstChild&&f.firstChild.tagName.toLowerCase()=="a")f=f.firstChild,f.onclick= -function(){return rcmail.command("sort",this.__col,this)},f.__col=g;f.innerHTML=this.get_label(g)}}this.env.subject_col=null;this.env.flagged_col=null;this.env.status_col=null;if((h=$.inArray("subject",this.env.coltypes))>=0)if(this.env.subject_col=h,d)d.subject_col=h;if((h=$.inArray("flag",this.env.coltypes))>=0)this.env.flagged_col=h;if((h=$.inArray("status",this.env.coltypes))>=0)this.env.status_col=h;d&&d.init_header()};this.set_rowcount=function(a){$(this.gui_objects.countdisplay).html(a);this.set_page_buttons()}; -this.set_mailboxname=function(a){if(this.gui_objects.mailboxname&&a)this.gui_objects.mailboxname.innerHTML=a};this.set_quota=function(a){a&&this.gui_objects.quotadisplay&&(typeof a==="object"&&a.type=="image"?this.percent_indicator(this.gui_objects.quotadisplay,a):$(this.gui_objects.quotadisplay).html(a))};this.set_unread_count=function(a,b,d){if(!this.gui_objects.mailboxlist)return!1;this.env.unread_counts[a]=b;this.set_unread_count_display(a,d)};this.set_unread_count_display=function(a,b){var d, -e,f,g,h;if(f=this.get_folder_li(a)){g=this.env.unread_counts[a]?this.env.unread_counts[a]:0;e=$(f).children("a").eq(0);d=e.children("span.unreadcount");!d.length&&g&&(d=$("<span>").addClass("unreadcount").appendTo(e));e=0;if((h=f.getElementsByTagName("div")[0])&&h.className.match(/collapsed/))for(var k in this.env.unread_counts)k.indexOf(a+this.env.delimiter)==0&&(e+=this.env.unread_counts[k]);g&&d.length?d.html(" ("+g+")"):d.length&&d.remove();d=RegExp(RegExp.escape(this.env.delimiter)+"[^"+RegExp.escape(this.env.delimiter)+ -"]+$");a.match(d)&&this.set_unread_count_display(a.replace(d,""),!1);g+e>0?$(f).addClass("unread"):$(f).removeClass("unread")}d=/^\([0-9]+\)\s+/i;b&&document.title&&(f="",f=String(document.title),f=g&&f.match(d)?f.replace(d,"("+g+") "):g?"("+g+") "+f:f.replace(d,""),this.set_pagetitle(f))};this.toggle_prefer_html=function(a){var b;if(b=document.getElementById("rcmfd_addrbook_show_images"))b.disabled=!a.checked};this.toggle_preview_pane=function(a){var b;if(b=document.getElementById("rcmfd_preview_pane_mark_read"))b.disabled= -!a.checked};this.set_headers=function(a){this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box&&a&&$(this.gui_objects.all_headers_box).html(a).show()};this.load_headers=function(a){if(this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box&&this.env.uid)$(a).removeClass("show-headers").addClass("hide-headers"),$(this.gui_objects.all_headers_row).show(),a.onclick=function(){rcmail.hide_headers(a)},this.gui_objects.all_headers_box.innerHTML||this.http_post("headers","_uid="+ -this.env.uid,this.display_message(this.get_label("loading"),"loading"))};this.hide_headers=function(a){if(this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box)$(a).removeClass("hide-headers").addClass("show-headers"),$(this.gui_objects.all_headers_row).hide(),a.onclick=function(){rcmail.load_headers(a)}};this.percent_indicator=function(a,b){if(!b||!a)return!1;var d=b.width?b.width:this.env.indicator_width?this.env.indicator_width:100,e=b.height?b.height:this.env.indicator_height?this.env.indicator_height: -14,f=b.percent?Math.abs(parseInt(b.percent)):0,g=parseInt(f/100*d),h=$(a).position();h.top=Math.max(0,h.top);h.left=Math.max(0,h.left);this.env.indicator_width=d;this.env.indicator_height=e;g>d&&(g=d,f=100);if(b.title)b.title=this.get_label("quota")+": "+b.title;var k=$("<div>");k.css({position:"absolute",top:h.top,left:h.left,width:d+"px",height:e+"px",zIndex:100,lineHeight:e+"px"}).attr("title",b.title).addClass("quota_text").html(f+"%");var j=$("<div>");j.css({position:"absolute",top:h.top+1,left:h.left+ -1,width:g+"px",height:e+"px",zIndex:99});g=$("<div>");g.css({position:"absolute",top:h.top+1,left:h.left+1,width:d+"px",height:e+"px",zIndex:98}).addClass("quota_bg");f>=80?(k.addClass(" quota_text_high"),j.addClass("quota_high")):f>=55?(k.addClass(" quota_text_mid"),j.addClass("quota_mid")):(k.addClass(" quota_text_low"),j.addClass("quota_low"));$(a).html("").append(j).append(g).append(k);$("#quotaimg").attr("title",b.title)};this.html2plain=function(a,b){var d=this,e=this.set_busy(!0,"converting"); -this.log("HTTP POST: ?_task=utils&_action=html2text");$.ajax({type:"POST",url:"?_task=utils&_action=html2text",data:a,contentType:"application/octet-stream",error:function(a,b,h){d.http_error(a,b,h,e)},success:function(a){d.set_busy(!1,null,e);$(document.getElementById(b)).val(a);d.log(a)}})};this.plain2html=function(a,b){var d=this.set_busy(!0,"converting");$(document.getElementById(b)).val("<pre>"+a+"</pre>");this.set_busy(!1,null,d)};this.url=function(a,b){var d=typeof b==="string"?"&"+b:"";if(typeof a!== -"string")b=a;else if(!b||typeof b!=="object")b={};b._action=a?a:this.env.action;var e=this.env.comm_path;if(b._action.match(/([a-z]+)\/([a-z-_.]+)/))b._action=RegExp.$2,e=e.replace(/\_task=[a-z]+/,"_task="+RegExp.$1);var f={},g;for(g in b)b[g]!==void 0&&b[g]!==null&&(f[g]=b[g]);return e+"&"+$.param(f)+d};this.redirect=function(a,b){(b||b===null)&&this.set_busy(!0);this.is_framed()?parent.rcmail.redirect(a,b):this.location_href(a,window)};this.goto_url=function(a,b){this.redirect(this.url(a,b))};this.location_href= -function(a,b,d){d&&this.lock_frame();bw.ie&&b==window?$("<a>").attr("href",a).appendTo(document.body).get(0).click():b.location.href=a};this.http_request=function(a,b,d){var e=this.url(a,b),a=this.triggerEvent("request"+a,b);if(a!==void 0)if(a===!1)return!1;else b=a;e+="&_remote=1";this.log("HTTP GET: "+e);return $.ajax({type:"GET",url:e,data:{_unlock:d?d:0},dataType:"json",success:function(a){l.http_response(a)},error:function(a,b,e){rcmail.http_error(a,b,e,d)}})};this.http_post=function(a,b,d){var e= -this.url(a);b&&typeof b==="object"?(b._remote=1,b._unlock=d?d:0):b+=(b?"&":"")+"_remote=1"+(d?"&_unlock="+d:"");a=this.triggerEvent("request"+a,b);if(a!==void 0)if(a===!1)return!1;else b=a;this.log("HTTP POST: "+e);return $.ajax({type:"POST",url:e,data:b,dataType:"json",success:function(a){l.http_response(a)},error:function(a,b,e){rcmail.http_error(a,b,e,d)}})};this.abort_request=function(a){a.request&&a.request.abort();a.lock&&this.set_busy(!1,null,a.lock)};this.http_response=function(a){if(a){a.unlock&& -this.set_busy(!1);this.triggerEvent("responsebefore",{response:a});this.triggerEvent("responsebefore"+a.action,{response:a});a.env&&this.set_env(a.env);if(typeof a.texts==="object")for(var b in a.texts)typeof a.texts[b]==="string"&&this.add_label(b,a.texts[b]);a.exec&&(this.log(a.exec),eval(a.exec));if(a.callbacks&&a.callbacks.length)for(b=0;b<a.callbacks.length;b++)this.triggerEvent(a.callbacks[b][0],a.callbacks[b][1]);switch(a.action){case "delete":if(this.task=="addressbook"){var d;b=this.contact_list.get_selection(); -d=!1;b&&this.contact_list.rows[b]&&(d=this.env.source==""?(d=String(b).replace(/^[^-]+-/,""))&&this.env.address_sources[d]&&!this.env.address_sources[d].readonly:!this.env.address_sources[this.env.source].readonly);this.enable_command("compose",b&&this.contact_list.rows[b]);this.enable_command("delete","edit",d);this.enable_command("export",this.contact_list&&this.contact_list.rowcount>0)}case "moveto":this.env.action=="show"?(this.enable_command(this.env.message_commands,!0),this.env.list_post|| -this.enable_command("reply-list",!1)):this.task=="addressbook"&&this.triggerEvent("listupdate",{folder:this.env.source,rowcount:this.contact_list.rowcount});case "purge":case "expunge":this.task=="mail"&&(this.env.messagecount||(this.env.contentframe&&this.show_contentframe(!1),this.enable_command(this.env.message_commands,"purge","expunge","select-all","select-none","sort","expand-all","expand-unread","collapse-all",!1)),this.message_list&&this.triggerEvent("listupdate",{folder:this.env.mailbox, -rowcount:this.message_list.rowcount}));break;case "check-recent":case "getunread":case "search":this.env.qsearch=null;case "list":if(this.task=="mail"){if(this.enable_command("show","expunge","select-all","select-none","sort",this.env.messagecount>0),this.enable_command("purge",this.purge_mailbox_test()),this.enable_command("expand-all","expand-unread","collapse-all",this.env.threading&&this.env.messagecount),a.action=="list"||a.action=="search")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),a.action=="list"||a.action=="search"))this.update_group_commands(),this.triggerEvent("listupdate",{folder:this.env.source,rowcount:this.contact_list.rowcount})}a.unlock&&this.hide_message(a.unlock);this.triggerEvent("responseafter",{response:a});this.triggerEvent("responseafter"+a.action,{response:a})}};this.http_error=function(a, -b,d,e){b=a.statusText;this.set_busy(!1,null,e);a.abort();a.status&&b&&this.display_message(this.get_label("servererror")+" ("+b+")","error")};this.async_upload_form=function(a,b,d){var e=(new Date).getTime(),f="rcmupload"+e;if(this.env.upload_progress_name){var g=this.env.upload_progress_name,h=$("input[name="+g+"]",a);h.length||(h=$("<input>").attr({type:"hidden",name:g}),h.prependTo(a));h.val(e)}document.all?document.body.insertAdjacentHTML("BeforeEnd",'<iframe name="'+f+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'): -(g=document.createElement("iframe"),g.name=f,g.style.border="none",g.style.width=0,g.style.height=0,g.style.visibility="hidden",document.body.appendChild(g));$(f).bind("load",{ts:e},d);$(a).attr({target:f,action:this.url(b,{_id:this.env.compose_id||"",_uploadid:e}),method:"POST"}).attr(a.encoding?"encoding":"enctype","multipart/form-data").submit();return f};this.start_keepalive=function(){this._int&&clearInterval(this._int);if(this.env.keep_alive&&!this.env.framed&&this.task=="mail"&&this.gui_objects.mailboxlist)this._int= -setInterval(function(){l.check_for_recent(!1)},this.env.keep_alive*1E3);else if(this.env.keep_alive&&!this.env.framed&&this.task!="login"&&this.env.action!="print")this._int=setInterval(function(){l.keep_alive()},this.env.keep_alive*1E3)};this.keep_alive=function(){this.busy||this.http_request("keep-alive")};this.check_for_recent=function(a){if(!this.busy){var b,d="_mbox="+urlencode(this.env.mailbox);a&&(b=this.set_busy(!0,"checkingmail"),d+="&_refresh=1",this.start_keepalive());this.gui_objects.messagelist&& -(d+="&_list=1");this.gui_objects.quotadisplay&&(d+="&_quota=1");this.env.search_request&&(d+="&_search="+this.env.search_request);this.http_request("check-recent",d,b)}};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(a){if(a.selectionEnd!==void 0)return a.selectionEnd; -else if(document.selection&&document.selection.createRange){var b=document.selection.createRange();if(b.parentElement()!=a)return 0;var d=b.duplicate();a.tagName=="TEXTAREA"?d.moveToElementText(a):d.expand("textedit");d.setEndPoint("EndToStart",b);b=d.text.length;return b<=a.value.length?b:-1}else return a.value.length};this.set_caret_pos=function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var d=a.createTextRange();d.collapse(!0);d.moveEnd("character",b);d.moveStart("character", -b);d.select()}};this.lock_form=function(a,b){if(a&&a.elements){var d,e,f;if(b)this.disabled_form_elements=[];for(d=0,e=a.elements.length;d<e;d++)if(f=a.elements[d],f.type!="hidden")if(b&&f.disabled)this.disabled_form_elements.push(f);else if(b||this.disabled_form_elements&&$.inArray(f,this.disabled_form_elements)<0)f.disabled=b}}}rcube_webmail.long_subject_title=function(l,t){if(!l.title){var a=$(l);if(a.width()+t*15>a.parent().width())l.title=a.html()}};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.env={recipients_separator:",",recipients_delimiter:", "};this.labels={};this.buttons={};this.buttons_sel={};this.gui_objects={};this.gui_containers={};this.commands={};this.command_handlers={};this.onloads=[];this.messages={};this.ref="rcmail";var i=this;this.dblclick_time=500;this.message_time=4E3;this.identifier_expr=RegExp("[^0-9a-z-_]","gi");this.env.keep_alive=60;this.env.request_timeout=180;this.env.draft_autosave=0;this.env.comm_path="./";this.env.blankpage="program/blank.gif"; +$.ajaxSetup({cache:!1,error:function(a,b,d){i.http_error(a,b,d)},beforeSend:function(a){a.setRequestHeader("X-Roundcube-Request",i.env.request_token)}});this.set_env=function(a,b){if(null!=a&&"object"===typeof a&&!b)for(var d in a)this.env[d]=a[d];else this.env[a]=b};this.add_label=function(a,b){"string"==typeof a?this.labels[a]=b:"object"==typeof a&&$.extend(this.labels,a)};this.register_button=function(a,b,d,e,f,h){this.buttons[a]||(this.buttons[a]=[]);b={id:b,type:d};if(e)b.act=e;if(f)b.sel=f; +if(h)b.over=h;this.buttons[a].push(b);this.loaded&&s(a,b)};this.gui_object=function(a,b){this.gui_objects[a]=this.loaded?rcube_find_object(b):b};this.gui_container=function(a,b){this.gui_containers[a]=b};this.add_element=function(a,b){this.gui_containers[b]&&this.gui_containers[b].jquery&&this.gui_containers[b].append(a)};this.register_command=function(a,b,d){this.command_handlers[a]=b;d&&this.enable_command(a,!0)};this.add_onload=function(a){this.onloads.push(a)};this.init=function(){var a,b=this; +this.task=this.env.task;if(!bw.dom||!bw.xmlhttp_test())this.goto_url("error","_code=0x199");else{for(a in this.gui_containers)this.gui_containers[a]=$("#"+this.gui_containers[a]);for(a in this.gui_objects)this.gui_objects[a]=rcube_find_object(this.gui_objects[a]);if(this.env.x_frame_options)try{if("deny"==this.env.x_frame_options&&top.location.href!=self.location.href)top.location.href=self.location.href;else if(top.location.hostname!=self.location.hostname)throw 1;}catch(d){$("form").each(function(){i.lock_form(this, +!0)});this.display_message("Blocked: possible clickjacking attack!","error");return}this.init_buttons();if(this.is_framed())parent.rcmail.set_busy(!1,null,parent.rcmail.env.frame_lock),parent.rcmail.env.frame_lock=null;this.enable_command("logout","mail","addressbook","settings","save-pref","compose","undo",!0);this.env.permaurl&&this.enable_command("permaurl",!0);switch(this.task){case "mail":this.enable_command("list","checkmail","add-contact","search","reset-search","collapse-folder",!0);if(this.gui_objects.messagelist)this.message_list= +new rcube_list_widget(this.gui_objects.messagelist,{multiselect:!0,multiexpand:!0,draggable:!0,keyboard:!0,column_movable:this.env.col_movable,dblclick_time:this.dblclick_time}),this.message_list.row_init=function(a){b.init_message_row(a)},this.message_list.addEventListener("dblclick",function(a){b.msglist_dbl_click(a)}),this.message_list.addEventListener("click",function(a){b.msglist_click(a)}),this.message_list.addEventListener("keypress",function(a){b.msglist_keypress(a)}),this.message_list.addEventListener("select", +function(a){b.msglist_select(a)}),this.message_list.addEventListener("dragstart",function(a){b.drag_start(a)}),this.message_list.addEventListener("dragmove",function(a){b.drag_move(a)}),this.message_list.addEventListener("dragend",function(a){b.drag_end(a)}),this.message_list.addEventListener("expandcollapse",function(a){b.msglist_expand(a)}),this.message_list.addEventListener("column_replace",function(a){b.msglist_set_coltypes(a)}),document.onmouseup=function(a){return b.doc_mouse_up(a)},this.gui_objects.messagelist.parentNode.onmousedown= +function(a){return b.click_on_list(a)},this.message_list.init(),this.enable_command("toggle_status","toggle_flag","menu-open","menu-save",!0),this.command("list");if(this.gui_objects.qsearchbox){if(null!=this.env.search_text)this.gui_objects.qsearchbox.value=this.env.search_text;$(this.gui_objects.qsearchbox).focusin(function(){rcmail.message_list.blur()})}!this.env.flag_for_deletion&&this.env.trash_mailbox&&this.env.mailbox!=this.env.trash_mailbox&&this.set_alttext("delete","movemessagetotrash"); +this.env.message_commands="show,reply,reply-all,reply-list,forward,moveto,copy,delete,open,mark,edit,viewsource,download,print,load-attachment,load-headers,forward-attachment".split(",");if("show"==this.env.action||"preview"==this.env.action){this.enable_command(this.env.message_commands,this.env.uid);this.enable_command("reply-list",this.env.list_post);"show"==this.env.action&&this.http_request("pagenav","_uid="+this.env.uid+"&_mbox="+urlencode(this.env.mailbox)+(this.env.search_request?"&_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",!0)}"preview"==this.env.action&&this.is_framed()&&(this.enable_command("compose","add-contact",!1),parent.rcmail.show_contentframe(!0))}else if("compose"==this.env.action){this.env.compose_commands=["send-attachment","remove-attachment","send","cancel","toggle-editor"]; +this.env.drafts_mailbox&&this.env.compose_commands.push("savedraft");this.enable_command(this.env.compose_commands,"identities",!0);if(this.env.spellcheck)this.env.spellcheck.spelling_state_observer=function(a){i.set_spellcheck_state(a)},this.env.compose_commands.push("spellcheck"),this.set_spellcheck_state("ready"),"1"==$("input[name='_is_html']").val()&&this.display_spellcheck_controls(!1);document.onmouseup=function(a){return b.doc_mouse_up(a)};this.init_messageform()}else"print"==this.env.action&& +this.env.uid&&(bw.safari?window.setTimeout("window.print()",10):window.print());if(this.gui_objects.mailboxlist)this.env.unread_counts={},this.gui_objects.folderlist=this.gui_objects.mailboxlist,this.http_request("getunread","");this.env.mdn_request&&this.env.uid&&(a="_uid="+this.env.uid+"&_mbox="+urlencode(this.env.mailbox),confirm(this.get_label("mdnrequest"))?this.http_post("sendmdn",a):this.http_post("mark",a+"&_flag=mdnsent"));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",!0);if(this.gui_objects.contactslist)this.contact_list=new rcube_list_widget(this.gui_objects.contactslist,{multiselect:!0,draggable:this.gui_objects.folderlist?!0:!1,keyboard:!0}),this.contact_list.row_init=function(a){b.triggerEvent("insertrow",{cid:a.uid,row:a})},this.contact_list.addEventListener("keypress", +function(a){b.contactlist_keypress(a)}),this.contact_list.addEventListener("select",function(a){b.contactlist_select(a)}),this.contact_list.addEventListener("dragstart",function(a){b.drag_start(a)}),this.contact_list.addEventListener("dragmove",function(a){b.drag_move(a)}),this.contact_list.addEventListener("dragend",function(a){b.drag_end(a)}),this.contact_list.init(),this.env.cid&&this.contact_list.highlight_row(this.env.cid),this.gui_objects.contactslist.parentNode.onmousedown=function(a){return b.click_on_list(a)}, +document.onmouseup=function(a){return b.doc_mouse_up(a)},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();this.env.cid&&(this.enable_command("show","edit",!0),this.gui_objects.editform&&$("input.groupmember").change(function(){i.group_member_change(this.checked?"add":"del",i.env.cid,i.env.source,this.value)}));this.gui_objects.editform&&(this.enable_command("save",!0), +("add"==this.env.action||"edit"==this.env.action)&&this.init_contact_form());this.gui_objects.qsearchbox&&this.enable_command("search","reset-search","moveto",!0);break;case "settings":this.enable_command("preferences","identities","save","folders",!0);if("identities"==this.env.action)this.enable_command("add",2>this.env.identities_level);else if("edit-identity"==this.env.action||"add-identity"==this.env.action)this.enable_command("add",2>this.env.identities_level),this.enable_command("save","delete", +"edit","toggle-editor",!0);else if("folders"==this.env.action)this.enable_command("subscribe","unsubscribe","create-folder","rename-folder",!0);else if("edit-folder"==this.env.action&&this.gui_objects.editform)this.enable_command("save","folder-size",!0),parent.rcmail.env.messagecount=this.env.messagecount,parent.rcmail.enable_command("purge",this.env.messagecount),$("input[type='text']").first().select();this.gui_objects.identitieslist?(this.identity_list=new rcube_list_widget(this.gui_objects.identitieslist, +{multiselect:!1,draggable:!1,keyboard:!1}),this.identity_list.addEventListener("select",function(a){b.identity_select(a)}),this.identity_list.init(),this.identity_list.focus(),this.env.iid&&this.identity_list.highlight_row(this.env.iid)):this.gui_objects.sectionslist?(this.sections_list=new rcube_list_widget(this.gui_objects.sectionslist,{multiselect:!1,draggable:!1,keyboard:!1}),this.sections_list.addEventListener("select",function(a){b.section_select(a)}),this.sections_list.init(),this.sections_list.focus()): +this.gui_objects.subscriptionlist&&this.init_subscription_list();break;case "login":a=$("#rcmloginuser");a.bind("keyup",function(a){return rcmail.login_user_keyup(a)});""==a.val()?a.focus():$("#rcmloginpwd").focus();var e=new Date;a=e.getTimezoneOffset()/-60;e=e.getStdTimezoneOffset()/-60;$("#rcmlogintz").val(e);$("#rcmlogindst").val(a>e?1:0);$("form").submit(function(){$("input[type=submit]",this).prop("disabled",!0);rcmail.display_message("","loading")});this.enable_command("login",!0)}bw.ie&&$("input[type=file]").keydown(function(a){"13"== +a.keyCode&&a.preventDefault()});this.loaded=!0;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);this.triggerEvent("init",{task:this.task,action:this.env.action});for(var f in this.onloads)if("string"===typeof this.onloads[f])eval(this.onloads[f]);else if("function"===typeof this.onloads[f])this.onloads[f]();this.start_keepalive()}};this.log= +function(a){window.console&&console.log&&console.log(a)};this.command=function(a,b,d){var e,f,h,g;d&&d.blur&&d.blur();if(this.busy)return!1;if(!this.commands[a])return this.is_framed()&&parent.rcmail.command(a,b),!1;if("mail"==this.task&&"compose"==this.env.action&&0>$.inArray(a,this.env.compose_commands)&&this.cmp_hash!=this.compose_field_hash()&&!confirm(this.get_label("notsentwarning")))return!1;if("function"===typeof this.command_handlers[a])return e=this.command_handlers[a](b,d),void 0!==e?e: +d?!1:!0;if("string"===typeof this.command_handlers[a])return e=window[this.command_handlers[a]](b,d),void 0!==e?e:d?!1:!0;this.triggerEvent("actionbefore",{props:b,action:a});e=this.triggerEvent("before"+a,b);if(void 0!==e){if(!1===e)return!1;b=e}e=void 0;switch(a){case "login":this.gui_objects.loginform&&this.gui_objects.loginform.submit();break;case "mail":case "addressbook":case "settings":case "logout":this.switch_task(a);break;case "permaurl":if(d&&d.href&&d.target)return!0;if(this.env.permaurl)parent.location.href= +this.env.permaurl;break;case "menu-open":case "menu-save":return this.triggerEvent(a,{props:b}),!1;case "open":if(f=this.get_single_uid())return d.href="?_task="+this.env.task+"&_action=show&_mbox="+urlencode(this.env.mailbox)+"&_uid="+f,!0;break;case "list":this.reset_qsearch();"mail"==this.task?(this.list_mailbox(b),this.env.trash_mailbox&&!this.env.flag_for_deletion&&this.set_alttext("delete",this.env.mailbox!=this.env.trash_mailbox?"movemessagetotrash":"deletemessage")):"addressbook"==this.task&& +this.list_contacts(b);break;case "load-headers":this.load_headers(d);break;case "sort":f=b;g=this.env.sort_col==f?"ASC"==this.env.sort_order?"DESC":"ASC":"ASC";this.set_list_sorting(f,g);this.list_mailbox("","",f+"_"+g);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":this.env.messagecount&&this.expunge_mailbox(this.env.mailbox);break;case "purge":case "empty-mailbox":this.env.messagecount&& +this.purge_mailbox(this.env.mailbox);break;case "show":if("mail"==this.task){if((f=this.get_single_uid())&&(!this.env.uid||f!=this.env.uid))this.env.mailbox==this.env.drafts_mailbox?this.goto_url("compose","_draft_uid="+f+"&_mbox="+urlencode(this.env.mailbox),!0):this.show_message(f)}else"addressbook"==this.task&&(h=b?b:this.get_single_cid())&&!("show"==this.env.action&&h==this.env.cid)&&this.load_contact(h,"show");break;case "add":"addressbook"==this.task?this.load_contact(0,"add"):"settings"==this.task&& +(this.identity_list.clear_selection(),this.load_identity(0,"add-identity"));break;case "edit":if("addressbook"==this.task&&(h=this.get_single_cid()))this.load_contact(h,"edit");else if("settings"==this.task&&b)this.load_identity(b,"edit-identity");else if("mail"==this.task&&(h=this.get_single_uid()))g=this.env.mailbox==this.env.drafts_mailbox?"_draft_uid=":"_uid=",this.goto_url("compose",g+h+"&_mbox="+urlencode(this.env.mailbox),!0);break;case "save":var k;if(g=this.gui_objects.editform){if("search"!= +this.env.action)if((k=$("input[name='_pagesize']",g))&&k.length&&isNaN(parseInt(k.val()))){alert(this.get_label("nopagesizewarning"));k.focus();break}else{if("reload"==b)g.action+="?_reload=1";else if("settings"==this.task&&0==this.env.identities_level%2&&(k=$("input[name='_email']",g))&&k.length&&!rcube_check_email(k.val())){alert(this.get_label("noemailwarning"));k.focus();break}$("input.placeholder").each(function(){if(this.value==this._placeholder)this.value=""})}if(parent.rcmail&&parent.rcmail.env.source)g.action= +this.add_url(g.action,"_orig_source",parent.rcmail.env.source);g.submit()}break;case "delete":"mail"==this.task?this.delete_messages():"addressbook"==this.task?this.delete_contacts():"settings"==this.task&&this.delete_identity();break;case "move":case "moveto":"mail"==this.task?this.move_messages(b):"addressbook"==this.task&&this.drag_active&&this.copy_contact(null,b);break;case "copy":"mail"==this.task&&this.copy_messages(b);break;case "mark":b&&this.mark_message(b);break;case "toggle_status":if(b&& +!b._row)break;g="read";if(b._row.uid)f=b._row.uid,this.message_list.rows[f].deleted?g="undelete":this.message_list.rows[f].unread||(g="unread");this.mark_message(g,f);break;case "toggle_flag":if(b&&!b._row)break;g="flagged";if(b._row.uid)f=b._row.uid,this.message_list.rows[f].flagged&&(g="unflagged");this.mark_message(g,f);break;case "always-load":if(this.env.uid&&this.env.sender){this.add_contact(urlencode(this.env.sender));window.setTimeout(function(){i.command("load-images")},300);break}case "load-images":this.env.uid&& +this.show_message(this.env.uid,!0,"preview"==this.env.action);break;case "load-attachment":g="_mbox="+urlencode(this.env.mailbox)+"&_uid="+this.env.uid+"&_part="+b.part;if(this.env.uid&&b.mimetype&&this.env.mimetypes&&0<=$.inArray(b.mimetype,this.env.mimetypes)&&("text/html"==b.mimetype&&(g+="&_safe=1"),this.attachment_win=window.open(this.env.comm_path+"&_action=get&"+g+"&_frame=1","rcubemailattachment"))){window.setTimeout(function(){i.attachment_win.focus()},10);break}this.goto_url("get",g+"&_download=1", +!1);break;case "select-all":this.select_all_mode=b?!1:!0;this.dummy_select=!0;"invert"==b?this.message_list.invert_selection():this.message_list.select_all("page"==b?"":b);this.dummy_select=null;break;case "select-none":this.select_all_mode=!1;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":this.env.next_uid&&this.show_message(this.env.next_uid,!1,"preview"==this.env.action);break;case "lastmessage":this.env.last_uid&&this.show_message(this.env.last_uid);break;case "previousmessage":this.env.prev_uid&&this.show_message(this.env.prev_uid,!1,"preview"==this.env.action);break;case "firstmessage":this.env.first_uid&&this.show_message(this.env.first_uid);break;case "checkmail":this.check_for_recent(!0);break;case "compose":g=this.url("mail/compose"); +if("mail"==this.task)g+="&_mbox="+urlencode(this.env.mailbox),b&&(g+="&_to="+urlencode(b));else if("addressbook"==this.task){if(b&&0<b.indexOf("@")){g=this.get_task_url("mail",g);this.redirect(g+"&_to="+urlencode(b));break}h=[];if(b)h.push(b);else if(this.contact_list){k=this.contact_list.get_selection();for(g=0,f=k.length;g<f;g++)h.push(k[g])}h.length?this.http_post("mailto",{_cid:h.join(","),_source:this.env.source},!0):this.env.group&&this.http_post("mailto",{_gid:this.env.group,_source:this.env.source}, +!0);break}else b&&(g+="&_to="+urlencode(b));this.redirect(g);break;case "spellcheck":window.tinyMCE&&tinyMCE.get(this.env.composebody)?tinyMCE.execCommand("mceSpellCheck",!0):this.env.spellcheck&&this.env.spellcheck.spellCheck&&this.spellcheck_ready&&(this.env.spellcheck.spellCheck(),this.set_spellcheck_state("checking"));break;case "savedraft":self.clearTimeout(this.save_timer);if(!this.gui_objects.messageform)break;if(!this.env.drafts_mailbox||this.cmp_hash==this.compose_field_hash())break;g=this.gui_objects.messageform; +f=this.set_busy(!0,"savingmessage");g.target="savetarget";g._draft.value="1";g.action=this.add_url(g.action,"_unlock",f);g.submit();break;case "send":if(!this.gui_objects.messageform)break;if(!b.nocheck&&!this.check_compose_input(a))break;self.clearTimeout(this.save_timer);h=this.spellcheck_lang();g=this.gui_objects.messageform;f=this.set_busy(!0,"sendingmessage");g.target="savetarget";g._draft.value="";g.action=this.add_url(g.action,"_unlock",f);g.action=this.add_url(g.action,"_lang",h);g.submit(); +clearTimeout(this.request_timer);break;case "send-attachment":self.clearTimeout(this.save_timer);this.upload_file(b);break;case "insert-sig":this.change_identity($("[name='_from']")[0],!0);break;case "reply-all":case "reply-list":case "reply":if(f=this.get_single_uid())g="_reply_uid="+f+"&_mbox="+urlencode(this.env.mailbox),"reply-all"==a?g+="&_all="+(!b&&this.commands["reply-list"]?"list":"all"):"reply-list"==a&&(g+="&_all=list"),this.goto_url("compose",g,!0);break;case "forward-attachment":case "forward":if(f= +this.get_single_uid()){g="_forward_uid="+f+"&_mbox="+urlencode(this.env.mailbox);if("forward-attachment"==a||!b&&this.env.forward_attachment)g+="&_attachment=1";this.goto_url("compose",g,!0)}break;case "print":if(f=this.get_single_uid())i.printwin=window.open(this.env.comm_path+"&_action=print&_uid="+f+"&_mbox="+urlencode(this.env.mailbox)+(this.env.safemode?"&_safe=1":"")),this.printwin&&(window.setTimeout(function(){i.printwin.focus()},20),"show"!=this.env.action&&this.mark_message("read",f));break; +case "viewsource":if(f=this.get_single_uid())i.sourcewin=window.open(this.env.comm_path+"&_action=viewsource&_uid="+f+"&_mbox="+urlencode(this.env.mailbox)),this.sourcewin&&window.setTimeout(function(){i.sourcewin.focus()},20);break;case "download":(f=this.get_single_uid())&&this.goto_url("viewsource","&_uid="+f+"&_mbox="+urlencode(this.env.mailbox)+"&_save=1");break;case "search":if(!b&&this.gui_objects.qsearchbox)b=this.gui_objects.qsearchbox.value;if(b){this.qsearch(b);break}case "reset-search":f= +this.env.search_request||this.env.qsearch;this.reset_qsearch();this.select_all_mode=!1;if(f&&this.env.mailbox)this.list_mailbox(this.env.mailbox,1);else if(f&&"addressbook"==this.task){if(""==this.env.source){for(g in this.env.address_sources)break;this.env.source=g;this.env.group=""}this.list_contacts(this.env.source,this.env.group,1)}break;case "listgroup":this.reset_qsearch();this.list_contacts(b.source,b.id);break;case "import":if("import"==this.env.action&&this.gui_objects.importform){if((g= +document.getElementById("rcmimportfile"))&&!g.value){alert(this.get_label("selectimportfile"));break}this.gui_objects.importform.submit();this.set_busy(!0,"importwait");this.lock_form(this.gui_objects.importform,!0)}else this.goto_url("import",this.env.source?"_target="+urlencode(this.env.source)+"&":"");break;case "export":0<this.contact_list.rowcount&&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(b); +break;case "delete-photo":this.replace_contact_photo("-del-");break;case "preferences":case "identities":case "folders":this.goto_url("settings/"+a);break;case "undo":this.http_request("undo","",this.display_message("","loading"));break;default:g=a.replace(/-/g,"_"),this[g]&&"function"===typeof this[g]&&(e=this[g](b))}!1===this.triggerEvent("after"+a,b)&&(e=!1);this.triggerEvent("actionafter",{props:b,action:a});return!1===e?!1:d?!1:!0};this.enable_command=function(){var a,b,d=Array.prototype.slice.call(arguments), +e=d.pop(),f;for(b=0;b<d.length;b++)if(f=d[b],"string"===typeof f)this.commands[f]=e,this.set_button(f,e?"act":"pas");else for(a in f)d.push(f[a])};this.set_busy=function(a,b,d){a&&b?(d=this.get_label(b),d==b&&(d="Loading..."),d=this.display_message(d,"loading")):!a&&d&&this.hide_message(d);this.busy=a;this.gui_objects.editform&&this.lock_form(this.gui_objects.editform,a);this.request_timer&&clearTimeout(this.request_timer);if(a&&this.env.request_timeout)this.request_timer=window.setTimeout(function(){i.request_timed_out()}, +1E3*this.env.request_timeout);return d};this.gettext=this.get_label=function(a,b){return b&&this.labels[b+"."+a]?this.labels[b+"."+a]:this.labels[a]?this.labels[a]:a};this.switch_task=function(a){if(!(this.task===a&&"mail"!=a)){var b=this.get_task_url(a);"mail"==a&&(b+="&_mbox=INBOX");this.redirect(b)}};this.get_task_url=function(a,b){if(!b)b=this.env.comm_path;return b.replace(/_task=[a-z]+/,"_task="+a)};this.request_timed_out=function(){this.set_busy(!1);this.display_message("Request timed out!", +"error")};this.reload=function(a){if(this.is_framed())parent.rcmail.reload(a);else if(a)window.setTimeout(function(){rcmail.reload()},a);else if(window.location)location.href=this.env.comm_path+(this.env.action?"&_action="+this.env.action:"")};this.add_url=function(a,b,d){d=urlencode(d);if(/(\?.*)$/.test(a)){var e=RegExp.$1,f=RegExp("((\\?|&)"+RegExp.escape(b)+"=[^&]*)"),e=f.test(e)?e.replace(f,RegExp.$2+b+"="+d):e+("&"+b+"="+d);return a.replace(/(\?.*)$/,e)}return a+"?"+b+"="+d};this.is_framed=function(){return this.env.framed&& +parent.rcmail&&parent.rcmail!=this&&parent.rcmail.command};this.save_pref=function(a){var b={_name:a.name,_value:a.value};if(a.session)b._session=a.session;if(a.env)this.env[a.env]=a.value;this.http_post("save-pref",b)};this.html_identifier=function(a,b){a=""+a;return b?Base64.encode(a).replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_"):a.replace(this.identifier_expr,"_")};this.html_identifier_decode=function(a){for(a=(""+a).replace(/-/g,"+").replace(/_/g,"/");a.length%4;)a+="=";return Base64.decode(a)}; +this.drag_menu=function(a,b){var d=rcube_event.get_modifier(a),e=this.gui_objects.message_dragmenu;return e&&d==SHIFT_KEY&&this.commands.copy?(d=rcube_event.get_mouse_pos(a),this.env.drag_target=b,$(e).css({top:d.y-10+"px",left:d.x-10+"px"}).show(),!0):!1};this.drag_menu_action=function(a){var b=this.gui_objects.message_dragmenu;b&&$(b).hide();this.command(a,this.env.drag_target);this.env.drag_target=null};this.drag_start=function(a){var b="mail"==this.task?this.env.mailboxes:this.env.contactfolders; +this.drag_active=!0;this.preview_timer&&clearTimeout(this.preview_timer);this.preview_read_timer&&clearTimeout(this.preview_read_timer);if(this.gui_objects.folderlist&&b){this.initialBodyScrollTop=bw.ie?0:window.pageYOffset;this.initialListScrollTop=this.gui_objects.folderlist.parentNode.scrollTop;var d,e,a=$(this.gui_objects.folderlist);pos=a.offset();this.env.folderlist_coords={x1:pos.left,y1:pos.top,x2:pos.left+a.width(),y2:pos.top+a.height()};this.env.folder_coords=[];for(d in b)if(a=this.get_folder_li(d))if(e= +a.firstChild.offsetHeight)pos=$(a.firstChild).offset(),this.env.folder_coords[d]={x1:pos.left,y1:pos.top,x2:pos.left+a.firstChild.offsetWidth,y2:pos.top+e,on:0}}};this.drag_end=function(){this.drag_active=!1;this.env.last_folder_target=null;if(this.folder_auto_timer)window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=this.folder_auto_timer=null;if(this.gui_objects.folderlist&&this.env.folder_coords)for(var a in this.env.folder_coords)this.env.folder_coords[a].on&&$(this.get_folder_li(a)).removeClass("droptarget")}; +this.drag_move=function(a){if(this.gui_objects.folderlist&&this.env.folder_coords){var b,d,e,f,h;d="draglayernormal";a=rcube_event.get_mouse_pos(a);f=this.env.folderlist_coords;e=bw.ie?-document.documentElement.scrollTop:this.initialBodyScrollTop;var g=this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop;this.contact_list&&this.contact_list.draglayer&&(h=this.contact_list.draglayer.attr("class"));a.y+=-g-e;if(a.x<f.x1||a.x>=f.x2||a.y<f.y1||a.y>=f.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}else for(b in this.env.folder_coords)if(f=this.env.folder_coords[b],a.x>=f.x1&&a.x<f.x2&&a.y>=f.y1&&a.y<f.y2)if(f=this.check_droptarget(b)){d=this.get_folder_li(b);e=$(d.getElementsByTagName("div")[0]);if(e.hasClass("collapsed"))this.folder_auto_timer&&window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=b,this.folder_auto_timer=window.setTimeout(function(){rcmail.command("collapse-folder",rcmail.folder_auto_expand); +rcmail.drag_start(null)},1E3);else if(this.folder_auto_timer)window.clearTimeout(this.folder_auto_timer),this.folder_auto_expand=this.folder_auto_timer=null;$(d).addClass("droptarget");this.env.folder_coords[b].on=1;this.env.last_folder_target=b;d="draglayer"+(1<f?"copy":"normal")}else this.env.last_folder_target=null;else if(f.on)$(this.get_folder_li(b)).removeClass("droptarget"),this.env.folder_coords[b].on=0;d!=h&&this.contact_list&&this.contact_list.draglayer&&this.contact_list.draglayer.attr("class", +d)}};this.collapse_folder=function(a){var b=this.get_folder_li(a,"",!0),d=$("div:first",b),e=$("ul:first",b);if(d.hasClass("collapsed"))e.show(),d.removeClass("collapsed").addClass("expanded"),this.env.collapsed_folders=this.env.collapsed_folders.replace(RegExp("&"+urlencode(a)+"&"),"");else if(d.hasClass("expanded"))e.hide(),d.removeClass("expanded").addClass("collapsed"),this.env.collapsed_folders=this.env.collapsed_folders+"&"+urlencode(a)+"&",0==this.env.mailbox.indexOf(a+this.env.delimiter)&& +this.command("list",a);else return;if(bw.ie6||bw.ie7)if((d=b.nextSibling?b.nextSibling.getElementsByTagName("ul"):null)&&d.length&&(b=d[0])&&b.style&&"none"!=b.style.display)b.style.display="none",b.style.display="";this.command("save-pref",{name:"collapsed_folders",value:this.env.collapsed_folders});this.set_unread_count_display(a,!1)};this.doc_mouse_up=function(a){var b,d,e;if(!$(rcube_event.get_target(a)).closest(".ui-dialog, .ui-widget-overlay").length){(d=this.message_list)?(rcube_mouse_is_over(a, +d.list.parentNode)?d.focus():d.blur(),b=this.env.mailboxes):(d=this.contact_list)?(rcube_mouse_is_over(a,d.list.parentNode)?d.focus():d.blur(),b=this.env.contactfolders):this.ksearch_value&&this.ksearch_blur();if(this.drag_active&&b&&this.env.last_folder_target)b=b[this.env.last_folder_target],$(this.get_folder_li(this.env.last_folder_target)).removeClass("droptarget"),this.env.last_folder_target=null,d.draglayer.hide(),this.drag_menu(a,b)||this.command("moveto",b);if(this.buttons_sel){for(e in this.buttons_sel)"function"!== +typeof e&&this.button_out(this.buttons_sel[e],e);this.buttons_sel={}}}};this.click_on_list=function(){this.gui_objects.qsearchbox&&this.gui_objects.qsearchbox.blur();this.message_list?this.message_list.focus():this.contact_list&&this.contact_list.focus();return!0};this.msglist_select=function(a){this.preview_timer&&clearTimeout(this.preview_timer);this.preview_read_timer&&clearTimeout(this.preview_read_timer);var b=null!=a.get_single_selection();this.enable_command(this.env.message_commands,b);b&& +(this.env.mailbox==this.env.drafts_mailbox?this.enable_command("reply","reply-all","reply-list","forward","forward-attachment",!1):this.env.messages[a.get_single_selection()].ml||this.enable_command("reply-list",!1));this.enable_command("delete","moveto","copy","mark",0<a.selection.length?!0:!1);if(b||a.selection.length&&a.selection.length!=a.rowcount)this.select_all_mode=!1;b&&this.env.contentframe&&!a.multi_selecting&&!this.dummy_select?this.preview_timer=window.setTimeout(function(){i.msglist_get_preview()}, +200):this.env.contentframe&&this.show_contentframe(!1)};this.msglist_click=function(a){if(!a.multi_selecting&&this.env.contentframe&&a.get_single_selection()&&window.frames&&window.frames[this.env.contentframe]&&0<=window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage))this.preview_timer&&clearTimeout(this.preview_timer),this.preview_read_timer&&clearTimeout(this.preview_read_timer),this.preview_timer=window.setTimeout(function(){i.msglist_get_preview()},200)};this.msglist_dbl_click= +function(a){this.preview_timer&&clearTimeout(this.preview_timer);this.preview_read_timer&&clearTimeout(this.preview_read_timer);(a=a.get_single_selection())&&this.env.mailbox==this.env.drafts_mailbox?this.goto_url("compose","_draft_uid="+a+"&_mbox="+urlencode(this.env.mailbox),!0):a&&this.show_message(a,!1,!1)};this.msglist_keypress=function(a){a.modkey!=CONTROL_KEY&&(a.key_pressed==a.ENTER_KEY?this.command("show"):a.key_pressed==a.DELETE_KEY||a.key_pressed==a.BACKSPACE_KEY?this.command("delete"): +33==a.key_pressed?this.command("previouspage"):34==a.key_pressed&&this.command("nextpage"))};this.msglist_get_preview=function(){var a=this.get_single_uid();a&&this.env.contentframe&&!this.drag_active?this.show_message(a,!1,!0):this.env.contentframe&&this.show_contentframe(!1)};this.msglist_expand=function(a){if(this.env.messages[a.uid])this.env.messages[a.uid].expanded=a.expanded};this.msglist_set_coltypes=function(a){var b,d=a.list.tHead.rows[0].cells;this.env.coltypes=[];for(a=0;a<d.length;a++)d[a].id&& +d[a].id.match(/^rcm/)&&(b=d[a].id.replace(/^rcm/,""),this.env.coltypes.push("to"==b?"from":b));if(0<=(a=$.inArray("flag",this.env.coltypes)))this.env.flagged_col=a;if(0<=(a=$.inArray("subject",this.env.coltypes)))this.env.subject_col=a;this.command("save-pref",{name:"list_cols",value:this.env.coltypes,session:"list_attrib/columns"})};this.check_droptarget=function(a){var b=!1,d=!1;if("mail"==this.task)b=this.env.mailboxes[a]&&this.env.mailboxes[a].id!=this.env.mailbox&&!this.env.mailboxes[a].virtual; +else if("settings"==this.task)b=a!=this.env.mailbox;else if("addressbook"==this.task&&a!=this.env.source&&this.env.contactfolders[a])"group"==this.env.contactfolders[a].type?(d=this.env.contactfolders[a].source,b=this.env.contactfolders[a].id!=this.env.group&&!this.env.contactfolders[d].readonly,d=d!=this.env.source):(b=!this.env.contactfolders[a].readonly,d=!0);return b?d?2:1:0};this.init_message_row=function(a){var b,d=this,e=a.uid,f=(null!=this.env.status_col?"status":"msg")+"icn"+a.uid;e&&this.env.messages[e]&& +$.extend(a,this.env.messages[e]);if(a.icon=document.getElementById(f))a.icon._row=a.obj,a.icon.onmousedown=function(a){d.command("toggle_status",this);rcube_event.cancel(a)};a.msgicon=null!=this.env.status_col?document.getElementById("msgicn"+a.uid):a.icon;if(null!=this.env.flagged_col&&(a.flagicon=document.getElementById("flagicn"+a.uid)))a.flagicon._row=a.obj,a.flagicon.onmousedown=function(a){d.command("toggle_flag",this);rcube_event.cancel(a)};if(!a.depth&&a.has_children&&(b=document.getElementById("rcmexpando"+ +a.uid)))a.expando=b,b.onmousedown=function(a){return d.expand_message_row(a,e)};this.triggerEvent("insertrow",{uid:e,row:a})};this.add_message_row=function(a,b,d,e){if(!this.gui_objects.messagelist||!this.message_list||d.mbox!=this.env.mailbox&&!d.skip_mbox_check)return!1;this.env.messages[a]||(this.env.messages[a]={});$.extend(this.env.messages[a],{deleted:d.deleted?1:0,replied:d.answered?1:0,unread:!d.seen?1:0,forwarded:d.forwarded?1:0,flagged:d.flagged?1:0,has_children:d.has_children?1:0,depth:d.depth? +d.depth:0,unread_children:d.unread_children?d.unread_children:0,parent_uid:d.parent_uid?d.parent_uid:0,selected:this.select_all_mode||this.message_list.in_selection(a),ml:d.ml?1:0,ctype:d.ctype,flags:d.extra_flags});var f,h,g,k="",j="",l=this.message_list;g=l.rows;var i=this.env.messages[a];f="message"+(!d.seen?" unread":"")+(d.deleted?" deleted":"")+(d.flagged?" flagged":"")+(d.unread_children&&d.seen&&!this.env.autoexpand_threads?" unroot":"")+(i.selected?" selected":"");var m=document.createElement("tr"); +m.id="rcmrow"+a;m.className=f;f="msgicon";null===this.env.status_col&&(f+=" status",d.deleted?f+=" deleted":d.seen?0<d.unread_children&&(f+=" unreadchildren"):f+=" unread");d.answered&&(f+=" replied");d.forwarded&&(f+=" forwarded");i.selected&&!l.in_selection(a)&&l.selection.push(a);if(this.env.threading)if(i.depth)k+='<span id="rcmtab'+a+'" class="branch" style="width:'+15*i.depth+'px;"> </span>',g[i.parent_uid]&&!1===g[i.parent_uid].expanded||(0==this.env.autoexpand_threads||2==this.env.autoexpand_threads)&& +(!g[i.parent_uid]||!g[i.parent_uid].expanded)?(m.style.display="none",i.expanded=!1):i.expanded=!0;else if(i.has_children){if(void 0===i.expanded&&(1==this.env.autoexpand_threads||2==this.env.autoexpand_threads&&i.unread_children))i.expanded=!0;j='<div id="rcmexpando'+a+'" class="'+(i.expanded?"expanded":"collapsed")+'"> </div>'}k+='<span id="msgicn'+a+'" class="'+f+'"> </span>';if(!bw.ie&&b.subject)g=d.mbox==this.env.drafts_mailbox?"_draft_uid":"_uid",b.subject='<a href="./?_task=mail&_action='+ +(d.mbox==this.env.drafts_mailbox?"compose":"show")+"&_mbox="+urlencode(d.mbox)+"&"+g+"="+a+'" onclick="return rcube_event.cancel(event)" onmouseover="rcube_webmail.long_subject_title(this,'+(i.depth+1)+')">'+b.subject+"</a>";for(h in this.env.coltypes){f=this.env.coltypes[h];g=document.createElement("td");g.className=(""+f).toLowerCase();if("flag"==f)f=d.flagged?"flagged":"unflagged",f='<span id="flagicn'+a+'" class="'+f+'"> </span>';else if("attachment"==f)f=/application\/|multipart\/m/.test(d.ctype)? +'<span class="attachment"> </span>':/multipart\/report/.test(d.ctype)?'<span class="report"> </span>':" ";else if("status"==f)f=d.deleted?"deleted":d.seen?0<d.unread_children?"unreadchildren":"msgicon":"unread",f='<span id="statusicn'+a+'" class="'+f+'"> </span>';else if("threads"==f)f=j;else if("subject"==f){if(bw.ie)g.onmouseover=function(){rcube_webmail.long_subject_title_ie(this,i.depth+1)};f=k+b[f]}else f="priority"==f?0<d.prio&&6>d.prio?'<span class="prio'+d.prio+'"> </span>': +" ":b[f];g.innerHTML=f;m.appendChild(g)}l.insert_row(m,e);e&&this.env.pagesize&&l.rowcount>this.env.pagesize&&(a=l.get_last_row(),l.remove_row(a),l.clear_selection(a))};this.set_list_sorting=function(a,b){$("#rcm"+this.env.sort_col).removeClass("sorted"+this.env.sort_order.toUpperCase());a&&$("#rcm"+a).addClass("sorted"+b);this.env.sort_col=a;this.env.sort_order=b};this.set_list_options=function(a,b,d,e){var f,h="";if(void 0===b)b=this.env.sort_col;if(!d)d=this.env.sort_order;if(this.env.sort_col!= +b||this.env.sort_order!=d)f=1,this.set_list_sorting(b,d);this.env.threading!=e&&(f=1,h+="&_threads="+e);if(a&&a.length){for(var g,k,j=[],i=this.env.coltypes,e=0;e<i.length;e++)k="to"==i[e]?"from":i[e],g=$.inArray(k,a),-1!=g&&(j.push(k),delete a[g]);for(e=0;e<a.length;e++)a[e]&&j.push(a[e]);j.join()!=i.join()&&(f=1,h+="&_cols="+j.join(","))}f&&this.list_mailbox("","",b+"_"+d,h)};this.show_message=function(a,b,d){if(a){var e=window,f=d?"preview":"show",h="&_action="+f+"&_uid="+a+"&_mbox="+urlencode(this.env.mailbox); +d&&this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(e=window.frames[this.env.contentframe],h+="&_framed=1");b&&(h+="&_safe=1");this.env.search_request&&(h+="&_search="+this.env.search_request);if("preview"==f&&0<=(""+e.location.href).indexOf(h))this.show_contentframe(!0);else if(this.location_href(this.env.comm_path+h,e,!0),"preview"==f&&this.message_list&&this.message_list.rows[a]&&this.message_list.rows[a].unread&&0<=this.env.preview_pane_mark_read)this.preview_read_timer= +window.setTimeout(function(){i.set_message(a,"unread",!1);i.update_thread_root(a,"read");i.env.unread_counts[i.env.mailbox]&&(i.env.unread_counts[i.env.mailbox]-=1,i.set_unread_count(i.env.mailbox,i.env.unread_counts[i.env.mailbox],"INBOX"==i.env.mailbox));0<i.env.preview_pane_mark_read&&i.http_post("mark","_uid="+a+"&_flag=read&_quiet=1")},1E3*this.env.preview_pane_mark_read)}};this.show_contentframe=function(a){var b,d;if(this.env.contentframe&&(b=$("#"+this.env.contentframe))&&b.length)if(!a&& +(d=window.frames[this.env.contentframe])){if(d.location&&0>d.location.href.indexOf(this.env.blankpage))d.location.href=this.env.blankpage}else if(!bw.safari&&!bw.konq)b[a?"show":"hide"]();!a&&this.busy&&this.set_busy(!1,null,this.env.frame_lock)};this.lock_frame=function(){if(!this.env.frame_lock)(this.is_framed()?parent.rcmail:this).env.frame_lock=this.set_busy(!0,"loading")};this.list_page=function(a){"next"==a?a=this.env.current_page+1:"last"==a?a=this.env.pagecount:"prev"==a&&1<this.env.current_page? +a=this.env.current_page-1:"first"==a&&1<this.env.current_page&&(a=1);if(0<a&&a<=this.env.pagecount)this.env.current_page=a,"mail"==this.task?this.list_mailbox(this.env.mailbox,a):"addressbook"==this.task&&this.list_contacts(this.env.source,this.env.group,a)};this.filter_mailbox=function(a){var b=this.set_busy(!0,"searching");this.clear_message_list();this.env.current_page=1;this.http_request("search",this.search_params(!1,a),b)};this.list_mailbox=function(a,b,d,e){var f="",h=window;a||(a=this.env.mailbox? +this.env.mailbox:"INBOX");e&&(f+=e);d&&(f+="&_sort="+d);this.env.search_request&&(f+="&_search="+this.env.search_request);if(this.env.mailbox!=a)b=1,this.env.current_page=b,this.select_all_mode=!1;this.clear_message_list();if(a!=this.env.mailbox||a==this.env.mailbox&&!b&&!d)f+="&_refresh=1";this.select_folder(a,"",!0);this.env.mailbox=a;this.gui_objects.messagelist?this.list_mailbox_remote(a,b,f):(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(h=window.frames[this.env.contentframe], +f+="&_framed=1"),a&&(this.set_busy(!0,"loading"),this.location_href(this.env.comm_path+"&_mbox="+urlencode(a)+(b?"&_page="+b:"")+f,h)))};this.clear_message_list=function(){this.env.messages={};this.last_selected=0;this.show_contentframe(!1);this.message_list&&this.message_list.clear(!0)};this.list_mailbox_remote=function(a,b,d){this.message_list.clear();a="_mbox="+urlencode(a)+(b?"&_page="+b:"");b=this.set_busy(!0,"loading");this.http_request("list",a+d,b)};this.update_selection=function(){var a= +this.message_list.selection,b=this.message_list.rows,d,e=[];for(d in a)b[a[d]]&&e.push(a[d]);this.message_list.selection=e};this.expand_unread=function(){for(var a,b=this.gui_objects.messagelist.tBodies[0].firstChild;b;){if(1==b.nodeType&&(a=this.message_list.rows[b.uid])&&a.unread_children)this.message_list.expand_all(a),this.set_unread_children(a.uid);b=b.nextSibling}return!1};this.expand_message_row=function(a,b){var d=this.message_list.rows[b];d.expanded=!d.expanded;this.set_unread_children(b); +d.expanded=!d.expanded;this.message_list.expand_row(a,b)};this.expand_threads=function(){if(this.env.threading&&this.env.autoexpand_threads&&this.message_list)switch(this.env.autoexpand_threads){case 2:this.expand_unread();break;case 1:this.message_list.expand_all()}};this.init_threads=function(a,b){if(b&&b!=this.env.mailbox)return!1;for(var d=0,e=a.length;d<e;d++)this.add_tree_icons(a[d]);this.expand_threads()};this.add_tree_icons=function(a){var b,d,e,f,h=[],g=[],k,j=this.message_list.rows;for(k= +a?j[a]?j[a].obj:null:this.message_list.list.tBodies[0].firstChild;k;){if(1==k.nodeType&&(d=j[k.uid]))if(d.depth){for(b=h.length-1;0<=b&&!(e=h[b].length,e>d.depth?(f=e-d.depth,h[b][f]&2||(h[b][f]=h[b][f]?h[b][f]+2:2)):e==d.depth&&(h[b][0]&2||(h[b][0]+=2)),d.depth>e);b--);h.push(Array(d.depth));h[h.length-1][0]=1;g.push(d.uid)}else{if(h.length){for(b in h)this.set_tree_icons(g[b],h[b]);h=[];g=[]}if(a&&k!=j[a].obj)break}k=k.nextSibling}if(h.length)for(b in h)this.set_tree_icons(g[b],h[b])};this.set_tree_icons= +function(a,b){var d,e=[],f="",h=b.length;for(d=0;d<h;d++)2<b[d]?e.push({"class":"l3",width:15}):1<b[d]?e.push({"class":"l2",width:15}):0<b[d]?e.push({"class":"l1",width:15}):e.length&&!e[e.length-1]["class"]?e[e.length-1].width+=15:e.push({"class":null,width:15});for(d=e.length-1;0<=d;d--)f=e[d]["class"]?f+('<div class="tree '+e[d]["class"]+'" />'):f+('<div style="width:'+e[d].width+'px" />');f&&$("#rcmtab"+a).html(f)};this.update_thread_root=function(a,b){if(this.env.threading){var d=this.message_list.find_root(a); +if(a!=d){var e=this.message_list.rows[d];if("read"==b&&e.unread_children)e.unread_children--;else if("unread"==b&&e.has_children)e.unread_children=e.unread_children?e.unread_children+1:1;else return;this.set_message_icon(d);this.set_unread_children(d)}}};this.update_thread=function(a){if(!this.env.threading)return 0;var b,d=0,e=this.message_list.rows,f=e[a],h=e[a].depth,g=[];f.depth?f.unread&&(a=this.message_list.find_root(a),e[a].unread_children--,this.set_unread_children(a)):d--;a=f.parent_uid; +for(f=f.obj.nextSibling;f;){if(1==f.nodeType&&(b=e[f.uid])){if(!b.depth||b.depth<=h)break;b.depth--;$("#rcmtab"+b.uid).width(15*b.depth).html("");if(b.depth){if(b.depth==h)b.parent_uid=a;b.unread&&g.length&&g[g.length-1].unread_children++}else{d++;b.parent_uid=0;if(b.has_children)$("#rcmrow"+b.uid+" .leaf:first").attr("id","rcmexpando"+b.uid).attr("class","none"!=b.obj.style.display?"expanded":"collapsed").bind("mousedown",{uid:b.uid,p:this},function(a){return a.data.p.expand_message_row(a,a.data.uid)}), +b.unread_children=0,g.push(b);"none"==b.obj.style.display&&$(b.obj).show()}}f=f.nextSibling}for(b=0;b<g.length;b++)this.set_unread_children(g[b].uid);return d};this.delete_excessive_thread_rows=function(){for(var a=this.message_list.rows,b=this.message_list.list.tBodies[0].firstChild,d=this.env.pagesize+1;b;){if(1==b.nodeType&&(r=a[b.uid]))!r.depth&&d&&d--,d||this.message_list.remove_row(b.uid);b=b.nextSibling}};this.set_message_icon=function(a){var b=this.message_list.rows[a];if(!b)return!1;if(b.icon)a= +"msgicon",b.deleted?a+=" deleted":b.unread?a+=" unread":b.unread_children&&(a+=" unreadchildren"),b.msgicon==b.icon&&(b.replied&&(a+=" replied"),b.forwarded&&(a+=" forwarded"),a+=" status"),b.icon.className=a;if(b.msgicon&&b.msgicon!=b.icon)a="msgicon",!b.unread&&b.unread_children&&(a+=" unreadchildren"),b.replied&&(a+=" replied"),b.forwarded&&(a+=" forwarded"),b.msgicon.className=a;if(b.flagicon)a=b.flagged?"flagged":"unflagged",b.flagicon.className=a};this.set_message_status=function(a,b,d){a=this.message_list.rows[a]; +if(!a)return!1;if("unread"==b)a.unread=d;else if("deleted"==b)a.deleted=d;else if("replied"==b)a.replied=d;else if("forwarded"==b)a.forwarded=d;else if("flagged"==b)a.flagged=d};this.set_message=function(a,b,d){var e=this.message_list.rows[a];if(!e)return!1;b&&this.set_message_status(a,b,d);b=$(e.obj);e.unread&&!b.hasClass("unread")?b.addClass("unread"):!e.unread&&b.hasClass("unread")&&b.removeClass("unread");e.deleted&&!b.hasClass("deleted")?b.addClass("deleted"):!e.deleted&&b.hasClass("deleted")&& +b.removeClass("deleted");e.flagged&&!b.hasClass("flagged")?b.addClass("flagged"):!e.flagged&&b.hasClass("flagged")&&b.removeClass("flagged");this.set_unread_children(a);this.set_message_icon(a)};this.set_unread_children=function(a){a=this.message_list.rows[a];a.parent_uid||(!a.unread&&a.unread_children&&!a.expanded?$(a.obj).addClass("unroot"):$(a.obj).removeClass("unroot"))};this.copy_messages=function(a){if(a&&"object"===typeof a)a=a.id;if(a&&!(a==this.env.mailbox||!this.env.uid&&(!this.message_list|| +!this.message_list.get_selection().length))){var b=[],d=this.display_message(this.get_label("copyingmessage"),"loading"),a="&_target_mbox="+urlencode(a)+"&_from="+(this.env.action?this.env.action:"");if(this.env.uid)b[0]=this.env.uid;else{var e=this.message_list.get_selection(),f;for(f in e)b.push(e[f])}a+="&_uid="+this.uids_to_list(b);this.http_post("copy","_mbox="+urlencode(this.env.mailbox)+a,d)}};this.move_messages=function(a){if(a&&"object"===typeof a)a=a.id;if(a&&!(a==this.env.mailbox||!this.env.uid&& +(!this.message_list||!this.message_list.get_selection().length))){var b=!1,a="&_target_mbox="+urlencode(a)+"&_from="+(this.env.action?this.env.action:"");"show"==this.env.action?b=this.set_busy(!0,"movingmessage"):this.show_contentframe(!1);this.enable_command(this.env.message_commands,!1);this._with_selected_messages("moveto",b,a)}};this.delete_messages=function(){var a,b,d,e=this.env.trash_mailbox,f=this.message_list,h=f?$.merge([],f.get_selection()):[];if(this.env.uid||h.length){for(b=0,d=h.length;b< +d;b++)a=h[b],f.rows[a].has_children&&!f.rows[a].expanded&&f.select_childs(a);if(this.env.flag_for_deletion)return this.mark_message("delete"),!1;!e||this.env.mailbox==e?this.permanently_remove_messages():f&&f.modkey==SHIFT_KEY?confirm(this.get_label("deletemessagesconfirm"))&&this.permanently_remove_messages():this.move_messages(e);return!0}};this.permanently_remove_messages=function(){if(this.env.uid||this.message_list&&this.message_list.get_selection().length)this.show_contentframe(!1),this._with_selected_messages("delete", +!1,"&_from="+(this.env.action?this.env.action:""))};this._with_selected_messages=function(a,b,d){var e=[],f=0;if(this.env.uid)e[0]=this.env.uid;else{var h,g,k,j=[],i=this.message_list.get_selection();for(h=0,len=i.length;h<len;h++)g=i[h],e.push(g),this.env.threading&&(f+=this.update_thread(g),k=this.message_list.find_root(g),k!=g&&0>$.inArray(k,j)&&j.push(k)),this.message_list.remove_row(g,this.env.display_next&&h==i.length-1);this.env.display_next||this.message_list.clear_selection();for(h=0,len= +j.length;h<len;h++)this.add_tree_icons(j[h])}this.env.search_request&&(d+="&_search="+this.env.search_request);this.env.display_next&&this.env.next_uid&&(d+="&_next_uid="+this.env.next_uid);0>f?d+="&_count="+-1*f:0<f&&this.delete_excessive_thread_rows();d+="&_uid="+this.uids_to_list(e);b||(b=this.display_message(this.get_label("moveto"==a?"movingmessage":"deletingmessage"),"loading"));this.http_post(a,"_mbox="+urlencode(this.env.mailbox)+d,b)};this.mark_message=function(a,b){var d=[],e=[],f,h,g;g= +this.message_list?this.message_list.get_selection():[];if(b)d[0]=b;else if(this.env.uid)d[0]=this.env.uid;else if(this.message_list)for(h=0,f=g.length;h<f;h++)d.push(g[h]);if(this.message_list)for(h=0,f=d.length;h<f;h++)g=d[h],("read"==a&&this.message_list.rows[g].unread||"unread"==a&&!this.message_list.rows[g].unread||"delete"==a&&!this.message_list.rows[g].deleted||"undelete"==a&&this.message_list.rows[g].deleted||"flagged"==a&&!this.message_list.rows[g].flagged||"unflagged"==a&&this.message_list.rows[g].flagged)&& +e.push(g);else e=d;if(e.length||this.select_all_mode)switch(a){case "read":case "unread":this.toggle_read_status(a,e);break;case "delete":case "undelete":this.toggle_delete_status(e);break;case "flagged":case "unflagged":this.toggle_flagged_status(a,d)}};this.toggle_read_status=function(a,b){var d,e=b.length,f="_uid="+this.uids_to_list(b)+"&_flag="+a,h=this.display_message(this.get_label("markingmessage"),"loading");for(d=0;d<e;d++)this.set_message(b[d],"unread","unread"==a?!0:!1);this.env.search_request&& +(f+="&_search="+this.env.search_request);this.http_post("mark",f,h);for(d=0;d<e;d++)this.update_thread_root(b[d],a)};this.toggle_flagged_status=function(a,b){var d,e=b.length,f="_uid="+this.uids_to_list(b)+"&_flag="+a,h=this.display_message(this.get_label("markingmessage"),"loading");for(d=0;d<e;d++)this.set_message(b[d],"flagged","flagged"==a?!0:!1);this.env.search_request&&(f+="&_search="+this.env.search_request);this.http_post("mark",f,h)};this.toggle_delete_status=function(a){var b=a.length,d, +e,f=!0,h=this.message_list?this.message_list.rows:[];if(1==b)return!h.length||h[a[0]]&&!h[a[0]].deleted?this.flag_as_deleted(a):this.flag_as_undeleted(a),!0;for(d=0;d<b;d++)if(e=a[d],h[e]&&!h[e].deleted){f=!1;break}f?this.flag_as_undeleted(a):this.flag_as_deleted(a);return!0};this.flag_as_undeleted=function(a){var b,d=a.length,e="_uid="+this.uids_to_list(a)+"&_flag=undelete",f=this.display_message(this.get_label("markingmessage"),"loading");for(b=0;b<d;b++)this.set_message(a[b],"deleted",!1);this.env.search_request&& +(e+="&_search="+this.env.search_request);this.http_post("mark",e,f);return!0};this.flag_as_deleted=function(a){for(var b="",d=[],b=this.message_list?this.message_list.rows:[],e=0,f=0,h=a.length;f<h;f++)uid=a[f],b[uid]&&(b[uid].unread&&(d[d.length]=uid),this.env.skip_deleted?(e+=this.update_thread(uid),this.message_list.remove_row(uid,this.env.display_next&&f==this.message_list.selection.length-1)):this.set_message(uid,"deleted",!0));this.env.skip_deleted&&this.message_list&&(this.env.display_next|| +this.message_list.clear_selection(),0>e||0<e&&this.delete_excessive_thread_rows());b="&_from="+(this.env.action?this.env.action:"");lock=this.display_message(this.get_label("markingmessage"),"loading");d.length&&(b+="&_ruid="+this.uids_to_list(d));this.env.skip_deleted&&this.env.display_next&&this.env.next_uid&&(b+="&_next_uid="+this.env.next_uid);this.env.search_request&&(b+="&_search="+this.env.search_request);this.http_post("mark","_uid="+this.uids_to_list(a)+"&_flag=delete"+b,lock);return!0}; +this.flag_deleted_as_read=function(a){var b,d,e,f=this.message_list?this.message_list.rows:[],a=(""+a).split(",");for(d=0,e=a.length;d<e;d++)b=a[d],f[b]&&this.set_message(b,"unread",!1)};this.uids_to_list=function(a){return this.select_all_mode?"*":a.join(",")};this.expunge_mailbox=function(a){var b,d="_mbox="+urlencode(a);a==this.env.mailbox&&(b=this.set_busy(!0,"loading"),d+="&_reload=1",this.env.search_request&&(d+="&_search="+this.env.search_request));this.http_post("expunge",d,b)};this.purge_mailbox= +function(a){var b=!1,d="_mbox="+urlencode(a);if(!confirm(this.get_label("purgefolderconfirm")))return!1;a==this.env.mailbox&&(b=this.set_busy(!0,"loading"),d+="&_reload=1");this.http_post("purge",d,b)};this.purge_mailbox_test=function(){return this.env.messagecount&&(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(a){var b=rcube_event.get_keycode(a),d=$("#rcmloginpwd");return 13==b&&d.length&&!d.val()?(d.focus(),rcube_event.cancel(a)):!0};this.init_messageform=function(){if(!this.gui_objects.messageform)return!1;var a=$("[name='_from']"),b=$("[name='_to']"),d=$("input[name='_subject']"),e=$("[name='_message']").get(0),f="1"==$("input[name='_is_html']").val(),h=["cc","bcc","replyto","followupto"],g;0<this.env.autocomplete_threads&&(g={threads:this.env.autocomplete_threads, +sources:this.env.autocomplete_sources});this.init_address_input_events(b,g);for(var k in h)this.init_address_input_events($("[name='_"+h[k]+"']"),g);f||(this.set_caret_pos(e,this.env.top_posting?0:$(e).val().length),"select-one"==a.prop("type")&&""==$("input[name='_draft_saveid']").val()&&this.change_identity(a[0]));""==b.val()?b.focus():""==d.val()?d.focus():e&&e.focus();this.env.compose_focus_elem=document.activeElement;this.compose_field_hash(!0);this.auto_save_start()};this.init_address_input_events= +function(a,b){this.env.recipients_delimiter=this.env.recipients_separator+" ";a[bw.ie||bw.safari||bw.chrome?"keydown":"keypress"](function(a){return i.ksearch_keydown(a,this,b)}).attr("autocomplete","off")};this.check_compose_input=function(a){var b,d=$("[name='_to']"),e=$("[name='_cc']"),f=$("[name='_bcc']"),h=$("[name='_from']"),g=$("[name='_subject']"),k=$("[name='_message']");if("text"==h.prop("type")&&!rcube_check_email(h.val(),!0))return alert(this.get_label("nosenderwarning")),h.focus(),!1; +e=d.val()?d.val():e.val()?e.val():f.val();if(!rcube_check_email(e.replace(/^\s+/,"").replace(/[\s,;]+$/,""),!0))return alert(this.get_label("norecipientwarning")),d.focus(),!1;for(var j in this.env.attachments)if("object"===typeof this.env.attachments[j]&&!this.env.attachments[j].complete)return alert(this.get_label("notuploadedwarning")),!1;if(""==g.val()){b=$('<div class="prompt">').html('<div class="message">'+this.get_label("nosubjectwarning")+"</div>").appendTo(document.body);var l=$("<input>").attr("type", +"text").attr("size",30).appendTo(b).val(this.get_label("nosubject")),d={};d[this.get_label("cancel")]=function(){g.focus();$(this).dialog("close")};d[this.get_label("sendmessage")]=function(){g.val(l.val());$(this).dialog("close");i.command(a,{nocheck:!0})};b.dialog({modal:!0,resizable:!1,buttons:d,close:function(){$(this).remove()}});l.select();return!1}this.stop_spellchecking();window.tinyMCE&&(b=tinyMCE.get(this.env.composebody));if(!b&&""==k.val()&&!confirm(this.get_label("nobodywarning")))return k.focus(), +!1;if(b){if(!b.getContent()&&!confirm(this.get_label("nobodywarning")))return b.focus(),!1;tinyMCE.triggerSave()}return!0};this.toggle_editor=function(a){if("html"==a.mode)this.display_spellcheck_controls(!1),this.plain2html($("#"+a.id).val(),a.id),tinyMCE.execCommand("mceAddControl",!1,a.id);else{var b=tinyMCE.get(a.id);b.plugins.spellchecker&&b.plugins.spellchecker.active&&b.execCommand("mceSpellCheck",!1);if(b=b.getContent()){if(!confirm(this.get_label("editorwarning")))return!1;this.html2plain(b, +a.id)}tinyMCE.execCommand("mceRemoveControl",!1,a.id);this.display_spellcheck_controls(!0)}return!0};this.stop_spellchecking=function(){var a;if(window.tinyMCE&&(a=tinyMCE.get(this.env.composebody)))a.plugins.spellchecker&&a.plugins.spellchecker.active&&a.execCommand("mceSpellCheck");else if((a=this.env.spellcheck)&&!this.spellcheck_ready)$(a.spell_span).trigger("click"),this.set_spellcheck_state("ready")};this.display_spellcheck_controls=function(a){this.env.spellcheck&&(a||this.stop_spellchecking(), +$(this.env.spellcheck.spell_container).css("visibility",a?"visible":"hidden"))};this.set_spellcheck_state=function(a){this.spellcheck_ready="ready"==a||"no_error_found"==a;this.enable_command("spellcheck",this.spellcheck_ready)};this.spellcheck_lang=function(){var a;if(window.tinyMCE&&(a=tinyMCE.get(this.env.composebody))&&a.plugins.spellchecker)return a.plugins.spellchecker.selectedLang;if(this.env.spellcheck)return GOOGIE_CUR_LANG};this.spellcheck_resume=function(a,b){if(a){var d=tinyMCE.get(this.env.composebody), +e=d.plugins.spellchecker;e.active=1;e._markWords(b);d.nodeChanged()}else{var e=this.env.spellcheck;e.prepare(!1,!0);e.processData(b)}};this.set_draft_id=function(a){$("input[name='_draft_saveid']").val(a)};this.auto_save_start=function(){if(this.env.draft_autosave)this.save_timer=self.setTimeout(function(){i.command("savedraft")},1E3*this.env.draft_autosave);this.busy=!1};this.compose_field_hash=function(a){var b,d="",e=$("[name='_to']").val(),f=$("[name='_cc']").val(),h=$("[name='_bcc']").val(), +g=$("[name='_subject']").val();e&&(d+=e+":");f&&(d+=f+":");h&&(d+=h+":");g&&(d+=g+":");d=window.tinyMCE&&(b=tinyMCE.get(this.env.composebody))?d+b.getContent():d+$("[name='_message']").val();if(this.env.attachments)for(var k in this.env.attachments)d+=k;if(a)this.cmp_hash=d;return d};this.change_identity=function(a,b){if(!a||!a.options)return!1;if(!b)b=this.env.show_sig;var d,e=-1,f=a.options[a.selectedIndex].value,h=$("[name='_message']"),g=h.val(),k="1"==$("input[name='_is_html']").val(),j=this.env.identity; +d=this.env.sig_above&&("reply"==this.env.compose_mode||"forward"==this.env.compose_mode)?"---":"-- ";this.env.signatures&&this.env.signatures[f]?(this.enable_command("insert-sig",!0),this.env.compose_commands.push("insert-sig")):this.enable_command("insert-sig",!1);if(k){if(b&&this.env.signatures&&(e=tinyMCE.get(this.env.composebody),h=e.dom.get("_rc_sig"),h||(j=e.getBody(),g=e.getDoc(),h=g.createElement("div"),h.setAttribute("id","_rc_sig"),this.env.sig_above?(e.getWin().focus(),e=e.selection.getNode(), +"BODY"==e.nodeName?(j.insertBefore(h,j.firstChild),j.insertBefore(g.createElement("br"),j.firstChild)):(j.insertBefore(h,e.nextSibling),j.insertBefore(g.createElement("br"),e.nextSibling))):(bw.ie&&j.appendChild(g.createElement("br")),j.appendChild(h))),this.env.signatures[f]))this.env.signatures[f].is_html?(j=this.env.signatures[f].text,this.env.signatures[f].plain_text.match(/^--[ -]\r?\n/m)||(j=d+"<br />"+j)):(j=this.env.signatures[f].text,j.match(/^--[ -]\r?\n/m)||(j=d+"\n"+j),j="<pre>"+j+"</pre>"), +h.innerHTML=j}else b&&j&&this.env.signatures&&this.env.signatures[j]&&(j=this.env.signatures[j].is_html?this.env.signatures[j].plain_text:this.env.signatures[j].text,j=j.replace(/\r\n/g,"\n"),j.match(/^--[ -]\n/m)||(j=d+"\n"+j),e=this.env.sig_above?g.indexOf(j):g.lastIndexOf(j),0<=e&&(g=g.substring(0,e)+g.substring(e+j.length,g.length))),b&&this.env.signatures&&this.env.signatures[f]?(j=this.env.signatures[f].is_html?this.env.signatures[f].plain_text:this.env.signatures[f].text,j=j.replace(/\r\n/g, +"\n"),j.match(/^--[ -]\n/m)||(j=d+"\n"+j),this.env.sig_above?0<=e?(g=g.substring(0,e)+j+g.substring(e,g.length),d=e-1):(pos=this.get_caret_pos(h.get(0)))?(g=g.substring(0,pos)+"\n"+j+"\n\n"+g.substring(pos,g.length),d=pos):(d=0,g="\n\n"+j+"\n\n"+g.replace(/^[\r\n]+/,"")):(g=g.replace(/[\r\n]+$/,""),d=!this.env.top_posting&&g.length?g.length+1:0,g+="\n\n"+j)):d=this.env.top_posting?0:g.length,h.val(g),this.set_caret_pos(h.get(0),d);this.env.identity=f;return!0};this.upload_file=function(a){if(!a)return!1; +var b,d=0,e=$("input[type=file]",a).get(0),f=e.files?e.files.length:e.value?1:0;if(f){if(e.files&&this.env.max_filesize&&this.env.filesizeerror){for(b=0;b<f;b++)d+=e.files[b].size;if(d&&d>this.env.max_filesize){this.display_message(this.env.filesizeerror,"error");return}}b=this.async_upload_form(a,"upload",function(a){var b,d="";try{if(this.contentDocument)b=this.contentDocument;else if(this.contentWindow)b=this.contentWindow.document;d=b.childNodes[0].innerHTML}catch(e){}if(!d.match(/add2attachment/)&& +(!bw.opera||rcmail.env.uploadframe&&rcmail.env.uploadframe==a.data.ts))d.match(/display_message/)||rcmail.display_message(rcmail.get_label("fileuploaderror"),"error"),rcmail.remove_from_attachment_list(a.data.ts);if(bw.opera)rcmail.env.uploadframe=a.data.ts});f="<span>"+this.get_label("uploading"+(1<f?"many":""))+"</span>";d=b.replace(/^rcmupload/,"");this.env.loadingicon&&(f='<img src="'+this.env.loadingicon+'" alt="" />'+f);this.env.cancelicon&&(f='<a title="'+this.get_label("cancel")+'" onclick="return rcmail.cancel_attachment_upload(\''+ +d+"', '"+b+'\');" href="#cancelupload"><img src="'+this.env.cancelicon+'" alt="" /></a>'+f);this.add2attachment_list(d,{name:"",html:f,complete:!1});this.env.upload_progress_time&&this.upload_progress_start("upload",d)}this.gui_objects.attachmentform=a;return!0};this.add2attachment_list=function(a,b,d){if(!this.gui_objects.attachmentlist)return!1;var e,f=$("<li>").attr("id",a).html(b.html);d&&(e=document.getElementById(d))?f.replaceAll(e):f.appendTo(this.gui_objects.attachmentlist);d&&this.env.attachments[d]&& +delete this.env.attachments[d];this.env.attachments[a]=b;return!0};this.remove_from_attachment_list=function(a){delete this.env.attachments[a];$("#"+a).remove()};this.remove_attachment=function(a){a&&this.env.attachments[a]&&this.http_post("remove-attachment",{_id:this.env.compose_id,_file:a});return!0};this.cancel_attachment_upload=function(a,b){if(!a||!b)return!1;this.remove_from_attachment_list(a);$("iframe[name='"+b+"']").remove();return!1};this.upload_progress_start=function(a,b){window.setTimeout(function(){rcmail.http_request(a, +{_progress:b})},1E3*this.env.upload_progress_time)};this.upload_progress_update=function(a){var b=$("#"+a.name+"> span");b.length&&a.text&&(b.text(a.text),a.done||this.upload_progress_start(a.action,a.name))};this.add_contact=function(a){a&&this.http_post("addcontact","_address="+a);return!0};this.qsearch=function(a){if(""!=a){var b=this.set_busy(!0,"searching");this.message_list?this.clear_message_list():this.contact_list&&this.list_contacts_clear();this.env.current_page=1;r=this.http_request("search", +this.search_params(a)+(this.env.source?"&_source="+urlencode(this.env.source):"")+(this.env.group?"&_gid="+urlencode(this.env.group):""),b);this.env.qsearch={lock:b,request:r}}};this.search_params=function(a,b){var d,e=[],f=[],h=this.env.search_mods,g=this.env.mailbox;if(!b&&this.gui_objects.search_filter)b=this.gui_objects.search_filter.value;if(!a&&this.gui_objects.qsearchbox)a=this.gui_objects.qsearchbox.value;b&&e.push("_filter="+urlencode(b));if(a&&(e.push("_q="+urlencode(a)),h&&this.message_list&& +(h=h[g]?h[g]:h["*"]),h)){for(d in h)f.push(d);e.push("_headers="+f.join(","))}g&&e.push("_mbox="+urlencode(g));return e.join("&")};this.reset_qsearch=function(){if(this.gui_objects.qsearchbox)this.gui_objects.qsearchbox.value="";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(a,b){this.display_message(b,a);window.setTimeout(function(){i.list_mailbox()},500)};this.ksearch_keydown=function(a, +b,d){this.ksearch_timer&&clearTimeout(this.ksearch_timer);var e=rcube_event.get_keycode(a),f=rcube_event.get_modifier(a);switch(e){case 38:case 40:if(!this.ksearch_pane)break;e=38==e?1:0;b=document.getElementById("rcmksearchSelected");if(!b)b=this.ksearch_pane.__ul.firstChild;b&&this.ksearch_select(e?b.previousSibling:b.nextSibling);return rcube_event.cancel(a);case 9:if(f==SHIFT_KEY||!this.ksearch_visible()){this.ksearch_hide();return}case 13:if(!this.ksearch_visible())return!1;this.insert_recipient(this.ksearch_selected); +this.ksearch_hide();return rcube_event.cancel(a);case 27:this.ksearch_hide();return;case 37:case 39:if(f!=SHIFT_KEY)return}this.ksearch_timer=window.setTimeout(function(){i.ksearch_get_results(d)},200);this.ksearch_input=b;return!0};this.ksearch_visible=function(){return null!==this.ksearch_selected&&void 0!==this.ksearch_selected&&this.ksearch_value};this.ksearch_select=function(a){var b=$("#rcmksearchSelected");b[0]&&a&&b.removeAttr("id").removeClass("selected");if(a)$(a).attr("id","rcmksearchSelected").addClass("selected"), +this.ksearch_selected=a._rcm_id};this.insert_recipient=function(a){if(!(null===a||!this.env.contacts[a]||!this.ksearch_input)){var b=this.ksearch_input.value,d=this.get_caret_pos(this.ksearch_input),d=b.lastIndexOf(this.ksearch_value,d),e=!1,f="",h=b.substring(0,d),b=b.substring(d+this.ksearch_value.length,b.length);this.ksearch_destroy();"object"===typeof this.env.contacts[a]&&this.env.contacts[a].id?(f+=this.env.contacts[a].name+this.env.recipients_delimiter,this.group2expand=$.extend({},this.env.contacts[a]), +this.group2expand.input=this.ksearch_input,this.http_request("mail/group-expand","_source="+urlencode(this.env.contacts[a].source)+"&_gid="+urlencode(this.env.contacts[a].id),!1)):"string"===typeof this.env.contacts[a]&&(f=this.env.contacts[a]+this.env.recipients_delimiter,e=!0);this.ksearch_input.value=h+f+b;d+=f.length;this.ksearch_input.setSelectionRange&&this.ksearch_input.setSelectionRange(d,d);e&&this.triggerEvent("autocomplete_insert",{field:this.ksearch_input,insert:f})}};this.replace_group_recipients= +function(a,b){if(this.group2expand&&this.group2expand.id==a)this.group2expand.input.value=this.group2expand.input.value.replace(this.group2expand.name,b),this.triggerEvent("autocomplete_insert",{field:this.group2expand.input,insert:b}),this.group2expand=null};this.ksearch_get_results=function(a){var b=this.ksearch_input?this.ksearch_input.value:null;if(null!==b){this.ksearch_pane&&this.ksearch_pane.is(":visible")&&this.ksearch_pane.hide();var d=this.get_caret_pos(this.ksearch_input),e=b.lastIndexOf(this.env.recipients_separator, +d-1),b=b.substring(e+1,d),e=this.env.autocomplete_min_length,d=this.ksearch_data,b=$.trim(b);if(b!=this.ksearch_value)if(this.ksearch_destroy(),b.length&&b.length<e){if(!this.ksearch_info)this.ksearch_info=this.display_message(this.get_label("autocompletechars").replace("$min",e))}else if(e=this.ksearch_value,this.ksearch_value=b,b.length&&(!e||!e.length||!(0==b.indexOf(e)&&(!d||!d.num)&&this.env.contacts&&!this.env.contacts.length))){var f,h,g,d=(new Date).getTime(),e=a&&a.threads?a.threads:1;f= +a&&a.sources?a.sources:[];a=a&&a.action?a.action:"mail/autocomplete";this.ksearch_data={id:d,sources:f.slice(),action:a,locks:[],requests:[],num:f.length};for(f=0;f<e;f++){g=this.ksearch_data.sources.shift();if(1<e&&null===g)break;h=this.display_message(this.get_label("searching"),"loading");g=this.http_post(a,"_search="+urlencode(b)+"&_id="+d+(g?"&_source="+urlencode(g):""),h);this.ksearch_data.locks.push(h);this.ksearch_data.requests.push(g)}}}};this.ksearch_query_results=function(a,b,d){if(this.ksearch_value&& +!(this.ksearch_input&&b!=this.ksearch_value)){var e,f,h,g,k,b=this.ksearch_value,j=this.ksearch_data,l=this.env.autocomplete_max?this.env.autocomplete_max:15;if(!this.ksearch_pane)h=$("<ul>"),this.ksearch_pane=$("<div>").attr("id","rcmKSearchpane").css({position:"absolute","z-index":3E4}).append(h).appendTo(document.body),this.ksearch_pane.__ul=h[0];h=this.ksearch_pane.__ul;d&&this.ksearch_pane.data("reqid")==d?l-=h.childNodes.length:(this.ksearch_pane.data("reqid",d),h.innerHTML="",this.env.contacts= +[],e=$(this.ksearch_input).offset(),this.ksearch_pane.css({left:e.left+"px",top:e.top+this.ksearch_input.offsetHeight+"px",display:"none"}));if(a&&(f=a.length))for(e=0;e<f&&0<l;e++)k="object"===typeof a[e]?a[e].name:a[e],g=document.createElement("LI"),g.innerHTML=k.replace(RegExp("("+RegExp.escape(b)+")","ig"),"##$1%%").replace(/</g,"<").replace(/>/g,">").replace(/##([^%]+)%%/g,"<b>$1</b>"),g.onmouseover=function(){i.ksearch_select(this)},g.onmouseup=function(){i.ksearch_click(this)},g._rcm_id= +this.env.contacts.length+e,h.appendChild(g),l-=1;if(h.childNodes.length&&(this.ksearch_pane.show(),!this.env.contacts.length))$("li:first",h).attr("id","rcmksearchSelected").addClass("selected"),this.ksearch_selected=0;if(f)this.env.contacts=this.env.contacts.concat(a);if(j.id==d)if(j.num--,0<l&&j.sources.length){if(f=j.sources.shift())a=this.display_message(this.get_label("searching"),"loading"),d=this.http_post(j.action,"_search="+urlencode(b)+"&_id="+d+"&_source="+urlencode(f),a),this.ksearch_data.locks.push(a), +this.ksearch_data.requests.push(d)}else if(!l){if(!this.ksearch_msg)this.ksearch_msg=this.display_message(this.get_label("autocompletemore"));this.ksearch_abort()}}};this.ksearch_click=function(a){this.ksearch_input&&this.ksearch_input.focus();this.insert_recipient(a._rcm_id);this.ksearch_hide()};this.ksearch_blur=function(){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=""; +this.ksearch_pane&&this.ksearch_pane.hide();this.ksearch_destroy()};this.ksearch_destroy=function(){this.ksearch_abort();this.ksearch_info&&this.hide_message(this.ksearch_info);this.ksearch_msg&&this.hide_message(this.ksearch_msg);this.ksearch_msg=this.ksearch_info=this.ksearch_data=null};this.ksearch_abort=function(){var a,b,d=this.ksearch_data;if(d)for(a=0,b=d.locks.length;a<b;a++)this.abort_request({request:d.requests[a],lock:d.locks[a]})};this.contactlist_keypress=function(a){a.key_pressed==a.DELETE_KEY&& +this.command("delete")};this.contactlist_select=function(a){this.preview_timer&&clearTimeout(this.preview_timer);var b,d,e,f=this,h=!1;e=this.env.source?this.env.address_sources[this.env.source]:null;(d=a.get_single_selection())?this.preview_timer=window.setTimeout(function(){f.load_contact(d,"show")},200):this.env.contentframe&&this.show_contentframe(!1);if(a.selection.length)if(e)h=!e.readonly;else for(b in a.selection)if((e=(""+a.selection[b]).replace(/^[^-]+-/,""))&&this.env.address_sources[e]&& +!this.env.address_sources[e].readonly){h=!0;break}this.enable_command("compose",this.env.group||0<a.selection.length);this.enable_command("edit",d&&h);this.enable_command("delete",a.selection.length&&h);return!1};this.list_contacts=function(a,b,d){var e="",f=window;if(!a)a=this.env.source;if(d&&this.current_page==d&&a==this.env.source&&b==this.env.group)return!1;if(a!=this.env.source)d=this.env.current_page=1,this.reset_qsearch();else if(b!=this.env.group)d=this.env.current_page=1;this.select_folder(this.env.search_id? +"S"+this.env.search_id:b?"G"+a+b:a);this.env.source=a;this.env.group=b;this.gui_objects.contactslist?this.list_contacts_remote(a,b,d):(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(f=window.frames[this.env.contentframe],e="&_framed=1"),b&&(e+="&_gid="+b),d&&(e+="&_page="+d),this.env.search_request&&(e+="&_search="+this.env.search_request),this.set_busy(!0,"loading"),this.location_href(this.env.comm_path+(a?"&_source="+urlencode(a):"")+e,f))};this.list_contacts_remote= +function(a,b,d){this.list_contacts_clear();var d=(a?"_source="+urlencode(a):"")+(d?(a?"&":"")+"_page="+d:""),e=this.set_busy(!0,"loading");this.env.source=a;(this.env.group=b)&&(d+="&_gid="+b);this.env.search_request&&(d+="&_search="+this.env.search_request);this.http_request("list",d,e)};this.list_contacts_clear=function(){this.contact_list.clear(!0);this.show_contentframe(!1);this.enable_command("delete",!1);this.enable_command("compose",this.env.group?!0:!1)};this.load_contact=function(a,b,d){var e= +"",f=window;if(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe])e="&_framed=1",f=window.frames[this.env.contentframe],this.show_contentframe(!0),a||(this.contact_list.clear_selection(),this.enable_command("delete","compose",!1));else if(d)return!1;if(b&&(a||"add"==b)&&!this.drag_active)this.env.group&&(e+="&_gid="+urlencode(this.env.group)),this.location_href(this.env.comm_path+"&_action="+b+"&_source="+urlencode(this.env.source)+"&_cid="+urlencode(a)+e,f,!0);return!0};this.group_member_change= +function(a,b,d,e){var a="add"==a?"add":"del",f=this.display_message(this.get_label("add"==a?"addingmember":"removingmember"),"loading");this.http_post("group-"+a+"members","_cid="+urlencode(b)+"&_source="+urlencode(d)+"&_gid="+urlencode(e),f)};this.copy_contact=function(a,b){a||(a=this.contact_list.get_selection().join(","));if("group"==b.type&&b.source==this.env.source)this.group_member_change("add",a,b.source,b.id);else if("group"==b.type&&!this.env.address_sources[b.source].readonly){var d=this.display_message(this.get_label("copyingcontact"), +"loading");this.http_post("copy","_cid="+urlencode(a)+"&_source="+urlencode(this.env.source)+"&_to="+urlencode(b.source)+"&_togid="+urlencode(b.id)+(this.env.group?"&_gid="+urlencode(this.env.group):""),d)}else b.id!=this.env.source&&a&&this.env.address_sources[b.id]&&!this.env.address_sources[b.id].readonly&&(d=this.display_message(this.get_label("copyingcontact"),"loading"),this.http_post("copy","_cid="+urlencode(a)+"&_source="+urlencode(this.env.source)+"&_to="+urlencode(b.id)+(this.env.group? +"&_gid="+urlencode(this.env.group):""),d))};this.delete_contacts=function(){var a=this.contact_list.get_selection(),b=this.env.source&&this.env.address_sources[this.env.source].undelete;if(!(!a.length&&!this.env.cid||!b&&!confirm(this.get_label("deletecontactconfirm")))){var d,e=[],f="";if(this.env.cid)e.push(this.env.cid);else{for(d=0;d<a.length;d++)b=a[d],e.push(b),this.contact_list.remove_row(b,d==a.length-1);1==a.length&&this.show_contentframe(!1)}this.env.group&&(f+="&_gid="+urlencode(this.env.group)); +this.env.search_request&&(f+="&_search="+this.env.search_request);this.http_post("delete","_cid="+urlencode(e.join(","))+"&_source="+urlencode(this.env.source)+"&_from="+(this.env.action?this.env.action:"")+f,this.display_message(this.get_label("contactdeleting"),"loading"));return!0}};this.update_contact_row=function(a,b,d,e){var f,h=this.contact_list,a=this.html_identifier(a);h.rows[a]||(a=a+"-"+e,d&&(d=d+"-"+e));if(h.rows[a]&&(f=h.rows[a].obj)){for(e=0;e<b.length;e++)f.cells[e]&&$(f.cells[e]).html(b[e]); +if(d)d=this.html_identifier(d),f.id="rcmrow"+d,h.remove_row(a),h.init_row(f),h.selection[0]=d,f.style.display=""}};this.add_contact_row=function(a,b){if(!this.gui_objects.contactslist)return!1;var d,e=this.contact_list,f=document.createElement("tr");f.id="rcmrow"+this.html_identifier(a);f.className="contact";e.in_selection(a)&&(f.className+=" selected");for(d in b)col=document.createElement("td"),col.className=(""+d).toLowerCase(),col.innerHTML=b[d],f.appendChild(col);e.insert_row(f);this.enable_command("export", +0<e.rowcount)};this.init_contact_form=function(){var a=this,b;this.set_photo_actions($("#ff_photo").val());for(b in this.env.coltypes)this.init_edit_field(b,null);$(".contactfieldgroup .row a.deletebutton").click(function(){a.delete_edit_field(this);return!1});$("select.addfieldmenu").change(function(){a.insert_edit_field($(this).val(),$(this).attr("rel"),this);this.selectedIndex=0});$.datepicker&&this.env.date_format&&($.datepicker.setDefaults({dateFormat:this.env.date_format,changeMonth:!0,changeYear:!0, +yearRange:"-100:+10",showOtherMonths:!0,selectOtherMonths:!0,monthNamesShort:this.env.month_names,onSelect:function(a){$(this).focus().val(a)}}),$("input.datepicker").datepicker());$("input[type='text']:visible").first().focus()};this.group_create=function(){this.add_input_row("contactgroup")};this.group_rename=function(){if(this.env.group&&this.gui_objects.folderlist){if(!this.name_input){this.enable_command("list","listgroup",!1);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(a){return rcmail.add_input_keydown(a)});this.env.group_renaming=!0;var a,b=this.get_folder_li(this.env.source+this.env.group,"rcmliG");b&&(a=b.firstChild)&&$(a).hide().before(this.name_input)}this.name_input.select().focus()}};this.group_delete=function(){if(this.env.group&&confirm(this.get_label("deletegroupconfirm"))){var a=this.set_busy(!0,"groupdeleting");this.http_post("group-delete","_source="+urlencode(this.env.source)+ +"&_gid="+urlencode(this.env.group),a)}};this.remove_group_item=function(a){var b,d="G"+a.source+a.id;if(b=this.get_folder_li(d))this.triggerEvent("group_delete",{source:a.source,id:a.id,li:b}),b.parentNode.removeChild(b),delete this.env.contactfolders[d],delete this.env.contactgroups[d];this.list_contacts(a.source,0)};this.add_input_row=function(a){if(this.gui_objects.folderlist){if(!this.name_input)this.name_input=$("<input>").attr("type","text").data("tt",a),this.name_input.bind("keydown",function(a){return rcmail.add_input_keydown(a)}), +this.name_input_li=$("<li>").addClass(a).append(this.name_input),this.name_input_li.insertAfter("contactsearch"==a?$("li:last",this.gui_objects.folderlist):this.get_folder_li(this.env.source));this.name_input.select().focus()}};this.add_input_keydown=function(a){var b=rcube_event.get_keycode(a),d=$(a.target),a=d.data("tt");if(13==b){if(b=d.val())d=this.set_busy(!0,"loading"),"contactsearch"==a?this.http_post("search-create","_search="+urlencode(this.env.search_request)+"&_name="+urlencode(b),d):this.env.group_renaming? +this.http_post("group-rename","_source="+urlencode(this.env.source)+"&_gid="+urlencode(this.env.group)+"&_name="+urlencode(b),d):this.http_post("group-create","_source="+urlencode(this.env.source)+"&_name="+urlencode(b),d);return!1}27==b&&this.reset_add_input();return!0};this.reset_add_input=function(){if(this.name_input){if(this.env.group_renaming)this.name_input.parent().children().last().show(),this.env.group_renaming=!1;this.name_input.remove();this.name_input_li&&this.name_input_li.remove(); +this.name_input=this.name_input_li=null}this.enable_command("list","listgroup",!0)};this.insert_contact_group=function(a){this.reset_add_input();a.type="group";var b="G"+a.source+a.id,d=$("<a>").attr("href","#").attr("rel",a.source+":"+a.id).click(function(){return rcmail.command("listgroup",a,this)}).html(a.name),d=$("<li>").attr({id:"rcmli"+this.html_identifier(b),"class":"contactgroup"}).append(d);this.env.contactfolders[b]=this.env.contactgroups[b]=a;this.add_contact_group_row(a,d);this.triggerEvent("group_insert", +{id:a.id,source:a.source,name:a.name,li:d[0]})};this.update_contact_group=function(a){this.reset_add_input();var b="G"+a.source+a.id,d=this.get_folder_li(b),e;if(d&&a.newid){e="G"+a.source+a.newid;var f=$.extend({},a);d.id="rcmli"+this.html_identifier(e);this.env.contactfolders[e]=this.env.contactfolders[b];this.env.contactfolders[e].id=a.newid;this.env.group=a.newid;delete this.env.contactfolders[b];delete this.env.contactgroups[b];f.id=a.newid;f.type="group";e=$("<a>").attr("href","#").attr("rel", +a.source+":"+a.newid).click(function(){return rcmail.command("listgroup",f,this)}).html(a.name);$(d).children().replaceWith(e)}else if(d&&(e=d.firstChild)&&"a"==e.tagName.toLowerCase())e.innerHTML=a.name;this.env.contactfolders[b].name=this.env.contactgroups[b].name=a.name;this.add_contact_group_row(a,$(d),!0);this.triggerEvent("group_update",{id:a.id,source:a.source,name:a.name,li:d[0],newid:a.newid})};this.add_contact_group_row=function(a,b,d){var e=a.name.toUpperCase(),f=this.get_folder_li(a.source), +a="rcmliG"+this.html_identifier(a.source);d?(d=b.clone(!0),b.remove()):d=b;$('li[id^="'+a+'"]',this.gui_objects.folderlist).each(function(a,b){if(e>=$(this).text().toUpperCase())f=b;else return!1});d.insertAfter(f)};this.update_group_commands=function(){var a=""!=this.env.source?this.env.address_sources[this.env.source]:null;this.enable_command("group-create",a&&a.groups&&!a.readonly);this.enable_command("group-rename","group-delete",a&&a.groups&&this.env.group&&!a.readonly)};this.init_edit_field= +function(a,b){b||(b=$(".ff_"+a));b.focus(function(){i.focus_textfield(this)}).blur(function(){i.blur_textfield(this)}).each(function(){this._placeholder=this.title=i.env.coltypes[a].label;i.blur_textfield(this)})};this.insert_edit_field=function(a,b,d){var e=$("#ff_"+a);if(e.length)e.show().focus(),$(d).children('option[value="'+a+'"]').prop("disabled",!0);else if($(".ff_"+a),e=$("#contactsection"+b+" .contactcontroller"+a),e.length||(e=$("<fieldset>").addClass("contactfieldgroup contactcontroller"+ +a).insertAfter($("#contactsection"+b+" .contactfieldgroup").last())),e.length&&"FIELDSET"==e.get(0).nodeName){var f,b=this.env.coltypes[a],h=$("<div>").addClass("row"),g=$("<div>").addClass("contactfieldcontent data"),k=$("<div>").addClass("contactfieldlabel label");b.subtypes_select?k.html(b.subtypes_select):k.html(b.label);var j=1!=b.limit?"[]":"";if("text"==b.type||"date"==b.type)f=$("<input>").addClass("ff_"+a).attr({type:"text",name:"_"+a+j,size:b.size}).appendTo(g),this.init_edit_field(a,f), +"date"==b.type&&$.datepicker&&f.datepicker();else if("composite"==b.type){var l,n,m=[],o=[];if(f=this.env[a+"_template"])for(l=0;l<f.length;l++)m.push(f[l][1]),o.push(f[l][2]);else for(l in b.childs)m.push(l);for(var p=0;p<m.length;p++)l=m[p],f=b.childs[l],f=$("<input>").addClass("ff_"+l).attr({type:"text",name:"_"+l+j,size:f.size}).appendTo(g),g.append(o[p]||" "),this.init_edit_field(l,f),n||(n=f);f=n}else if("select"==b.type){f=$("<select>").addClass("ff_"+a).attr("name","_"+a+j).appendTo(g);var q= +f.attr("options");q[q.length]=new Option("---","");b.options&&$.each(b.options,function(a,b){q[q.length]=new Option(b,a)})}if(f){$('<a href="#del"></a>').addClass("contactfieldbutton deletebutton").attr({title:this.get_label("delete"),rel:a}).html(this.env.delbutton).click(function(){i.delete_edit_field(this);return!1}).appendTo(g);h.append(k).append(g).appendTo(e.show());f.first().focus();if(!b.count)b.count=0;++b.count==b.limit&&b.limit&&$(d).children('option[value="'+a+'"]').prop("disabled",!0)}}}; +this.delete_edit_field=function(a){var b=$(a).attr("rel"),d=this.env.coltypes[b],e=$(a).parents("fieldset.contactfieldgroup"),f=e.parent().find("select.addfieldmenu");0>=--d.count&&d.visible?$(a).parent().children("input").val("").blur():($(a).parents("div.row").remove(),e.children("div.row").length||e.hide());f.length&&(a=f.children('option[value="'+b+'"]'),a.length?a.prop("disabled",!1):$("<option>").attr("value",b).html(d.label).appendTo(f),f.show())};this.upload_contact_photo=function(a){if(a&& +a.elements._photo.value)this.async_upload_form(a,"upload-photo",function(){rcmail.set_busy(!1,null,rcmail.photo_upload_id)}),this.photo_upload_id=this.set_busy(!0,"uploading")};this.replace_contact_photo=function(a){var b="-del-"==a?this.env.photo_placeholder:this.env.comm_path+"&_action=photo&_source="+this.env.source+"&_cid="+this.env.cid+"&_photo="+a;this.set_photo_actions(a);$(this.gui_objects.contactphoto).children("img").attr("src",b)};this.photo_upload_end=function(){this.set_busy(!1,null, +this.photo_upload_id);delete this.photo_upload_id};this.set_photo_actions=function(a){var b,d=this.buttons["upload-photo"];for(b=0;d&&b<d.length;b++)$("#"+d[b].id).html(this.get_label("-del-"==a?"addphoto":"replacephoto"));$("#ff_photo").val(a);this.enable_command("upload-photo",this.env.coltypes.photo?!0:!1);this.enable_command("delete-photo",this.env.coltypes.photo&&"-del-"!=a)};this.advanced_search=function(){var a="&_form=1",b=window;this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&& +(a+="&_framed=1",b=window.frames[this.env.contentframe],this.contact_list.clear_selection());this.location_href(this.env.comm_path+"&_action=search"+a,b,!0);return!0};this.unselect_directory=function(){this.select_folder("");this.enable_command("search-delete",!1)};this.insert_saved_search=function(a,b){this.reset_add_input();var d="S"+b,e=$("<a>").attr("href","#").attr("rel",b).click(function(){return rcmail.command("listsearch",b,this)}).html(a),d=$("<li>").attr({id:"rcmli"+this.html_identifier(d), +"class":"contactsearch"}).append(e),e={name:a,id:b,li:d[0]};this.add_saved_search_row(e,d);this.select_folder("S"+b);this.enable_command("search-delete",!0);this.env.search_id=b;this.triggerEvent("abook_search_insert",e)};this.add_saved_search_row=function(a,b,d){var e,f=a.name.toUpperCase();d?(a=b.clone(!0),b.remove()):a=b;$('li[class~="contactsearch"]',this.gui_objects.folderlist).each(function(a,b){if(!e)e=this.previousSibling;if(f>=$(this).text().toUpperCase())e=b;else return!1});e?a.insertAfter(e): +a.appendTo(this.gui_objects.folderlist)};this.search_create=function(){this.add_input_row("contactsearch")};this.search_delete=function(){if(this.env.search_request){var a=this.set_busy(!0,"savedsearchdeleting");this.http_post("search-delete","_sid="+urlencode(this.env.search_id),a)}};this.remove_search_item=function(a){var b;if(b=this.get_folder_li("S"+a))this.triggerEvent("search_delete",{id:a,li:b}),b.parentNode.removeChild(b);this.env.search_id=null;this.env.search_request=null;this.list_contacts_clear(); +this.reset_qsearch();this.enable_command("search-delete","search-create",!1)};this.listsearch=function(a){var b=this.set_busy(!0,"searching");this.contact_list&&this.list_contacts_clear();this.reset_qsearch();this.select_folder("S"+a);this.env.current_page=1;this.http_request("search","_sid="+urlencode(a),b)};this.section_select=function(a){var a=a.get_single_selection(),b="",d=window;a&&(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe]&&(b="&_framed=1",d=window.frames[this.env.contentframe]), +this.location_href(this.env.comm_path+"&_action=edit-prefs&_section="+a+b,d,!0));return!0};this.identity_select=function(a){var b;(b=a.get_single_selection())&&this.load_identity(b,"edit-identity")};this.load_identity=function(a,b){if("edit-identity"==b&&(!a||a==this.env.iid))return!1;var d="",e=window;if(this.env.contentframe&&window.frames&&window.frames[this.env.contentframe])d="&_framed=1",e=window.frames[this.env.contentframe],document.getElementById(this.env.contentframe).style.visibility="inherit"; +if(b&&(a||"add-identity"==b))this.set_busy(!0),this.location_href(this.env.comm_path+"&_action="+b+"&_iid="+a+d,e);return!0};this.delete_identity=function(a){var b=this.identity_list.get_selection();if(b.length||this.env.iid)return a||(a=this.env.iid?this.env.iid:b[0]),this.goto_url("delete-identity","_iid="+a+"&_token="+this.env.request_token,!0),!0};this.init_subscription_list=function(){var a=this;this.subscription_list=new rcube_list_widget(this.gui_objects.subscriptionlist,{multiselect:!1,draggable:!0, +keyboard:!1,toggleselect:!0});this.subscription_list.addEventListener("select",function(b){a.subscription_select(b)});this.subscription_list.addEventListener("dragstart",function(){a.drag_active=!0});this.subscription_list.addEventListener("dragend",function(b){a.subscription_move_folder(b)});this.subscription_list.row_init=function(b){b.obj.onmouseover=function(){a.focus_subscription(b.id)};b.obj.onmouseout=function(){a.unfocus_subscription(b.id)}};this.subscription_list.init();$("#mailboxroot").mouseover(function(){a.focus_subscription(this.id)}).mouseout(function(){a.unfocus_subscription(this.id)})}; +this.focus_subscription=function(a){var b,d,e=RegExp.escape(this.env.delimiter),e=RegExp("["+e+"]?[^"+e+"]+$");if(this.drag_active&&this.env.mailbox&&(b=document.getElementById(a)))if(this.env.subscriptionrows[a]&&null!==(d=this.env.subscriptionrows[a][0])&&this.check_droptarget(d)&&!this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2]&&d!=this.env.mailbox.replace(e,"")&&!d.match(RegExp("^"+RegExp.escape(this.env.mailbox+this.env.delimiter))))this.env.dstfolder=d,$(b).addClass("droptarget")}; +this.unfocus_subscription=function(a){var b=$("#"+a);this.env.dstfolder=null;this.env.subscriptionrows[a]&&b[0]?b.removeClass("droptarget"):$(this.subscription_list.frame).removeClass("droptarget")};this.subscription_select=function(a){var b,d;a&&(b=a.get_single_selection())&&(d=this.env.subscriptionrows["rcmrow"+b])?(this.env.mailbox=d[0],this.show_folder(d[0]),this.enable_command("delete-folder",!d[2])):(this.env.mailbox=null,this.show_contentframe(!1),this.enable_command("delete-folder","purge", +!1))};this.subscription_move_folder=function(){var a=RegExp.escape(this.env.delimiter);this.env.mailbox&&null!==this.env.dstfolder&&this.env.dstfolder!=this.env.mailbox&&this.env.dstfolder!=this.env.mailbox.replace(RegExp("["+a+"]?[^"+a+"]+$"),"")&&(a=this.env.mailbox.replace(RegExp("[^"+a+"]*["+a+"]","g"),""),a=""===this.env.dstfolder?a:this.env.dstfolder+this.env.delimiter+a,a!=this.env.mailbox&&(this.http_post("rename-folder","_folder_oldname="+urlencode(this.env.mailbox)+"&_folder_newname="+urlencode(a), +this.set_busy(!0,"foldermoving")),this.subscription_list.draglayer.hide()));this.drag_active=!1;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(a){if((a=this.env.subscriptionrows[this.get_folder_row_id(a?a:this.env.mailbox)][0])&&confirm(this.get_label("deletefolderconfirm"))){var b=this.set_busy(!0,"folderdeleting");this.http_post("delete-folder","_mbox="+urlencode(a),b)}};this.add_folder_row= +function(a,b,d,e,f,h){if(!this.gui_objects.subscriptionlist)return!1;var g,k,j,i,n,m=[],o=[],p=this.gui_objects.subscriptionlist.tBodies[0];g=$("tr",p).get(1);var q="rcmrow"+(new Date).getTime();if(!g)return this.goto_url("folders"),!1;g=$(g).clone(!0);g.attr("id",q);g.attr("class",h);g.find("td:first").html(b);$('input[name="_subscribed[]"]',g).val(a).prop({checked:e?!0:!1,disabled:d?!0:!1});this.env.subscriptionrows[q]=[a,b,0];i=[];$.each(this.env.subscriptionrows,function(a,b){i.push(b)});i.sort(function(a, +b){return a[0]<b[0]?-1:a[0]>b[0]?1:0});for(k in i)i[k][2]?(o.push(i[k][0]),j=i[k][0]+this.env.delimiter):j&&0==i[k][0].indexOf(j)?o.push(i[k][0]):(m.push(i[k][0]),j=null);for(k=0;k<o.length;k++)0==a.indexOf(o[k]+this.env.delimiter)&&(n=this.get_folder_row_id(o[k]));for(k=0;!n&&k<m.length;k++)k&&m[k]==a&&(n=this.get_folder_row_id(m[k-1]));n?$("#"+n).after(g):g.appendTo(p);this.subscription_list.clear_selection();f||this.init_subscription_list();g=g.get(0);g.scrollIntoView&&g.scrollIntoView();return g}; +this.replace_folder_row=function(a,b,d,e,f){if(!this.gui_objects.subscriptionlist)return!1;var h,g,i,j,l=this.get_folder_row_id(a),n=RegExp("^"+RegExp.escape(a));h=$('input[name="_subscribed[]"]',$("#"+l)).prop("checked");var m=this.get_subfolders(a);this._remove_folder_row(l);e=$(this.add_folder_row(b,d,e,h,!0,f));if(d=m.length)j=a.split(this.env.delimiter).length-b.split(this.env.delimiter).length;for(a=0;a<d;a++)if(l=m[a],h=this.env.subscriptionrows[l][0],f=this.env.subscriptionrows[l][1],g=$("#"+ +l),i=g.clone(!0),g.remove(),e.after(i),e=i,h=h.replace(n,b),$('input[name="_subscribed[]"]',e).val(h),this.env.subscriptionrows[l][0]=h,0!=j){if(0<j)for(h=j;0<h;h--)f=f.replace(/^ /,"");else for(h=j;0>h;h++)f=" "+f;e.find("td:first").html(f);this.env.subscriptionrows[l][1]=f}this.init_subscription_list()};this.remove_folder_row=function(a,b){var d,e,f=[];d=this.get_folder_row_id(a);b&&(f=this.get_subfolders(a));this._remove_folder_row(d);for(d=0,e=f.length;d< +e;d++)this._remove_folder_row(f[d])};this._remove_folder_row=function(a){this.subscription_list.remove_row(a.replace(/^rcmrow/,""));$("#"+a).remove();delete this.env.subscriptionrows[a]};this.get_subfolders=function(a){for(var b=[],d=RegExp("^"+RegExp.escape(a)+RegExp.escape(this.env.delimiter)),e=$("#"+this.get_folder_row_id(a)).get(0);e=e.nextSibling;)if(e.id)if(a=this.env.subscriptionrows[e.id][0],d.test(a))b.push(e.id);else break;return b};this.subscribe=function(a){if(a){var b=this.display_message(this.get_label("foldersubscribing"), +"loading");this.http_post("subscribe","_mbox="+urlencode(a),b)}};this.unsubscribe=function(a){if(a){var b=this.display_message(this.get_label("folderunsubscribing"),"loading");this.http_post("unsubscribe","_mbox="+urlencode(a),b)}};this.get_folder_row_id=function(a){var b,d=this.env.subscriptionrows;for(b in d)if(d[b]&&d[b][0]==a)break;return b};this.show_folder=function(a,b,d){var e=window,a="&_action=edit-folder&_mbox="+urlencode(a);b&&(a+="&_path="+urlencode(b));this.env.contentframe&&window.frames&& +window.frames[this.env.contentframe]&&(e=window.frames[this.env.contentframe],a+="&_framed=1");0<=(""+e.location.href).indexOf(a)&&!d?this.show_contentframe(!0):this.location_href(this.env.comm_path+a,e,!0)};this.disable_subscription=function(a){(a=this.get_folder_row_id(a))&&$('input[name="_subscribed[]"]',$("#"+a)).prop("disabled",!0)};this.folder_size=function(a){var b=this.set_busy(!0,"loading");this.http_post("folder-size","_mbox="+urlencode(a),b)};this.folder_size_update=function(a){$("#folder-size").replaceWith(a)}; +var s=function(a,b){var d=document.getElementById(b.id);if(d){var e=!1;if("image"==b.type)d=d.parentNode,e=!0;d._command=a;d._id=b.id;if(b.sel&&(d.onmousedown=function(){return rcmail.button_sel(this._command,this._id)},d.onmouseup=function(){return rcmail.button_out(this._command,this._id)},e))(new Image).src=b.sel;if(b.over&&(d.onmouseover=function(){return rcmail.button_over(this._command,this._id)},d.onmouseout=function(){return rcmail.button_out(this._command,this._id)},e))(new Image).src=b.over}}; +this.set_page_buttons=function(){this.enable_command("nextpage","lastpage",this.env.pagecount>this.env.current_page);this.enable_command("previouspage","firstpage",1<this.env.current_page)};this.init_buttons=function(){for(var a in this.buttons)if("string"===typeof a)for(var b=0;b<this.buttons[a].length;b++)s(a,this.buttons[a][b]);this.set_button(this.task,"sel")};this.set_button=function(a,b){var d,e,f,h=this.buttons[a],g=h?h.length:0;for(d=0;d<g;d++){e=h[d];if((f=document.getElementById(e.id))&& +"image"==e.type&&!e.status){if(e.pas=f._original_src?f._original_src:f.src,f.runtimeStyle&&f.runtimeStyle.filter&&f.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/))e.pas=RegExp.$1}else if(f&&!e.status)e.pas=""+f.className;if(f&&"image"==e.type&&e[b])e.status=b,f.src=e[b];else if(f&&void 0!==e[b])e.status=b,f.className=e[b];if(f&&"input"==e.type)e.status=b,f.disabled=!b}};this.set_alttext=function(a,b){var d,e,f,h,g=this.buttons[a],i=g?g.length:0;for(d=0;d<i;d++)e=g[d],f=document.getElementById(e.id), +"image"==e.type&&f?(f.setAttribute("alt",this.get_label(b)),(h=f.parentNode)&&"a"==h.tagName.toLowerCase()&&h.setAttribute("title",this.get_label(b))):f&&f.setAttribute("title",this.get_label(b))};this.button_over=function(a,b){var d,e,f,h=this.buttons[a],g=h?h.length:0;for(d=0;d<g;d++)if(e=h[d],e.id==b&&"act"==e.status&&(f=document.getElementById(e.id))&&e.over)"image"==e.type?f.src=e.over:f.className=e.over};this.button_sel=function(a,b){var d,e,f,h=this.buttons[a],g=h?h.length:0;for(d=0;d<g;d++)if(e= +h[d],e.id==b&&"act"==e.status){if((f=document.getElementById(e.id))&&e.sel)"image"==e.type?f.src=e.sel:f.className=e.sel;this.buttons_sel[b]=a}};this.button_out=function(a,b){var d,e,f,h=this.buttons[a],g=h?h.length:0;for(d=0;d<g;d++)if(e=h[d],e.id==b&&"act"==e.status&&(f=document.getElementById(e.id))&&e.act)"image"==e.type?f.src=e.act:f.className=e.act};this.focus_textfield=function(a){a._hasfocus=!0;var b=$(a);(b.hasClass("placeholder")||b.val()==a._placeholder)&&b.val("").removeClass("placeholder").attr("spellcheck", +!0)};this.blur_textfield=function(a){a._hasfocus=!1;var b=$(a);a._placeholder&&(!b.val()||b.val()==a._placeholder)&&b.addClass("placeholder").attr("spellcheck",!1).val(a._placeholder)};this.set_pagetitle=function(a){if(a&&document.title)document.title=a};this.display_message=function(a,b,d){if(this.is_framed())return parent.rcmail.display_message(a,b,d);if(!this.gui_objects.message){if("loading"!=b)this.pending_message=[a,b,d];return!1}var b=b?b:"notice",e=this,f=this.html_identifier(a),h=b+(new Date).getTime(); +d||(d=this.message_time*("error"==b||"warning"==b?2:1));"loading"==b&&(f="loading",d=1E3*this.env.request_timeout,a||(a=this.get_label("loading")));if(this.messages[f])return this.messages[f].obj&&this.messages[f].obj.html(a),"loading"==b&&this.messages[f].labels.push({id:h,msg:a}),this.messages[f].elements.push(h),window.setTimeout(function(){e.hide_message(h,"loading"==b)},d),h;var g=$("<div>").addClass(b).html(a).data("key",f);$(this.gui_objects.message).append(g).show();this.messages[f]={obj:g, +elements:[h]};"loading"==b?this.messages[f].labels=[{id:h,msg:a}]:g.click(function(){return e.hide_message(g)});0<d&&window.setTimeout(function(){e.hide_message(h,"loading"==b)},d);return h};this.hide_message=function(a,b){if(this.is_framed())return parent.rcmail.hide_message(a,b);var d,e,f,h,g=this.messages;if("object"===typeof a)$(a)[b?"fadeOut":"hide"](),h=$(a).data("key"),this.messages[h]&&delete this.messages[h];else for(d in g)for(e in g[d].elements)if(g[d]&&g[d].elements[e]==a)if(g[d].elements.splice(e, +1),g[d].elements.length){if("loading"==d)for(f in g[d].labels)g[d].labels[f].id==a?delete g[d].labels[f]:h=g[d].labels[f].msg,g[d].obj.html(h)}else g[d].obj[b?"fadeOut":"hide"](),delete g[d]};this.select_folder=function(a,b,d){if(this.gui_objects.folderlist){var e,f;(e=$("li.selected",this.gui_objects.folderlist))&&e.removeClass("selected").addClass("unfocused");(f=this.get_folder_li(a,b,d))&&$(f).removeClass("unfocused").addClass("selected");this.triggerEvent("selectfolder",{folder:a,prefix:b})}}; +this.get_folder_li=function(a,b,d){b||(b="rcmli");return this.gui_objects.folderlist?(a=this.html_identifier(a,d),document.getElementById(b+a)):null};this.set_message_coltypes=function(a,b){var d=this.message_list,e=d?d.list.tHead:null,f,h,g,i;this.env.coltypes=a;if(e){if(b){h=document.createElement("thead");g=document.createElement("tr");for(c=0,i=b.length;c<i;c++){f=document.createElement("td");f.innerHTML=b[c].html;if(b[c].id)f.id=b[c].id;if(b[c].className)f.className=b[c].className;g.appendChild(f)}h.appendChild(g); +e.parentNode.replaceChild(h,e);e=h}for(g=0,i=this.env.coltypes.length;g<i;g++)if(h=this.env.coltypes[g],(f=e.rows[0].cells[g])&&("from"==h||"to"==h)){f.id="rcm"+h;if(f.firstChild&&"a"==f.firstChild.tagName.toLowerCase())f=f.firstChild,f.onclick=function(){return rcmail.command("sort",this.__col,this)},f.__col=h;f.innerHTML=this.get_label(h)}}this.env.subject_col=null;this.env.flagged_col=null;this.env.status_col=null;if(0<=(g=$.inArray("subject",this.env.coltypes)))if(this.env.subject_col=g,d)d.subject_col= +g;if(0<=(g=$.inArray("flag",this.env.coltypes)))this.env.flagged_col=g;if(0<=(g=$.inArray("status",this.env.coltypes)))this.env.status_col=g;d&&d.init_header()};this.set_rowcount=function(a,b){if(b&&b!=this.env.mailbox)return!1;$(this.gui_objects.countdisplay).html(a);this.set_page_buttons()};this.set_mailboxname=function(a){if(this.gui_objects.mailboxname&&a)this.gui_objects.mailboxname.innerHTML=a};this.set_quota=function(a){a&&this.gui_objects.quotadisplay&&("object"===typeof a&&"image"==a.type? +this.percent_indicator(this.gui_objects.quotadisplay,a):$(this.gui_objects.quotadisplay).html(a))};this.set_unread_count=function(a,b,d){if(!this.gui_objects.mailboxlist)return!1;this.env.unread_counts[a]=b;this.set_unread_count_display(a,d)};this.set_unread_count_display=function(a,b){var d,e,f,h,g;if(f=this.get_folder_li(a,"",!0)){h=this.env.unread_counts[a]?this.env.unread_counts[a]:0;e=$(f).children("a").eq(0);d=e.children("span.unreadcount");!d.length&&h&&(d=$("<span>").addClass("unreadcount").appendTo(e)); +e=0;if((g=f.getElementsByTagName("div")[0])&&g.className.match(/collapsed/))for(var i in this.env.unread_counts)0==i.indexOf(a+this.env.delimiter)&&(e+=this.env.unread_counts[i]);h&&d.length?d.html(" ("+h+")"):d.length&&d.remove();d=RegExp(RegExp.escape(this.env.delimiter)+"[^"+RegExp.escape(this.env.delimiter)+"]+$");a.match(d)&&this.set_unread_count_display(a.replace(d,""),!1);0<h+e?$(f).addClass("unread"):$(f).removeClass("unread")}d=/^\([0-9]+\)\s+/i;b&&document.title&&(f="",f=""+document.title, +f=h&&f.match(d)?f.replace(d,"("+h+") "):h?"("+h+") "+f:f.replace(d,""),this.set_pagetitle(f))};this.toggle_prefer_html=function(a){$("#rcmfd_show_images").prop("disabled",!a.checked).val(0)};this.toggle_preview_pane=function(a){$("#rcmfd_preview_pane_mark_read").prop("disabled",!a.checked)};this.set_headers=function(a){this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box&&a&&$(this.gui_objects.all_headers_box).html(a).show()};this.load_headers=function(a){if(this.gui_objects.all_headers_row&& +this.gui_objects.all_headers_box&&this.env.uid)$(a).removeClass("show-headers").addClass("hide-headers"),$(this.gui_objects.all_headers_row).show(),a.onclick=function(){rcmail.hide_headers(a)},this.gui_objects.all_headers_box.innerHTML||this.http_post("headers","_uid="+this.env.uid,this.display_message(this.get_label("loading"),"loading"))};this.hide_headers=function(a){if(this.gui_objects.all_headers_row&&this.gui_objects.all_headers_box)$(a).removeClass("hide-headers").addClass("show-headers"), +$(this.gui_objects.all_headers_row).hide(),a.onclick=function(){rcmail.load_headers(a)}};this.percent_indicator=function(a,b){if(!b||!a)return!1;var d=b.width?b.width:this.env.indicator_width?this.env.indicator_width:100,e=b.height?b.height:this.env.indicator_height?this.env.indicator_height:14,f=b.percent?Math.abs(parseInt(b.percent)):0,h=parseInt(f/100*d),g=$(a).position();g.top=Math.max(0,g.top);g.left=Math.max(0,g.left);this.env.indicator_width=d;this.env.indicator_height=e;h>d&&(h=d,f=100);if(b.title)b.title= +this.get_label("quota")+": "+b.title;var i=$("<div>");i.css({position:"absolute",top:g.top,left:g.left,width:d+"px",height:e+"px",zIndex:100,lineHeight:e+"px"}).attr("title",b.title).addClass("quota_text").html(f+"%");var j=$("<div>");j.css({position:"absolute",top:g.top+1,left:g.left+1,width:h+"px",height:e+"px",zIndex:99});h=$("<div>");h.css({position:"absolute",top:g.top+1,left:g.left+1,width:d+"px",height:e+"px",zIndex:98}).addClass("quota_bg");80<=f?(i.addClass(" quota_text_high"),j.addClass("quota_high")): +55<=f?(i.addClass(" quota_text_mid"),j.addClass("quota_mid")):(i.addClass(" quota_text_low"),j.addClass("quota_low"));$(a).html("").append(j).append(h).append(i);$("#quotaimg").attr("title",b.title)};this.html2plain=function(a,b){var d=this,e=this.set_busy(!0,"converting");this.log("HTTP POST: ?_task=utils&_action=html2text");$.ajax({type:"POST",url:"?_task=utils&_action=html2text",data:a,contentType:"application/octet-stream",error:function(a,b,g){d.http_error(a,b,g,e)},success:function(a){d.set_busy(!1, +null,e);$("#"+b).val(a);d.log(a)}})};this.plain2html=function(a,b){var d=this.set_busy(!0,"converting"),a=a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");$("#"+b).val(a?"<pre>"+a+"</pre>":"");this.set_busy(!1,null,d)};this.url=function(a,b){var d="string"===typeof b?"&"+b:"";if("string"!==typeof a)b=a;else if(!b||"object"!==typeof b)b={};b._action=a?a:this.env.action;var e=this.env.comm_path;if(b._action.match(/([a-z]+)\/([a-z0-9-_.]+)/))b._action=RegExp.$2,e=e.replace(/\_task=[a-z]+/, +"_task="+RegExp.$1);var f={},h;for(h in b)void 0!==b[h]&&null!==b[h]&&(f[h]=b[h]);return e+"&"+$.param(f)+d};this.redirect=function(a,b){(b||null===b)&&this.set_busy(!0);this.is_framed()?parent.rcmail.redirect(a,b):this.location_href(a,window)};this.goto_url=function(a,b){this.redirect(this.url(a,b))};this.location_href=function(a,b,d){d&&this.lock_frame();bw.ie&&b==window?$("<a>").attr("href",a).appendTo(document.body).get(0).click():b.location.href=a};this.http_request=function(a,b,d){var e=this.url(a, +b),a=this.triggerEvent("request"+a,b);if(void 0!==a){if(!1===a)return!1;b=a}e+="&_remote=1";this.log("HTTP GET: "+e);return $.ajax({type:"GET",url:e,data:{_unlock:d?d:0},dataType:"json",success:function(a){i.http_response(a)},error:function(a,b,e){rcmail.http_error(a,b,e,d)}})};this.http_post=function(a,b,d){var e=this.url(a);b&&"object"===typeof b?(b._remote=1,b._unlock=d?d:0):b+=(b?"&":"")+"_remote=1"+(d?"&_unlock="+d:"");a=this.triggerEvent("request"+a,b);if(void 0!==a){if(!1===a)return!1;b=a}this.log("HTTP POST: "+ +e);return $.ajax({type:"POST",url:e,data:b,dataType:"json",success:function(a){i.http_response(a)},error:function(a,b,e){rcmail.http_error(a,b,e,d)}})};this.abort_request=function(a){a.request&&a.request.abort();a.lock&&this.set_busy(!1,null,a.lock)};this.http_response=function(a){if(a){a.unlock&&this.set_busy(!1);this.triggerEvent("responsebefore",{response:a});this.triggerEvent("responsebefore"+a.action,{response:a});a.env&&this.set_env(a.env);if("object"===typeof a.texts)for(var b in a.texts)"string"=== +typeof a.texts[b]&&this.add_label(b,a.texts[b]);a.exec&&(this.log(a.exec),eval(a.exec));if(a.callbacks&&a.callbacks.length)for(b=0;b<a.callbacks.length;b++)this.triggerEvent(a.callbacks[b][0],a.callbacks[b][1]);switch(a.action){case "delete":if("addressbook"==this.task){var d;b=this.contact_list.get_selection();d=!1;b&&this.contact_list.rows[b]&&(d=""==this.env.source?(d=(""+b).replace(/^[^-]+-/,""))&&this.env.address_sources[d]&&!this.env.address_sources[d].readonly:!this.env.address_sources[this.env.source].readonly); +this.enable_command("compose",b&&this.contact_list.rows[b]);this.enable_command("delete","edit",d);this.enable_command("export",this.contact_list&&0<this.contact_list.rowcount)}case "moveto":"show"==this.env.action?(this.enable_command(this.env.message_commands,!0),this.env.list_post||this.enable_command("reply-list",!1)):"addressbook"==this.task&&this.triggerEvent("listupdate",{folder:this.env.source,rowcount:this.contact_list.rowcount});case "purge":case "expunge":"mail"==this.task&&(this.env.messagecount|| +(this.env.contentframe&&this.show_contentframe(!1),this.enable_command(this.env.message_commands,"purge","expunge","select-all","select-none","sort","expand-all","expand-unread","collapse-all",!1)),this.message_list&&this.triggerEvent("listupdate",{folder:this.env.mailbox,rowcount:this.message_list.rowcount}));break;case "check-recent":case "getunread":case "search":this.env.qsearch=null;case "list":if("mail"==this.task){if(this.enable_command("show","expunge","select-all","select-none","sort",0< +this.env.messagecount),this.enable_command("purge",this.purge_mailbox_test()),this.enable_command("expand-all","expand-unread","collapse-all",this.env.threading&&this.env.messagecount),"list"==a.action||"search"==a.action)this.msglist_select(this.message_list),this.triggerEvent("listupdate",{folder:this.env.mailbox,rowcount:this.message_list.rowcount})}else if("addressbook"==this.task&&(this.enable_command("export",this.contact_list&&0<this.contact_list.rowcount),"list"==a.action||"search"==a.action))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})}a.unlock&&this.hide_message(a.unlock);this.triggerEvent("responseafter",{response:a});this.triggerEvent("responseafter"+a.action,{response:a})}};this.http_error=function(a,b,d,e){b=a.statusText;this.set_busy(!1,null,e);a.abort();a.status&&b&&this.display_message(this.get_label("servererror")+" ("+b+")", +"error")};this.async_upload_form=function(a,b,d){var e=(new Date).getTime(),f="rcmupload"+e;if(this.env.upload_progress_name){var h=this.env.upload_progress_name,g=$("input[name="+h+"]",a);g.length||(g=$("<input>").attr({type:"hidden",name:h}),g.prependTo(a));g.val(e)}document.all?document.body.insertAdjacentHTML("BeforeEnd",'<iframe name="'+f+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'):(h=document.createElement("iframe"),h.name=f,h.style.border="none",h.style.width= +0,h.style.height=0,h.style.visibility="hidden",document.body.appendChild(h));$(f).bind("load",{ts:e},d);$(a).attr({target:f,action:this.url(b,{_id:this.env.compose_id||"",_uploadid:e}),method:"POST"}).attr(a.encoding?"encoding":"enctype","multipart/form-data").submit();return f};this.start_keepalive=function(){this._int&&clearInterval(this._int);if(this.env.keep_alive&&!this.env.framed&&"mail"==this.task&&this.gui_objects.mailboxlist)this._int=setInterval(function(){i.check_for_recent(!1)},1E3*this.env.keep_alive); +else if(this.env.keep_alive&&!this.env.framed&&"login"!=this.task&&"print"!=this.env.action)this._int=setInterval(function(){i.keep_alive()},1E3*this.env.keep_alive)};this.keep_alive=function(){this.busy||this.http_request("keep-alive")};this.check_for_recent=function(a){if(!this.busy){var b,d="_mbox="+urlencode(this.env.mailbox);a&&(b=this.set_busy(!0,"checkingmail"),d+="&_refresh=1",this.start_keepalive());this.gui_objects.messagelist&&(d+="&_list=1");this.gui_objects.quotadisplay&&(d+="&_quota=1"); +this.env.search_request&&(d+="&_search="+this.env.search_request);this.http_request("check-recent",d,b)}};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(a){if(void 0!==a.selectionEnd)return a.selectionEnd;if(document.selection&&document.selection.createRange){var b= +document.selection.createRange();if(b.parentElement()!=a)return 0;var d=b.duplicate();"TEXTAREA"==a.tagName?d.moveToElementText(a):d.expand("textedit");d.setEndPoint("EndToStart",b);b=d.text.length;return b<=a.value.length?b:-1}return a.value.length};this.set_caret_pos=function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var d=a.createTextRange();d.collapse(!0);d.moveEnd("character",b);d.moveStart("character",b);d.select()}};this.lock_form=function(a,b){if(a&&a.elements){var d, +e,f;if(b)this.disabled_form_elements=[];for(d=0,e=a.elements.length;d<e;d++)if(f=a.elements[d],"hidden"!=f.type)if(b&&f.disabled)this.disabled_form_elements.push(f);else if(b||this.disabled_form_elements&&0>$.inArray(f,this.disabled_form_elements))f.disabled=b}}}rcube_webmail.long_subject_title=function(i,s){if(!i.title){var a=$(i);if(a.width()+15*s>a.parent().width())i.title=a.html()}}; +rcube_webmail.long_subject_title_ie=function(i,s){if(!i.title){var a=$(i),b=$.trim(a.text()),d=$("<span>").text(b).css({position:"absolute","float":"left",visibility:"hidden","font-size":a.css("font-size"),"font-weight":a.css("font-weight")}).appendTo($("body")),e=d.width();d.remove();if(e+15*s>a.width())i.title=b}};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; diff --git a/program/js/app.js.src b/program/js/app.js.src index a127b29..15d8884 100644 --- a/program/js/app.js.src +++ b/program/js/app.js.src @@ -3,7 +3,8 @@ | Roundcube Webmail Client Script | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -14,12 +15,12 @@ | Requires: jquery.js, common.js, list.js | +-----------------------------------------------------------------------+ - $Id: app.js 5281 2011-09-27 07:29:49Z alec $ + $Id: app.js 5554 2011-12-07 07:50:00Z alec $ */ function rcube_webmail() { - this.env = {}; + this.env = { recipients_separator:',', recipients_delimiter:', ' }; this.labels = {}; this.buttons = {}; this.buttons_sel = {}; @@ -36,7 +37,7 @@ function rcube_webmail() // webmail client settings this.dblclick_time = 500; - this.message_time = 2000; + this.message_time = 4000; this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); @@ -85,7 +86,7 @@ function rcube_webmail() if (over) button_prop.over = over; this.buttons[command].push(button_prop); - + if (this.loaded) init_button(command, button_prop); }; @@ -127,7 +128,7 @@ function rcube_webmail() // initialize webmail client this.init = function() { - var p = this; + var n, p = this; this.task = this.env.task; // check browser @@ -137,13 +138,29 @@ function rcube_webmail() } // find all registered gui containers - for (var n in this.gui_containers) + for (n in this.gui_containers) this.gui_containers[n] = $('#'+this.gui_containers[n]); // find all registered gui objects - for (var n in this.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(); @@ -154,7 +171,7 @@ function rcube_webmail() } // enable general commands - this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'undo', true); + this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', true); if (this.env.permaurl) this.enable_command('permaurl', true); @@ -163,7 +180,7 @@ function rcube_webmail() case 'mail': // enable mail commands - this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); + this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); if (this.gui_objects.messagelist) { @@ -206,12 +223,13 @@ function rcube_webmail() 'moveto', 'copy', 'delete', 'open', 'mark', 'edit', 'viewsource', 'download', 'print', 'load-attachment', 'load-headers', 'forward-attachment']; - if (this.env.action=='show' || this.env.action=='preview') { + 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='+urlencode(this.env.mailbox), + this.http_request('pagenav', '_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox) + + (this.env.search_request ? '&_search='+this.env.search_request : ''), this.display_message('', 'loading')); } @@ -277,6 +295,9 @@ function rcube_webmail() 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, @@ -299,6 +320,7 @@ function rcube_webmail() } this.update_group_commands(); + this.command('list'); } this.set_page_buttons(); @@ -318,22 +340,13 @@ function rcube_webmail() if (this.env.action == 'add' || this.env.action == 'edit') this.init_contact_form(); } + if (this.gui_objects.qsearchbox) { this.enable_command('search', 'reset-search', 'moveto', true); } - if (this.contact_list && this.contact_list.rowcount > 0) - this.enable_command('export', true); - - this.enable_command('add', 'import', this.env.writable_source); - this.enable_command('list', 'listgroup', 'advanced-search', true); - - // load contacts of selected source - if (!this.env.action) - this.command('list', this.env.source); break; - case 'settings': this.enable_command('preferences', 'identities', 'save', 'folders', true); @@ -384,7 +397,12 @@ function rcube_webmail() $('#rcmloginpwd').focus(); // detect client timezone - $('#rcmlogintz').val(new Date().getTimezoneOffset() / -60); + var dt = new Date(), + tz = dt.getTimezoneOffset() / -60, + stdtz = dt.getStdTimezoneOffset() / -60; + + $('#rcmlogintz').val(stdtz); + $('#rcmlogindst').val(tz > stdtz ? 1 : 0); // display 'loading' message on form submit, lock submit button $('form').submit(function () { @@ -443,6 +461,8 @@ function rcube_webmail() // execute a specific command on the web client this.command = function(command, props, obj) { + var ret, uid, cid, url, flag; + if (obj && obj.blur) obj.blur(); @@ -459,32 +479,34 @@ function rcube_webmail() } // check input before leaving compose step - if (this.task=='mail' && this.env.action=='compose' && $.inArray(command, this.env.compose_commands)<0) { + 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') { - var ret = this.command_handlers[command](props, obj); + ret = this.command_handlers[command](props, obj); return ret !== undefined ? ret : (obj ? false : true); } else if (typeof this.command_handlers[command] === 'string') { - var ret = window[this.command_handlers[command]](props, obj); + 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}); - var ret = this.triggerEvent('before'+command, props); + ret = this.triggerEvent('before'+command, props); if (ret !== undefined) { - // abort if one the handlers returned false + // abort if one of the handlers returned false if (ret === false) return false; else props = ret; } + ret = undefined; + // process internal command switch (command) { @@ -514,7 +536,6 @@ function rcube_webmail() return false; case 'open': - var uid; if (uid = this.get_single_uid()) { obj.href = '?_task='+this.env.task+'&_action=show&_mbox='+urlencode(this.env.mailbox)+'&_uid='+uid; return true; @@ -522,21 +543,15 @@ function rcube_webmail() break; case 'list': - if (this.task=='mail') { - if (!this.env.search_request || (props && props != this.env.mailbox)) - this.reset_qsearch(); - + this.reset_qsearch(); + if (this.task == 'mail') { this.list_mailbox(props); if (this.env.trash_mailbox && !this.env.flag_for_deletion) this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage'); } else if (this.task == 'addressbook') { - if (!this.env.search_request || (props != this.env.source)) - this.reset_qsearch(); - this.list_contacts(props); - this.enable_command('add', 'import', this.env.writable_source); } break; @@ -589,7 +604,7 @@ function rcube_webmail() // common commands used in multiple tasks case 'show': if (this.task == 'mail') { - var uid = this.get_single_uid(); + uid = this.get_single_uid(); if (uid && (!this.env.uid || uid != this.env.uid)) { if (this.env.mailbox == this.env.drafts_mailbox) this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); @@ -598,7 +613,7 @@ function rcube_webmail() } } else if (this.task == 'addressbook') { - var cid = props ? props : this.get_single_cid(); + cid = props ? props : this.get_single_cid(); if (cid && !(this.env.action == 'show' && cid == this.env.cid)) this.load_contact(cid, 'show'); } @@ -614,13 +629,12 @@ function rcube_webmail() break; case 'edit': - var cid; 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())) { - var url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid='; + url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid='; this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true); } break; @@ -698,7 +712,7 @@ function rcube_webmail() if (props && !props._row) break; - var uid, flag = 'read'; + flag = 'read'; if (props._row.uid) { uid = props._row.uid; @@ -718,7 +732,7 @@ function rcube_webmail() if (props && !props._row) break; - var uid, flag = 'flagged'; + flag = 'flagged'; if (props._row.uid) { uid = props._row.uid; @@ -814,17 +828,11 @@ function rcube_webmail() break; case 'compose': - var url = this.env.comm_path+'&_action=compose'; + url = this.url('mail/compose'); if (this.task == 'mail') { url += '&_mbox='+urlencode(this.env.mailbox); - - if (this.env.mailbox == this.env.drafts_mailbox) { - var uid; - if (uid = this.get_single_uid()) - url += '&_draft_uid='+uid; - } - else if (props) + if (props) url += '&_to='+urlencode(props); } // modify url if we're in addressbook @@ -848,10 +856,14 @@ function rcube_webmail() } if (a_cids.length) - this.http_post('mailto', {_cid: a_cids.join(','), _source: this.env.source}, true); + 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='+urlencode(props); this.redirect(url); break; @@ -891,7 +903,7 @@ function rcube_webmail() if (!this.gui_objects.messageform) break; - if (!this.check_compose_input()) + if (!props.nocheck && !this.check_compose_input(command)) break; // Reset the auto-save timer @@ -926,9 +938,8 @@ function rcube_webmail() case 'reply-all': case 'reply-list': case 'reply': - var uid; if (uid = this.get_single_uid()) { - var url = '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); + url = '_reply_uid='+uid+'&_mbox='+urlencode(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'); @@ -941,7 +952,6 @@ function rcube_webmail() case 'forward-attachment': case 'forward': - var uid, url; if (uid = this.get_single_uid()) { url = '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); if (command == 'forward-attachment' || (!props && this.env.forward_attachment)) @@ -951,7 +961,6 @@ function rcube_webmail() break; case 'print': - var uid; 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) { @@ -963,7 +972,6 @@ function rcube_webmail() break; case 'viewsource': - var uid; 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) @@ -972,7 +980,6 @@ function rcube_webmail() break; case 'download': - var uid; if (uid = this.get_single_uid()) this.goto_url('viewsource', '&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+'&_save=1'); break; @@ -1006,6 +1013,7 @@ function rcube_webmail() break; case 'listgroup': + this.reset_qsearch(); this.list_contacts(props.source, props.id); break; @@ -1052,24 +1060,26 @@ function rcube_webmail() // unified command call (command name == function name) default: var func = command.replace(/-/g, '_'); - if (this[func] && typeof this[func] === 'function') - this[func](props); + if (this[func] && typeof this[func] === 'function') { + ret = this[func](props); + } break; } - this.triggerEvent('after'+command, props); + if (this.triggerEvent('after'+command, props) === false) + ret = false; this.triggerEvent('actionafter', {props:props, action:command}); - return obj ? false : true; + return ret === false ? false : obj ? false : true; }; // set command(s) enabled or disabled this.enable_command = function() { - var args = Array.prototype.slice.call(arguments), + var i, n, args = Array.prototype.slice.call(arguments), enable = args.pop(), cmd; - for (var n=0; n<args.length; n++) { + for (n=0; n<args.length; n++) { cmd = args[n]; // argument of type array if (typeof cmd === 'string') { @@ -1078,7 +1088,7 @@ function rcube_webmail() } // push array elements into commands array else { - for (var i in cmd) + for (i in cmd) args.push(cmd[i]); } } @@ -1205,6 +1215,24 @@ function rcube_webmail() 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); + }; + /*********************************************************/ /********* event handling methods *********/ @@ -1251,13 +1279,14 @@ function rcube_webmail() this.initialBodyScrollTop = bw.ie ? 0 : window.pageYOffset; this.initialListScrollTop = this.gui_objects.folderlist.parentNode.scrollTop; - var li, pos, list, height; - list = $(this.gui_objects.folderlist); - pos = list.offset(); + 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 (var k in model) { + for (k in model) { if (li = this.get_folder_li(k)) { // only visible folders if (height = li.firstChild.offsetHeight) { @@ -1293,19 +1322,18 @@ function rcube_webmail() this.drag_move = function(e) { if (this.gui_objects.folderlist && this.env.folder_coords) { - // offsets to compensate for scrolling while dragging a message - var boffset = bw.ie ? -document.documentElement.scrollTop : this.initialBodyScrollTop; - var moffset = this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop; - var toffset = -moffset-boffset; - var li, div, pos, mouse, check, oldclass, - layerclass = 'draglayernormal'; + var k, li, div, check, oldclass, + layerclass = 'draglayernormal', + mouse = rcube_event.get_mouse_pos(e), + pos = this.env.folderlist_coords, + // offsets to compensate for scrolling while dragging a message + 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 = rcube_event.get_mouse_pos(e); - pos = this.env.folderlist_coords; - mouse.y += toffset; + mouse.y += -moffset-boffset; // if mouse pointer is outside of folderlist if (mouse.x < pos.x1 || mouse.x >= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) { @@ -1320,10 +1348,10 @@ function rcube_webmail() } // over the folders - for (var k in this.env.folder_coords) { + 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))) { + if ((check = this.check_droptarget(k))) { li = this.get_folder_li(k); div = $(li.getElementsByTagName('div')[0]); @@ -1334,9 +1362,9 @@ function rcube_webmail() this.folder_auto_expand = k; this.folder_auto_timer = window.setTimeout(function() { - rcmail.command('collapse-folder', rcmail.folder_auto_expand); - rcmail.drag_start(null); - }, 1000); + rcmail.command('collapse-folder', rcmail.folder_auto_expand); + rcmail.drag_start(null); + }, 1000); } else if (this.folder_auto_timer) { window.clearTimeout(this.folder_auto_timer); this.folder_auto_timer = null; @@ -1362,31 +1390,29 @@ function rcube_webmail() } }; - this.collapse_folder = function(id) + this.collapse_folder = function(name) { - var li = this.get_folder_li(id), - div = $(li.getElementsByTagName('div')[0]); - - if (!div || (!div.hasClass('collapsed') && !div.hasClass('expanded'))) - return; - - var ul = $(li.getElementsByTagName('ul')[0]); + 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(id)+'&'); + var reg = new RegExp('&'+urlencode(name)+'&'); this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, ''); } - else { + else if (div.hasClass('expanded')) { ul.hide(); div.removeClass('expanded').addClass('collapsed'); - this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(id)+'&'; + this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(name)+'&'; // select parent folder if one of its childs is currently selected - if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0) - this.command('list', id); + if (this.env.mailbox.indexOf(name + this.env.delimiter) == 0) + this.command('list', name); } + else + return; // Work around a bug in IE6 and IE7, see #1485309 if (bw.ie6 || bw.ie7) { @@ -1398,13 +1424,17 @@ function rcube_webmail() } this.command('save-pref', { name: 'collapsed_folders', value: this.env.collapsed_folders }); - this.set_unread_count_display(id, false); + this.set_unread_count_display(name, false); }; this.doc_mouse_up = function(e) { var model, list, li, 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) { if (!rcube_mouse_is_over(e, list.list.parentNode)) list.blur(); @@ -1526,11 +1556,12 @@ function rcube_webmail() 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) - this.command('delete'); - else if (list.key_pressed == list.BACKSPACE_KEY) + 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'); @@ -1644,14 +1675,18 @@ function rcube_webmail() 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.replied?1:0, - unread: flags.unread?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, @@ -1665,23 +1700,18 @@ function rcube_webmail() flags: flags.extra_flags }); - var c, html, tree = expando = '', + var c, n, col, html, tree = '', expando = '', list = this.message_list, rows = list.rows, - tbody = this.gui_objects.messagelist.tBodies[0], - rowcount = tbody.rows.length, - even = rowcount%2, message = this.env.messages[uid], css_class = 'message' - + (even ? ' even' : ' odd') - + (flags.unread ? ' unread' : '') + + (!flags.seen ? ' unread' : '') + (flags.deleted ? ' deleted' : '') + (flags.flagged ? ' flagged' : '') - + (flags.unread_children && !flags.unread && !this.env.autoexpand_threads ? ' unroot' : '') + + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '') + (message.selected ? ' selected' : ''), // for performance use DOM instead of jQuery here - row = document.createElement('tr'), - col = document.createElement('td'); + row = document.createElement('tr'); row.id = 'rcmrow'+uid; row.className = css_class; @@ -1692,12 +1722,12 @@ function rcube_webmail() css_class += ' status'; if (flags.deleted) css_class += ' deleted'; - else if (flags.unread) + else if (!flags.seen) css_class += ' unread'; else if (flags.unread_children > 0) css_class += ' unreadchildren'; } - if (flags.replied) + if (flags.answered) css_class += ' replied'; if (flags.forwarded) css_class += ' forwarded'; @@ -1708,9 +1738,10 @@ function rcube_webmail() // threads if (this.env.threading) { - // This assumes that div width is hardcoded to 15px, - var width = message.depth * 15; 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)) @@ -1725,13 +1756,9 @@ function rcube_webmail() if (message.expanded === undefined && (this.env.autoexpand_threads == 1 || (this.env.autoexpand_threads == 2 && message.unread_children))) { message.expanded = true; } - } - if (width) - tree += '<span id="rcmtab' + uid + '" class="branch" style="width:' + width + 'px;"> </span>'; - - if (message.has_children && !message.depth) expando = '<div id="rcmexpando' + uid + '" class="' + (message.expanded ? 'expanded' : 'collapsed') + '"> </div>'; + } } tree += '<span id="msgicn'+uid+'" class="'+css_class+'"> </span>'; @@ -1745,7 +1772,7 @@ function rcube_webmail() } // add each submitted col - for (var n in this.env.coltypes) { + for (n in this.env.coltypes) { c = this.env.coltypes[n]; col = document.createElement('td'); col.className = String(c).toLowerCase(); @@ -1765,7 +1792,7 @@ function rcube_webmail() else if (c == 'status') { if (flags.deleted) css_class = 'deleted'; - else if (flags.unread) + else if (!flags.seen) css_class = 'unread'; else if (flags.unread_children > 0) css_class = 'unreadchildren'; @@ -1775,8 +1802,17 @@ function rcube_webmail() } else if (c == 'threads') html = expando; - else if (c == 'subject') + else if (c == 'subject') { + if (bw.ie) + col.onmouseover = function() { rcube_webmail.long_subject_title_ie(this, message.depth+1); }; 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]; @@ -1940,18 +1976,13 @@ function rcube_webmail() // list messages of a specific mailbox using filter this.filter_mailbox = function(filter) { - var search, lock = this.set_busy(true, 'searching'); - - if (this.gui_objects.qsearchbox) - search = this.gui_objects.qsearchbox.value; + var lock = this.set_busy(true, 'searching'); this.clear_message_list(); // reset vars this.env.current_page = 1; - this.http_request('search', '_filter='+filter - + (search ? '&_q='+urlencode(search) : '') - + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), lock); + this.http_request('search', this.search_params(false, filter), lock); }; // list messages of a specific mailbox @@ -1986,7 +2017,7 @@ function rcube_webmail() if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort)) url += '&_refresh=1'; - this.select_folder(mbox, this.env.mailbox); + this.select_folder(mbox, '', true); this.env.mailbox = mbox; // load message list remotely @@ -2050,8 +2081,7 @@ function rcube_webmail() new_row = tbody.firstChild; while (new_row) { - if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) - && r.unread_children) { + 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); } @@ -2086,8 +2116,12 @@ function rcube_webmail() }; // Initializes threads indicators/expanders after list update - this.init_threads = function(roots) + 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(); @@ -2491,7 +2525,7 @@ function rcube_webmail() // 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.shiftkey) { + if (list && list.modkey == SHIFT_KEY) { if (confirm(this.get_label('deletemessagesconfirm'))) this.permanently_remove_messages(); } @@ -2914,12 +2948,14 @@ function rcube_webmail() 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'); }; // checks the input fields before sending a message - this.check_compose_input = function() + this.check_compose_input = function(cmd) { // check input fields var ed, input_to = $("[name='_to']"), @@ -2954,15 +2990,28 @@ function rcube_webmail() // display localized warning for missing subject if (input_subject.val() == '') { - var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject')); + 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')); - // user hit cancel, so don't send - if (!subject && subject !== '') { + var buttons = {}; + buttons[this.get_label('cancel')] = function(){ input_subject.focus(); - return false; - } - else - input_subject.val((subject ? subject : this.get_label('nosubject'))); + $(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 @@ -3151,7 +3200,7 @@ function rcube_webmail() sig = this.env.signatures[sig].is_html ? this.env.signatures[sig].plain_text : this.env.signatures[sig].text; sig = sig.replace(/\r\n/g, '\n'); - if (!sig.match(/^--[ -]\n/)) + if (!sig.match(/^--[ -]\n/m)) sig = sig_separator + '\n' + sig; p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig); @@ -3163,7 +3212,7 @@ function rcube_webmail() sig = this.env.signatures[id]['is_html'] ? this.env.signatures[id]['plain_text'] : this.env.signatures[id]['text']; sig = sig.replace(/\r\n/g, '\n'); - if (!sig.match(/^--[ -]\n/)) + if (!sig.match(/^--[ -]\n/m)) sig = sig_separator + '\n' + sig; if (this.env.sig_above) { @@ -3232,12 +3281,12 @@ function rcube_webmail() if (this.env.signatures[id]) { if (this.env.signatures[id].is_html) { sig = this.env.signatures[id].text; - if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/)) + if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/m)) sig = sig_separator + '<br />' + sig; } else { sig = this.env.signatures[id].text; - if (!sig.match(/^--[ -]\r?\n/)) + if (!sig.match(/^--[ -]\r?\n/m)) sig = sig_separator + '\n' + sig; sig = '<pre>' + sig + '</pre>'; } @@ -3341,16 +3390,8 @@ function rcube_webmail() this.remove_from_attachment_list = function(name) { - if (this.env.attachments[name]) - delete this.env.attachments[name]; - - if (!this.gui_objects.attachmentlist) - return false; - - var list = this.gui_objects.attachmentlist.getElementsByTagName("li"); - for (i=0; i<list.length; i++) - if (list[i].id == name) - this.gui_objects.attachmentlist.removeChild(list[i]); + delete this.env.attachments[name]; + $('#'+name).remove(); }; this.remove_attachment = function(name) @@ -3403,40 +3444,58 @@ function rcube_webmail() this.qsearch = function(value) { if (value != '') { - var n, r, addurl = '', mods_arr = [], - mods = this.env.search_mods, - mbox = this.env.mailbox, - lock = this.set_busy(true, 'searching'); + var n, lock = this.set_busy(true, 'searching'); - if (this.message_list) { + if (this.message_list) this.clear_message_list(); - if (mods) - mods = mods[mbox] ? mods[mbox] : mods['*']; - } else if (this.contact_list) { + else if (this.contact_list) this.list_contacts_clear(); - } - - if (mods) { - for (n in mods) - mods_arr.push(n); - addurl += '&_headers='+mods_arr.join(','); - } - - if (this.gui_objects.search_filter) - addurl += '&_filter=' + this.gui_objects.search_filter.value; // reset vars this.env.current_page = 1; - r = this.http_request('search', '_q='+urlencode(value) - + (mbox ? '&_mbox='+urlencode(mbox) : '') + r = this.http_request('search', this.search_params(value) + (this.env.source ? '&_source='+urlencode(this.env.source) : '') - + (this.env.group ? '&_gid='+urlencode(this.env.group) : '') - + (addurl ? addurl : ''), lock); + + (this.env.group ? '&_gid='+urlencode(this.env.group) : ''), 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.push('_filter=' + urlencode(filter)); + + if (search) { + url.push('_q='+urlencode(search)); + + if (mods && this.message_list) + mods = mods[mbox] ? mods[mbox] : mods['*']; + + if (mods) { + for (n in mods) + mods_arr.push(n); + url.push('_headers='+mods_arr.join(',')); + } + } + + if (mbox) + url.push('_mbox='+urlencode(mbox)); + + return url.join('&'); + }; + // reset quick-search form this.reset_qsearch = function() { @@ -3448,6 +3507,7 @@ function rcube_webmail() this.env.qsearch = null; this.env.search_request = null; + this.env.search_id = null; }; this.sent_successfully = function(type, msg) @@ -3542,7 +3602,7 @@ function rcube_webmail() this.insert_recipient = function(id) { - if (!this.env.contacts[id] || !this.ksearch_input) + if (id === null || !this.env.contacts[id] || !this.ksearch_input) return; // get cursor pos @@ -3559,13 +3619,13 @@ function rcube_webmail() // insert all members of a group if (typeof this.env.contacts[id] === 'object' && this.env.contacts[id].id) { - insert += this.env.contacts[id].name + ', '; + insert += this.env.contacts[id].name + this.env.recipients_delimiter; this.group2expand = $.extend({}, this.env.contacts[id]); this.group2expand.input = this.ksearch_input; this.http_request('mail/group-expand', '_source='+urlencode(this.env.contacts[id].source)+'&_gid='+urlencode(this.env.contacts[id].id), false); } else if (typeof this.env.contacts[id] === 'string') { - insert = this.env.contacts[id] + ', '; + insert = this.env.contacts[id] + this.env.recipients_delimiter; trigger = true; } @@ -3602,7 +3662,7 @@ function rcube_webmail() // get string from current cursor pos to last comma var cpos = this.get_caret_pos(this.ksearch_input), - p = inp_value.lastIndexOf(',', cpos-1), + 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; @@ -3614,22 +3674,19 @@ function rcube_webmail() if (q == this.ksearch_value) return; + this.ksearch_destroy(); + if (q.length && q.length < min) { - if (!this.env.acinfo) { - this.env.acinfo = this.display_message( + if (!this.ksearch_info) { + this.ksearch_info = this.display_message( this.get_label('autocompletechars').replace('$min', min)); } return; } - else if (this.env.acinfo) { - this.hide_message(this.env.acinfo); - } var old_value = this.ksearch_value; this.ksearch_value = q; - this.ksearch_destroy(); - // ...string is empty if (!q.length) return; @@ -3671,7 +3728,9 @@ function rcube_webmail() return; // display search results - var p, ul, li, text, init, s_val = this.ksearch_value, + 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 @@ -3700,11 +3759,11 @@ function rcube_webmail() } // add each result line to list - if (results && results.length) { - for (i=0; i < results.length && maxlen > 0; i++) { + 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(s_val)+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>'); + 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; @@ -3722,20 +3781,28 @@ function rcube_webmail() } } - if (results && results.length) + if (len) this.env.contacts = this.env.contacts.concat(results); // run next parallel search - if (maxlen > 0 && this.ksearch_data.id == reqid && this.ksearch_data.sources.length) { - var lock, xhr, props = this.ksearch_data, source = props.sources.shift(); - if (source) { + if (data.id == reqid) { data.num--; - lock = this.display_message(this.get_label('searching'), 'loading'); - xhr = this.http_post(props.action, '_search='+urlencode(s_val)+'&_id='+reqid - +'&_source='+urlencode(source), lock); - - this.ksearch_data.locks.push(lock); - this.ksearch_data.requests.push(xhr); + if (maxlen > 0 && data.sources.length) { + var lock, xhr, source = data.sources.shift(); + if (source) { + lock = this.display_message(this.get_label('searching'), 'loading'); + xhr = this.http_post(data.action, '_search='+urlencode(value)+'&_id='+reqid + +'&_source='+urlencode(source), 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(); } } }; @@ -3769,8 +3836,24 @@ function rcube_webmail() this.ksearch_destroy(); }; - // Aborts pending autocomplete requests + // 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; @@ -3779,9 +3862,8 @@ function rcube_webmail() for (i=0, len=ac.locks.length; i<len; i++) this.abort_request({request: ac.requests[i], lock: ac.locks[i]}); + }; - this.ksearch_data = null; - } /*********************************************************/ /********* address book methods *********/ @@ -3823,7 +3905,7 @@ function rcube_webmail() } } - this.enable_command('compose', 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); @@ -3832,7 +3914,7 @@ function rcube_webmail() this.list_contacts = function(src, group, page) { - var add_url = '', + var folder, add_url = '', target = window; if (!src) @@ -3848,7 +3930,12 @@ function rcube_webmail() else if (group != this.env.group) page = this.env.current_page = 1; - this.select_folder((group ? 'G'+src+group : src), (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); + if (this.env.search_id) + folder = 'S'+this.env.search_id; + else + folder = group ? 'G'+src+group : src; + + this.select_folder(folder); this.env.source = src; this.env.group = group; @@ -3893,8 +3980,8 @@ function rcube_webmail() if (group) url += '&_gid='+group; - // also send search request to get the right messages - if (this.env.search_request) + // also send search request to get the right messages + if (this.env.search_request) url += '&_search='+this.env.search_request; this.http_request('list', url, lock); @@ -3904,7 +3991,8 @@ function rcube_webmail() { this.contact_list.clear(true); this.show_contentframe(false); - this.enable_command('delete', 'compose', false); + this.enable_command('delete', false); + this.enable_command('compose', this.env.group ? true : false); }; // load contact record @@ -3976,9 +4064,11 @@ function rcube_webmail() this.delete_contacts = function() { + var selection = this.contact_list.get_selection(), + undelete = this.env.source && this.env.address_sources[this.env.source].undelete; + // exit if no mailbox specified or if selection is empty - var selection = this.contact_list.get_selection(); - if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm'))) + if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm')))) return; var id, n, a_cids = [], qs = ''; @@ -4005,7 +4095,10 @@ function rcube_webmail() qs += '&_search='+this.env.search_request; // send request to server - this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs); + this.http_post('delete', '_cid='+urlencode(a_cids.join(',')) + +'&_source='+urlencode(this.env.source) + +'&_from='+(this.env.action ? this.env.action : '')+qs, + this.display_message(this.get_label('contactdeleting'), 'loading')); return true; }; @@ -4015,7 +4108,7 @@ function rcube_webmail() { var c, row, list = this.contact_list; - cid = String(cid).replace(this.identifier_expr, '_'); + cid = this.html_identifier(cid); // when in searching mode, concat cid with the source name if (!list.rows[cid]) { @@ -4031,7 +4124,7 @@ function rcube_webmail() // cid change if (newcid) { - newcid = String(newcid).replace(this.identifier_expr, '_'); + newcid = this.html_identifier(newcid); row.id = 'rcmrow' + newcid; list.remove_row(cid); list.init_row(row); @@ -4044,31 +4137,29 @@ function rcube_webmail() // add row to contacts list this.add_contact_row = function(cid, cols, select) { - if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0]) + if (!this.gui_objects.contactslist) return false; - var tbody = this.gui_objects.contactslist.tBodies[0], - rowcount = tbody.rows.length, - even = rowcount%2, + var c, list = this.contact_list, row = document.createElement('tr'); - row.id = 'rcmrow'+String(cid).replace(this.identifier_expr, '_'); - row.className = 'contact '+(even ? 'even' : 'odd'); + row.id = 'rcmrow'+this.html_identifier(cid); + row.className = 'contact'; - if (this.contact_list.in_selection(cid)) + if (list.in_selection(cid)) row.className += ' selected'; // add each submitted col - for (var c in cols) { + for (c in cols) { col = document.createElement('td'); col.className = String(c).toLowerCase(); col.innerHTML = cols[c]; row.appendChild(col); } - this.contact_list.insert_row(row); + list.insert_row(row); - this.enable_command('export', (this.contact_list.rowcount > 0)); + this.enable_command('export', list.rowcount > 0); }; this.init_contact_form = function() @@ -4090,24 +4181,27 @@ function rcube_webmail() 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, + monthNamesShort: this.env.month_names, + onSelect: function(dateText) { $(this).focus().val(dateText) } + }); + $('input.datepicker').datepicker(); + } + $("input[type='text']:visible").first().focus(); }; this.group_create = function() { - if (!this.gui_objects.folderlist) - return; - - if (!this.name_input) { - this.name_input = $('<input>').attr('type', 'text'); - this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); - this.name_input_li = $('<li>').addClass('contactgroup').append(this.name_input); - - var li = this.get_folder_li(this.env.source) - this.name_input_li.insertAfter(li); - } - - this.name_input.select().focus(); + this.add_input_row('contactgroup'); }; this.group_rename = function() @@ -4153,18 +4247,40 @@ function rcube_webmail() 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 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(); + }; + // handler for keyboard events on the input field this.add_input_keydown = function(e) { - var key = rcube_event.get_keycode(e); + var key = rcube_event.get_keycode(e), + input = $(e.target), itype = input.data('tt'); // enter if (key == 13) { - var newname = this.name_input.val(); + var newname = input.val(); if (newname) { var lock = this.set_busy(true, 'loading'); - if (this.env.group_renaming) + + if (itype == 'contactsearch') + this.http_post('search-create', '_search='+urlencode(this.env.search_request)+'&_name='+urlencode(newname), lock); + else if (this.env.group_renaming) this.http_post('group-rename', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group)+'&_name='+urlencode(newname), lock); else this.http_post('group-create', '_source='+urlencode(this.env.source)+'&_name='+urlencode(newname), lock); @@ -4209,7 +4325,7 @@ function rcube_webmail() .attr('rel', prop.source+':'+prop.id) .click(function() { return rcmail.command('listgroup', prop, this); }) .html(prop.name), - li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactgroup'}) + li = $('<li>').attr({id: 'rcmli'+this.html_identifier(key), 'class': 'contactgroup'}) .append(link); this.env.contactfolders[key] = this.env.contactgroups[key] = prop; @@ -4232,7 +4348,7 @@ function rcube_webmail() var newkey = 'G'+prop.source+prop.newid, newprop = $.extend({}, prop);; - li.id = String('rcmli'+newkey).replace(this.identifier_expr, '_'); + 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; @@ -4264,7 +4380,7 @@ function rcube_webmail() { var row, name = prop.name.toUpperCase(), sibling = this.get_folder_li(prop.source), - prefix = 'rcmliG'+(prop.source).replace(this.identifier_expr, '_'); + prefix = 'rcmliG' + this.html_identifier(prop.source); // When renaming groups, we need to remove it from DOM and insert it in the proper place if (reloc) { @@ -4335,6 +4451,9 @@ function rcube_webmail() .appendTo(cell); this.init_edit_field(col, input); + + if (colprop.type == 'date' && $.datepicker) + input.datepicker(); } else if (colprop.type == 'composite') { var childcol, cp, first, templ, cols = [], suffices = []; @@ -4480,11 +4599,106 @@ function rcube_webmail() // unselect directory/group this.unselect_directory = function() { - if (this.env.address_sources.length > 1 || this.env.group != '') { - this.select_folder('', (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source)); - this.env.group = ''; - this.env.source = ''; + 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), + 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); + }; + + // add saved search row to the list, with sorting + this.add_saved_search_row = function(prop, li, reloc) + { + var row, sibling, name = prop.name.toUpperCase(); + + // When renaming groups, we need to remove it from DOM and insert it in the proper place + 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); + }; + + // 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='+urlencode(this.env.search_id), lock); + } + }; + + // callback from server upon search-delete command + 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); + + // reset vars + this.env.current_page = 1; + this.http_request('search', '_sid='+urlencode(id), lock); }; @@ -4970,17 +5184,18 @@ function rcube_webmail() 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 button, obj, a_buttons = this.buttons[command]; + var n, button, obj, a_buttons = this.buttons[command], + len = a_buttons ? a_buttons.length : 0; - if (!a_buttons || !a_buttons.length) - return false; - - for (var n=0; n<a_buttons.length; n++) { + for (n=0; n<len; n++) { button = a_buttons[n]; obj = document.getElementById(button.id); @@ -5015,15 +5230,14 @@ function rcube_webmail() // display a specific alttext this.set_alttext = function(command, label) { - if (!this.buttons[command] || !this.buttons[command].length) - return; + var n, button, obj, link, a_buttons = this.buttons[command], + len = a_buttons ? a_buttons.length : 0; - var button, obj, link; - for (var n=0; n<this.buttons[command].length; n++) { - button = this.buttons[command][n]; + for (n=0; n<len; n++) { + button = a_buttons[n]; obj = document.getElementById(button.id); - if (button.type=='image' && obj) { + 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)); @@ -5036,20 +5250,18 @@ function rcube_webmail() // mouse over button this.button_over = function(command, id) { - var button, elm, a_buttons = this.buttons[command]; - - if (!a_buttons || !a_buttons.length) - return false; + var n, button, obj, a_buttons = this.buttons[command], + len = a_buttons ? a_buttons.length : 0; - for (var n=0; n<a_buttons.length; n++) { + for (n=0; n<len; n++) { button = a_buttons[n]; if (button.id == id && button.status == 'act') { - elm = document.getElementById(button.id); - if (elm && button.over) { + obj = document.getElementById(button.id); + if (obj && button.over) { if (button.type == 'image') - elm.src = button.over; + obj.src = button.over; else - elm.className = button.over; + obj.className = button.over; } } } @@ -5058,20 +5270,18 @@ function rcube_webmail() // mouse down on button this.button_sel = function(command, id) { - var button, elm, a_buttons = this.buttons[command]; - - if (!a_buttons || !a_buttons.length) - return; + var n, button, obj, a_buttons = this.buttons[command], + len = a_buttons ? a_buttons.length : 0; - for (var n=0; n<a_buttons.length; n++) { + for (n=0; n<len; n++) { button = a_buttons[n]; if (button.id == id && button.status == 'act') { - elm = document.getElementById(button.id); - if (elm && button.sel) { + obj = document.getElementById(button.id); + if (obj && button.sel) { if (button.type == 'image') - elm.src = button.sel; + obj.src = button.sel; else - elm.className = button.sel; + obj.className = button.sel; } this.buttons_sel[id] = command; } @@ -5081,26 +5291,23 @@ function rcube_webmail() // mouse out of button this.button_out = function(command, id) { - var button, elm, a_buttons = this.buttons[command]; - - if (!a_buttons || !a_buttons.length) - return; + var n, button, obj, a_buttons = this.buttons[command], + len = a_buttons ? a_buttons.length : 0; - for (var n=0; n<a_buttons.length; n++) { + for (n=0; n<len; n++) { button = a_buttons[n]; if (button.id == id && button.status == 'act') { - elm = document.getElementById(button.id); - if (elm && button.act) { + obj = document.getElementById(button.id); + if (obj && button.act) { if (button.type == 'image') - elm.src = button.act; + obj.src = button.act; else - elm.className = button.act; + obj.className = button.act; } } } }; - this.focus_textfield = function(elem) { elem._hasfocus = true; @@ -5134,14 +5341,14 @@ function rcube_webmail() if (!this.gui_objects.message) { // save message in order to display after page loaded if (type != 'loading') - this.pending_message = new Array(msg, type, timeout); + this.pending_message = [msg, type, timeout]; return false; } type = type ? type : 'notice'; var ref = this, - key = String(msg).replace(this.identifier_expr, '_'), + key = this.html_identifier(msg), date = new Date(), id = type + date.getTime(); @@ -5234,31 +5441,31 @@ function rcube_webmail() }; // mark a mailbox as selected and set environment variable - this.select_folder = function(name, old, prefix) + this.select_folder = function(name, prefix, encode) { if (this.gui_objects.folderlist) { var current_li, target_li; - if ((current_li = this.get_folder_li(old, prefix))) { - $(current_li).removeClass('selected').addClass('unfocused'); + if ((current_li = $('li.selected', this.gui_objects.folderlist))) { + current_li.removeClass('selected').addClass('unfocused'); } - if ((target_li = this.get_folder_li(name, prefix))) { + if ((target_li = this.get_folder_li(name, prefix, encode))) { $(target_li).removeClass('unfocused').addClass('selected'); } // trigger event hook - this.triggerEvent('selectfolder', { folder:name, old:old, prefix:prefix }); + this.triggerEvent('selectfolder', { folder:name, prefix:prefix }); } }; // helper method to find a folder list item - this.get_folder_li = function(name, prefix) + this.get_folder_li = function(name, prefix, encode) { if (!prefix) prefix = 'rcmli'; if (this.gui_objects.folderlist) { - name = String(name).replace(this.identifier_expr, '_'); + name = this.html_identifier(name, encode); return document.getElementById(prefix+name); } @@ -5327,8 +5534,12 @@ function rcube_webmail() }; // replace content of row count display - this.set_rowcount = function(text) + 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 @@ -5368,7 +5579,7 @@ function rcube_webmail() { var reg, link, text_obj, item, mycount, childcount, div; - if (item = this.get_folder_li(mbox)) { + 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'); @@ -5380,7 +5591,7 @@ function rcube_webmail() if ((div = item.getElementsByTagName('div')[0]) && div.className.match(/collapsed/)) { // add children's counters - for (var k in this.env.unread_counts) + for (var k in this.env.unread_counts) if (k.indexOf(mbox + this.env.delimiter) == 0) childcount += this.env.unread_counts[k]; } @@ -5421,16 +5632,12 @@ function rcube_webmail() this.toggle_prefer_html = function(checkbox) { - var elem; - if (elem = document.getElementById('rcmfd_addrbook_show_images')) - elem.disabled = !checkbox.checked; + $('#rcmfd_show_images').prop('disabled', !checkbox.checked).val(0); }; this.toggle_preview_pane = function(checkbox) { - var elem; - if (elem = document.getElementById('rcmfd_preview_pane_mark_read')) - elem.disabled = !checkbox.checked; + $('#rcmfd_preview_pane_mark_read').prop('disabled', !checkbox.checked); }; // display fetched raw headers @@ -5546,14 +5753,17 @@ function rcube_webmail() $.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); $(document.getElementById(id)).val(data); rcmail.log(data); } + success: function(data) { rcmail.set_busy(false, null, lock); $('#'+id).val(data); rcmail.log(data); } }); }; - this.plain2html = function(plainText, id) + this.plain2html = function(plain, id) { var lock = this.set_busy(true, 'converting'); - $(document.getElementById(id)).val('<pre>'+plainText+'</pre>'); + + plain = plain.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + $('#'+id).val(plain ? '<pre>'+plain+'</pre>' : ''); + this.set_busy(false, null, lock); }; @@ -5580,7 +5790,7 @@ function rcube_webmail() var base = this.env.comm_path; // overwrite task name - if (query._action.match(/([a-z]+)\/([a-z-_.]+)/)) { + if (query._action.match(/([a-z]+)\/([a-z0-9-_.]+)/)) { query._action = RegExp.$2; base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1); } @@ -5794,6 +6004,8 @@ function rcube_webmail() 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 }); } @@ -6008,6 +6220,23 @@ rcube_webmail.long_subject_title = function(elem, indent) } }; +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; + } +}; + // copy event engine prototype rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener; rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener; diff --git a/program/js/common.js b/program/js/common.js index a9b6f53..7d1f173 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -1,25 +1,28 @@ var CONTROL_KEY=1,SHIFT_KEY=2,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?!0:!1;this.dom2=document.addEventListener&&document.removeEventListener;this.ie4=(this.ie=document.all&&!window.opera)&&!this.dom;this.ie5=this.dom&&this.appver.indexOf("MSIE 5")>0;this.ie8=this.dom&&this.appver.indexOf("MSIE 8")>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.mz=this.dom&&!this.ie&&!this.ns&&!this.chrome&&!this.safari&&this.agent.indexOf("Mozilla")>=0;this.konq=this.agent_lc.indexOf("konqueror")>0;this.iphone=this.safari&&this.agent_lc.indexOf("iphone")>0;this.ipad= -this.safari&&this.agent_lc.indexOf("ipad")>0;if((this.opera=window.opera?!0:!1)&&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.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 a=new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}");return this.xmlhttp=window.XMLHttpRequest||window.ActiveXObject&&a()};this.set_html_class=function(){var a=" js";this.ie?(a+=" ie",this.ie5?a+=" ie5":this.ie6?a+= +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=(""+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=0<=this.platform.indexOf("win");this.mac=0<=this.platform.indexOf("mac");this.linux=0<=this.platform.indexOf("linux");this.unix=0<=this.platform.indexOf("unix");this.dom=document.getElementById?!0:!1;this.dom2=document.addEventListener&&document.removeEventListener;this.ie4=(this.ie=document.all&&!window.opera)&&!this.dom;this.ie5=this.dom&&0<this.appver.indexOf("MSIE 5");this.ie8=this.dom&&0<this.appver.indexOf("MSIE 8");this.ie7=this.dom&&0<this.appver.indexOf("MSIE 7");this.ie6=this.dom&& +!this.ie8&&!this.ie7&&0<this.appver.indexOf("MSIE 6");this.ns=5>this.ver&&"Netscape"==this.name||5<=this.ver&&0<=this.vendor.indexOf("Netscape");this.chrome=0<this.agent_lc.indexOf("chrome");this.safari=!this.chrome&&(0<this.agent_lc.indexOf("safari")||0<this.agent_lc.indexOf("applewebkit"));this.mz=this.dom&&!this.ie&&!this.ns&&!this.chrome&&!this.safari&&0<=this.agent.indexOf("Mozilla");this.konq=0<this.agent_lc.indexOf("konqueror");this.iphone=this.safari&&0<this.agent_lc.indexOf("iphone");this.ipad= +this.safari&&0<this.agent_lc.indexOf("ipad");if((this.opera=window.opera?!0:!1)&&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||0<this.agent.indexOf("Camino"))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.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&&6<=this.vendver||this.ie&& +this.mac&&5<=this.vendver||this.ie&&this.win&&5.5<=this.vendver||this.safari;this.opacity=this.mz||this.ie&&5.5<=this.vendver&&!this.opera||this.safari&&100<=this.vendver;this.cookies=a.cookieEnabled;this.xmlhttp_test=function(){var a=new Function("try{var o=new ActiveXObject('Microsoft.XMLHTTP');return true;}catch(err){return false;}");return this.xmlhttp=window.XMLHttpRequest||window.ActiveXObject&&a()};this.set_html_class=function(){var a=" js";this.ie?(a+=" ie",this.ie5?a+=" ie5":this.ie6?a+= " ie6":this.ie7?a+=" ie7":this.ie8&&(a+=" ie8")):this.opera?a+=" opera":this.konq?a+=" konqueror":this.safari&&(a+=" safari");this.chrome?a+=" chrome":this.iphone?a+=" iphone":this.ipad&&(a+=" ipad");document.documentElement&&(document.documentElement.className+=a)}} -var rcube_event={get_target:function(a){return(a=a||window.event)&&a.target?a.target:a.srcElement},get_keycode:function(a){return(a=a||window.event)&&a.keyCode?a.keyCode:a&&a.which?a.which:0},get_button:function(a){return(a=a||window.event)&&a.button!==void 0?a.button:a&&a.which?a.which:0},get_modifier:function(a){var b=0,a=a||window.event;if(bw.mac&&a)return b+=(a.metaKey&&CONTROL_KEY)+(a.shiftKey&&SHIFT_KEY),b;if(a)return b+=(a.ctrlKey&&CONTROL_KEY)+(a.shiftKey&&SHIFT_KEY),b},get_mouse_pos:function(a){if(!a)a= -window.event;var b=a.pageX?a.pageX:a.clientX,c=a.pageY?a.pageY:a.clientY;document.body&&document.all&&(b+=document.body.scrollLeft,c+=document.body.scrollTop);a._offset&&(b+=a._offset.left,c+=a._offset.top);return{x:b,y:c}},add_listener:function(a){if(a.object&&a.method){if(!a.element)a.element=document;if(!a.object._rc_events)a.object._rc_events=[];var b=a.event+"*"+a.method;a.object._rc_events[b]||(a.object._rc_events[b]=function(c){return a.object[a.method](c)});a.element.addEventListener?a.element.addEventListener(a.event, +var rcube_event={get_target:function(a){return(a=a||window.event)&&a.target?a.target:a.srcElement},get_keycode:function(a){return(a=a||window.event)&&a.keyCode?a.keyCode:a&&a.which?a.which:0},get_button:function(a){return(a=a||window.event)&&void 0!==a.button?a.button:a&&a.which?a.which:0},get_modifier:function(a){var b=0,a=a||window.event;bw.mac&&a?b+=(a.metaKey&&CONTROL_KEY)+(a.shiftKey&&SHIFT_KEY):a&&(b+=(a.ctrlKey&&CONTROL_KEY)+(a.shiftKey&&SHIFT_KEY));return b},get_mouse_pos:function(a){if(!a)a= +window.event;var b=a.pageX?a.pageX:a.clientX,c=a.pageY?a.pageY:a.clientY;document.body&&document.all&&(b+=document.body.scrollLeft,c+=document.body.scrollTop);a._offset&&(b+=a._offset.left,c+=a._offset.top);return{x:b,y:c}},add_listener:function(a){if(a.object&&a.method){if(!a.element)a.element=document;if(!a.object._rc_events)a.object._rc_events=[];var b=a.event+"*"+a.method;a.object._rc_events[b]||(a.object._rc_events[b]=function(b){return a.object[a.method](b)});a.element.addEventListener?a.element.addEventListener(a.event, a.object._rc_events[b],!1):a.element.attachEvent?(a.element.detachEvent("on"+a.event,a.object._rc_events[b]),a.element.attachEvent("on"+a.event,a.object._rc_events[b])):a.element["on"+a.event]=a.object._rc_events[b]}},remove_listener:function(a){if(!a.element)a.element=document;var b=a.event+"*"+a.method;a.object&&a.object._rc_events&&a.object._rc_events[b]&&(a.element.removeEventListener?a.element.removeEventListener(a.event,a.object._rc_events[b],!1):a.element.detachEvent?a.element.detachEvent("on"+ a.event,a.object._rc_events[b]):a.element["on"+a.event]=null)},cancel:function(a){a=a?a:window.event;a.preventDefault&&a.preventDefault();a.stopPropagation&&a.stopPropagation();a.cancelBubble=!0;return a.returnValue=!1},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:!0}}};function rcube_event_engine(){this._events={}} -rcube_event_engine.prototype={addEventListener:function(a,b,c){if(!this._events)this._events={};this._events[a]||(this._events[a]=[]);this._events[a][this._events[a].length]={func:b,obj:c?c:window}},removeEventListener:function(a,b,c){c===void 0&&(c=window);for(var d,e=0;this._events&&this._events[a]&&e<this._events[a].length;e++)if((d=this._events[a][e])&&d.func==b&&d.obj==c)this._events[a][e]=null},triggerEvent:function(a,b){var c,d;if(b===void 0)b=this;else if(typeof b==="object")b.event=a;if(this._events&& -this._events[a]&&!this._event_exec){this._event_exec=!0;for(var e=0;e<this._events[a].length;e++)if(d=this._events[a][e])if(typeof d.func==="function"?c=d.func.call?d.func.call(d.obj,b):d.func(b):typeof d.obj[d.func]==="function"&&(c=d.obj[d.func](b)),c!==void 0&&!c)break;if(c&&c.event)try{delete c.event}catch(g){$(c).removeAttr("event")}}this._event_exec=!1;if(b.event)try{delete b.event}catch(h){$(b).removeAttr("event")}return c}}; -function rcube_layer(a,b){this.name=a;this.create=function(a){var b=a.x?a.x:0,e=a.y?a.y:0,g=a.width,h=a.height,i=a.zindex,j=a.vis,a=a.parent,f=document.createElement("DIV");f.id=this.name;f.style.position="absolute";f.style.visibility=j?j==2?"inherit":"visible":"hidden";f.style.left=b+"px";f.style.top=e+"px";if(g)f.style.width=g.toString().match(/\%$/)?g:g+"px";if(h)f.style.height=h.toString().match(/\%$/)?h:h+"px";if(i)f.style.zIndex=i;a?a.appendChild(f):document.body.appendChild(f);this.elm=f}; -b!=null?(this.create(b),this.name=this.elm.id):this.elm=document.getElementById(a);if(!this.elm)return!1;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"?!0:!1;this.move=function(a,b){this.x=a;this.y=b;this.css.left=Math.round(this.x)+"px";this.css.top=Math.round(this.y)+ -"px"};this.resize=function(a,b){this.css.width=a+"px";this.css.height=b+"px";this.width=a;this.height=b};this.show=function(a){a==1?(this.css.visibility="visible",this.visible=!0):a==2?(this.css.visibility="inherit",this.visible=!0):(this.css.visibility="hidden",this.visible=!1)};this.write=function(a){this.elm.innerHTML=a}} +rcube_event_engine.prototype={addEventListener:function(a,b,c){if(!this._events)this._events={};this._events[a]||(this._events[a]=[]);this._events[a][this._events[a].length]={func:b,obj:c?c:window}},removeEventListener:function(a,b,c){void 0===c&&(c=window);for(var d,e=0;this._events&&this._events[a]&&e<this._events[a].length;e++)if((d=this._events[a][e])&&d.func==b&&d.obj==c)this._events[a][e]=null},triggerEvent:function(a,b){var c,d;if(void 0===b)b=this;else if("object"===typeof b)b.event=a;if(this._events&& +this._events[a]&&!this._event_exec){this._event_exec=!0;for(var e=0;e<this._events[a].length;e++)if(d=this._events[a][e])if("function"===typeof d.func?c=d.func.call?d.func.call(d.obj,b):d.func(b):"function"===typeof d.obj[d.func]&&(c=d.obj[d.func](b)),void 0!==c&&!c)break;if(c&&c.event)try{delete c.event}catch(f){$(c).removeAttr("event")}}this._event_exec=!1;if(b.event)try{delete b.event}catch(h){$(b).removeAttr("event")}return c}}; +function rcube_layer(a,b){this.name=a;this.create=function(a){var b=a.x?a.x:0,e=a.y?a.y:0,f=a.width,h=a.height,i=a.zindex,g=a.vis,a=a.parent,j=document.createElement("DIV");j.id=this.name;j.style.position="absolute";j.style.visibility=g?2==g?"inherit":"visible":"hidden";j.style.left=b+"px";j.style.top=e+"px";if(f)j.style.width=f.toString().match(/\%$/)?f:f+"px";if(h)j.style.height=h.toString().match(/\%$/)?h:h+"px";if(i)j.style.zIndex=i;a?a.appendChild(j):document.body.appendChild(j);this.elm=j}; +null!=b?(this.create(b),this.name=this.elm.id):this.elm=document.getElementById(a);if(!this.elm)return!1;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="visible"==this.css.visibility||"show"==this.css.visibility||"inherit"==this.css.visibility?!0:!1;this.move=function(a,b){this.x=a;this.y=b;this.css.left=Math.round(this.x)+"px";this.css.top=Math.round(this.y)+ +"px"};this.resize=function(a,b){this.css.width=a+"px";this.css.height=b+"px";this.width=a;this.height=b};this.show=function(a){1==a?(this.css.visibility="visible",this.visible=!0):2==a?(this.css.visibility="inherit",this.visible=!0):(this.css.visibility="hidden",this.visible=!1)};this.write=function(a){this.elm.innerHTML=a}} function rcube_check_email(a,b){return a&&window.RegExp?(b?RegExp("(^|<|[,;s\n])((([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))|(mailtest\\x40(\\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)))($|>|[,;s\n])","i"): RegExp("^((([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))|(mailtest\\x40(\\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)))$", -"i")).test(a)?!0:!1:!1}function rcube_clone_object(a){var b={},c;for(c in a)b[c]=a[c]&&typeof a[c]==="object"?clone_object(a[c]):a[c];return b}function urlencode(a){return window.encodeURIComponent?encodeURIComponent(a):escape(a)} +"i")).test(a)?!0:!1:!1}function rcube_clone_object(a){var b={},c;for(c in a)b[c]=a[c]&&"object"===typeof a[c]?clone_object(a[c]):a[c];return b}function urlencode(a){return window.encodeURIComponent?encodeURIComponent(a).replace("*","%2A"):escape(a).replace("+","%2B").replace("*","%2A").replace("/","%2F").replace("@","%40")} function rcube_find_object(a,b){var c,d;b||(b=document);if(b.getElementsByName&&(c=b.getElementsByName(a)))d=c[0];!d&&b.getElementById&&(d=b.getElementById(a));!d&&b.all&&(d=b.all[a]);!d&&b.images.length&&(d=b.images[a]);if(!d&&b.forms.length)for(c=0;c<b.forms.length;c++)b.forms[c].name==a?d=b.forms[c]:b.forms[c].elements[a]&&(d=b.forms[c].elements[a]);if(!d&&b.layers){b.layers[a]&&(d=b.layers[a]);for(c=0;!d&&c<b.layers.length;c++)d=rcube_find_object(a,b.layers[c].document)}return d} -function rcube_mouse_is_over(a,b){var c=rcube_event.get_mouse_pos(a),d=$(b).offset();return c.x>=d.left&&c.x<d.left+b.offsetWidth&&c.y>=d.top&&c.y<d.top+b.offsetHeight}function setCookie(a,b,c,d,e,g){a=a+"="+escape(b)+(c?"; expires="+c.toGMTString():"")+(d?"; path="+d:"")+(e?"; domain="+e:"")+(g?"; secure":"");document.cookie=a} -function getCookie(a){var b=document.cookie;a+="=";var c=b.indexOf("; "+a);if(c==-1){if(c=b.indexOf(a),c!=0)return null}else c+=2;var d=b.indexOf(";",c);if(d==-1)d=b.length;return unescape(b.substring(c+a.length,d))}roundcube_browser.prototype.set_cookie=setCookie;roundcube_browser.prototype.get_cookie=getCookie; -function rcube_console(){this.log=function(a){var b=rcube_find_object("dbgconsole");if(b)a+=a.charAt(a.length-1)=="\n"?"--------------------------------------\n":"\n--------------------------------------\n",bw.konq?(b.innerText+=a,b.value=b.innerText):b.value+=a};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")}; -if(bw.ie)document._getElementById=document.getElementById,document.getElementById=function(a){var b=0,c=document._getElementById(a);if(c&&c.id!=a)for(;(c=document.all[b])&&c.id!=a;)b++;return c}; +function rcube_mouse_is_over(a,b){var c=rcube_event.get_mouse_pos(a),d=$(b).offset();return c.x>=d.left&&c.x<d.left+b.offsetWidth&&c.y>=d.top&&c.y<d.top+b.offsetHeight}function setCookie(a,b,c,d,e,f){a=a+"="+escape(b)+(c?"; expires="+c.toGMTString():"")+(d?"; path="+d:"")+(e?"; domain="+e:"")+(f?"; secure":"");document.cookie=a} +function getCookie(a){var b=document.cookie,a=a+"=",c=b.indexOf("; "+a);if(-1==c){if(c=b.indexOf(a),0!=c)return null}else c+=2;var d=b.indexOf(";",c);if(-1==d)d=b.length;return unescape(b.substring(c+a.length,d))}roundcube_browser.prototype.set_cookie=setCookie;roundcube_browser.prototype.get_cookie=getCookie; +function rcube_console(){this.log=function(a){var b=rcube_find_object("dbgconsole");if(b)a="\n"==a.charAt(a.length-1)?a+"--------------------------------------\n":a+"\n--------------------------------------\n",bw.konq?(b.innerText+=a,b.value=b.innerText):b.value+=a};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(""+a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}; +Date.prototype.getStdTimezoneOffset=function(){for(var a=12,b=new Date(null,a,1),c=b.getTimezoneOffset();--a;)if(b.setUTCMonth(a),c!=b.getTimezoneOffset())return Math.max(c,b.getTimezoneOffset());return c};if(bw.ie)document._getElementById=document.getElementById,document.getElementById=function(a){var b=0,c=document._getElementById(a);if(c&&c.id!=a)for(;(c=document.all[b])&&c.id!=a;)b++;return c}; +var Base64=function(){return{encode:function(a){if("function"===typeof window.btoa)return btoa(a);var b,c,d,e,f,h,i=0,g="",j=a.length;do b=a.charCodeAt(i++),c=a.charCodeAt(i++),d=a.charCodeAt(i++),e=b>>2,b=(b&3)<<4|c>>4,f=(c&15)<<2|d>>6,h=d&63,isNaN(c)?f=h=64:isNaN(d)&&(h=64),g=g+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(e)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(i<j);return g},decode:function(a){if("function"===typeof window.atob)return atob(a);var b,c,d,e,f,h,i=0,g="",a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");h=a.length;do b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(i++)),c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(i++)),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(i++)), +f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a.charAt(i++)),b=b<<2|c>>4,c=(c&15)<<4|e>>2,d=(e&3)<<6|f,g+=String.fromCharCode(b),64!=e&&(g+=String.fromCharCode(c)),64!=f&&(g+=String.fromCharCode(d));while(i<h);return g}}}(); diff --git a/program/js/common.js.src b/program/js/common.js.src index 4a9b9aa..d2558ce 100644 --- a/program/js/common.js.src +++ b/program/js/common.js.src @@ -10,7 +10,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: common.js 5281 2011-09-27 07:29:49Z alec $ + $Id: common.js 5481 2011-11-24 07:53:00Z alec $ */ // Constants @@ -171,14 +171,12 @@ get_modifier: function(e) var opcode = 0; e = e || window.event; - if (bw.mac && e) { + if (bw.mac && e) opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY); - return opcode; - } - if (e) { + else if (e) opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY); - return opcode; - } + + return opcode; }, /** @@ -544,10 +542,17 @@ function rcube_clone_object(obj) return out; }; -// make a string URL safe +// make a string URL safe (and compatible with PHP's rawurlencode()) function urlencode(str) { - return window.encodeURIComponent ? encodeURIComponent(str) : escape(str); + if (window.encodeURIComponent) + return encodeURIComponent(str).replace('*', '%2A'); + + return escape(str) + .replace('+', '%2B') + .replace('*', '%2A') + .replace('/', '%2F') + .replace('@', '%40'); }; @@ -673,6 +678,23 @@ 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) @@ -689,3 +711,82 @@ if (bw.ie) return obj; } } + +// 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; +})(); diff --git a/program/js/editor.js b/program/js/editor.js index a3aef72..63186fb 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -14,15 +14,15 @@ */ // Initialize HTML editor -function rcmail_editor_init(skin_path, editor_lang, spellcheck, mode) +function rcmail_editor_init(config) { var ret, conf = { mode: 'textareas', editor_selector: 'mce_editor', apply_source_formatting: true, theme: 'advanced', - language: editor_lang, - content_css: skin_path + '/editor_content.css', + language: config.lang, + content_css: config.skin_path + '/editor_content.css', theme_advanced_toolbar_location: 'top', theme_advanced_toolbar_align: 'left', theme_advanced_buttons3: '', @@ -35,7 +35,7 @@ function rcmail_editor_init(skin_path, editor_lang, spellcheck, mode) rc_client: rcmail }; - if (mode == 'identity') + if (config.mode == 'identity') $.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', @@ -43,11 +43,12 @@ function rcmail_editor_init(skin_path, editor_lang, spellcheck, mode) }); else // mail compose $.extend(conf, { - plugins: 'paste,emotions,media,nonbreaking,table,searchreplace,visualchars,directionality,tabfocus' + (spellcheck ? ',spellchecker' : ''), + plugins: 'paste,emotions,media,nonbreaking,table,searchreplace,visualchars,directionality,tabfocus' + (config.spellcheck ? ',spellchecker' : ''), theme_advanced_buttons1: 'bold,italic,underline,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,outdent,indent,ltr,rtl,blockquote,|,forecolor,backcolor,fontselect,fontsizeselect', - theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search' + (spellcheck ? ',spellchecker' : '') + ',undo,redo', + theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search' + (config.spellcheck ? ',spellchecker' : '') + ',undo,redo', spellchecker_languages: (rcmail.env.spellcheck_langs ? rcmail.env.spellcheck_langs : 'Dansk=da,Deutsch=de,+English=en,Espanol=es,Francais=fr,Italiano=it,Nederlands=nl,Polski=pl,Portugues=pt,Suomi=fi,Svenska=sv'), spellchecker_rpc_url: '?_task=utils&_action=spell_html', + spellchecker_enable_learn_rpc: config.spelldict, accessibility_focus: false, oninit: 'rcmail_editor_callback' }); @@ -114,13 +115,17 @@ function rcmail_toggle_editor(select, textAreaId, flagElement) if (flagElement && (flag = rcube_find_object(flagElement))) flag.value = '1'; } - else { - if (!res && select.tagName == 'SELECT') - select.value = 'html'; + else if (res) { if (flagElement && (flag = rcube_find_object(flagElement))) flag.value = '0'; if (rcmail.env.composebody) rcube_find_object(rcmail.env.composebody).focus(); } + else { // !res + if (select.tagName == 'SELECT') + select.value = 'html'; + else if (select.tagName == 'INPUT') + select.checked = true; + } } diff --git a/program/js/googiespell.js b/program/js/googiespell.js index 411740f..3618fe1 100644 --- a/program/js/googiespell.js +++ b/program/js/googiespell.js @@ -1,38 +1,39 @@ var GOOGIE_CUR_LANG,GOOGIE_DEFAULT_LANG="en"; -function GoogieSpell(s,t){var l=this,r=getCookie("language");GOOGIE_CUR_LANG=r!=null?r:GOOGIE_DEFAULT_LANG;this.array_keys=function(a){var b=[],c;for(c in a)b.push([c]);return b};this.img_dir=s;this.server_url=t;this.lang_to_word=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",fi:"Suomi",sv:"Svenska"};this.langlist_codes=this.array_keys(this.lang_to_word);this.show_change_lang_pic=!0;this.change_lang_pic_placement= -"right";this.report_state_change=!0;this.el_scroll_top=this.ta_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.show_spell_img=!1;this.decoration=!0;this.use_close_btn=!1;this.report_ta_not_found=this.edit_layer_dbl_click=!0;this.custom_no_spelling_error=this.custom_ajax_error=null;this.custom_menu_builder=[];this.custom_item_evaulator= -null;this.extra_menu_items=[];this.custom_spellcheck_starter=null;this.main_controller=!0;this.all_errors_fixed_observer=this.show_menu_observer=this.spelling_state_observer=this.lang_state_observer=null;this.use_focus=!1;this.focus_link_b=this.focus_link_t=null;this.cnt_errors_fixed=this.cnt_errors=0;$(document).bind("click",function(a){a=$(a.target);a.attr("googie_action_btn")!="1"&&l.isLangWindowShown()&&l.hideLangWindow();a.attr("googie_action_btn")!="1"&&l.isErrorWindowShown()&&l.hideErrorWindow()}); -this.decorateTextarea=function(a){if(this.text_area=typeof a==="string"?document.getElementById(a):a){if(!this.spell_container&&this.decoration){var a=document.createElement("table"),b=document.createElement("tbody"),c=document.createElement("tr"),d=document.createElement("td"),e=this.isDefined(this.force_width)?this.force_width:this.text_area.offsetWidth,f=this.isDefined(this.force_height)?this.force_height:16;c.appendChild(d);b.appendChild(c);$(a).append(b).insertBefore(this.text_area).width("100%").height(f); -$(d).height(f).width(e).css("text-align","right");this.spell_container=d}this.checkSpellingState()}else this.report_ta_not_found&&alert("Text area not found")};this.setSpellContainer=function(a){this.spell_container=typeof a==="string"?document.getElementById(a):a};this.setLanguages=function(a){this.lang_to_word=a;this.langlist_codes=this.array_keys(a)};this.setCurrentLanguage=function(a){GOOGIE_CUR_LANG=a;var b=new Date;b.setTime(b.getTime()+31536E6);setCookie("language",a,b)};this.setForceWidthHeight= -function(a,b){this.force_width=a;this.force_height=b};this.setDecoration=function(a){this.decoration=a};this.dontUseCloseButtons=function(){this.use_close_btn=!1};this.appendNewMenuItem=function(a,b,c){this.extra_menu_items.push([a,b,c])};this.appendCustomMenuBuilder=function(a,b){this.custom_menu_builder.push([a,b])};this.setFocus=function(){try{return this.focus_link_b.focus(),this.focus_link_t.focus(),!0}catch(a){return!1}};this.setStateChanged=function(a){this.state=a;this.spelling_state_observer!= -null&&this.report_state_change&&this.spelling_state_observer(a,this)};this.setReportStateChange=function(a){this.report_state_change=a};this.getUrl=function(){return this.server_url+GOOGIE_CUR_LANG};this.escapeSpecial=function(a){return a?a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"):""};this.createXMLReq=function(a){return'<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>'+a+"</text></spellrequest>"}; -this.spellCheck=function(a){this.prepare(a);var a=this.escapeSpecial(this.orginal_text),b=this;$.ajax({type:"POST",url:this.getUrl(),data:this.createXMLReq(a),dataType:"text",error:function(){b.custom_ajax_error?b.custom_ajax_error(b):alert("An error was encountered on the server. Please try again later.");b.main_controller&&($(b.spell_span).remove(),b.removeIndicator());b.checkSpellingState()},success:function(a){b.processData(a);b.results.length||(b.custom_no_spelling_error?b.custom_no_spelling_error(b): -b.flashNoSpellingErrorState());b.removeIndicator()}})};this.prepare=function(a,b){this.cnt_errors=this.cnt_errors_fixed=0;this.setStateChanged("checking_spell");!b&&this.main_controller&&this.appendIndicator(this.spell_span);this.error_links=[];this.ta_scroll_top=this.text_area.scrollTop;this.ignore=a;this.hideLangWindow();if($(this.text_area).val()==""||a)this.custom_no_spelling_error?this.custom_no_spelling_error(this):this.flashNoSpellingErrorState(),this.removeIndicator();else{this.createEditLayer(this.text_area.offsetWidth, -this.text_area.offsetHeight);this.createErrorWindow();$("body").append(this.error_window);try{netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead")}catch(c){}this.main_controller&&$(this.spell_span).unbind("click");this.orginal_text=$(this.text_area).val()}};this.parseResult=function(a){var b=/\w+="(\d+|true)"/g,c=/\t/g,a=a.match(/<c[^>]*>[^<]*<\/c>/g),d=[];if(a==null)return d;for(var e=0,f=a.length;e<f;e++){var j=[];this.errorFound();j.attrs=[];for(var g,h,l=a[e].match(b),k= -0;k<l.length;k++)g=l[k].split(/=/),h=g[1].replace(/"/g,""),j.attrs[g[0]]=h!="true"?parseInt(h):h;j.suggestions=[];g=a[e].replace(/<[^>]*>/g,"").split(c);for(h=0;h<g.length;h++)g[h]!=""&&j.suggestions.push(g[h]);d.push(j)}return d};this.processData=function(a){this.results=this.parseResult(a);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(a,b,c,d){var e=this.orginal_text.substring(0,a),a=this.orginal_text.substring(a+b.length),b=c.length-b.length;this.orginal_text=e+c+a;$(this.text_area).val(this.orginal_text);c=0;for(e=this.results.length;c<e;c++)c!=d&&c>d&&(this.results[c].attrs.o+=b)};this.saveOldValue=function(a,b){a.is_changed= -!0;a.old_value=b};this.createListSeparator=function(){var a=document.createElement("td"),b=document.createElement("tr");$(a).html(" ").attr("googie_action_btn","1").css({cursor:"default","font-size":"3px","border-top":"1px solid #ccc","padding-top":"3px"});b.appendChild(a);return b};this.correctError=function(a,b,c,d){var e=b.innerHTML,c=c.nodeType==3?c.nodeValue:c.innerHTML,f=this.results[a].attrs.o;if(d)d=b.previousSibling.innerHTML,b.previousSibling.innerHTML=d.slice(0,d.length-1),e=" "+e,f--; -this.hideErrorWindow();this.updateOrginalText(f,e,c,a);$(b).html(c).css("color","green").attr("is_corrected",!0);this.results[a].attrs.l=c.length;this.isDefined(b.old_value)||this.saveOldValue(b,e);this.errorFixed()};this.showErrorWindow=function(a,b){this.show_menu_observer&&this.show_menu_observer(this);var c=this,d=$(a).offset(),e=document.createElement("table"),f=document.createElement("tbody");$(this.error_window).html("");$(e).addClass("googie_list").attr("googie_action_btn","1");for(var j= -!1,g=0;g<this.custom_menu_builder.length;g++){var h=this.custom_menu_builder[g];if(h[0](this.results[b])){j=h[1](this,f,a);break}}if(!j){var j=this.results[b].suggestions,l=this.results[b].attrs.o,g=this.results[b].attrs.l,k,m;j.length==0&&(h=document.createElement("tr"),k=document.createElement("td"),m=document.createElement("span"),$(m).text(this.lang_no_suggestions),$(k).attr("googie_action_btn","1").css("cursor","default"),k.appendChild(m),h.appendChild(k),f.appendChild(h));for(var o=0,g=j.length;o< -g;o++)h=document.createElement("tr"),k=document.createElement("td"),m=document.createElement("span"),$(m).html(j[o]),$(k).bind("mouseover",this.item_onmouseover).bind("mouseout",this.item_onmouseout).bind("click",function(d){c.correctError(b,a,d.target.firstChild)}),k.appendChild(m),h.appendChild(k),f.appendChild(h);if(a.is_changed&&a.innerHTML!=a.old_value){var p=a.old_value,j=document.createElement("tr"),g=document.createElement("td"),h=document.createElement("span");$(h).addClass("googie_list_revert").html(this.lang_revert+ -" "+p);$(g).bind("mouseover",this.item_onmouseover).bind("mouseout",this.item_onmouseout).bind("click",function(){c.updateOrginalText(l,a.innerHTML,p,b);$(a).attr("is_corrected",!0).css("color","#b91414").html(p);c.hideErrorWindow()});g.appendChild(h);j.appendChild(g);f.appendChild(j)}var j=document.createElement("tr"),g=document.createElement("td"),n=document.createElement("input"),h=document.createElement("img");k=document.createElement("form");m=function(){n.value!=""&&(c.isDefined(a.old_value)|| -c.saveOldValue(a,a.innerHTML),c.updateOrginalText(l,a.innerHTML,n.value,b),$(a).attr("is_corrected",!0).css("color","green").html(n.value),c.hideErrorWindow());return!1};$(n).width(120).css({margin:0,padding:0});$(n).val(a.innerHTML).attr("googie_action_btn","1");$(g).css("cursor","default").attr("googie_action_btn","1");$(h).attr("src",this.img_dir+"ok.gif").width(32).height(16).css({cursor:"pointer","margin-left":"2px","margin-right":"2px"}).bind("click",m);$(k).attr("googie_action_btn","1").css({margin:0, -padding:0,cursor:"default","white-space":"nowrap"}).bind("submit",m);k.appendChild(n);k.appendChild(h);g.appendChild(k);j.appendChild(g);f.appendChild(j);this.extra_menu_items.length>0&&f.appendChild(this.createListSeparator());var q=function(b){if(b<c.extra_menu_items.length){var d=c.extra_menu_items[b];if(!d[2]||d[2](a,c)){var e=document.createElement("tr"),g=document.createElement("td");$(g).html(d[0]).bind("mouseover",c.item_onmouseover).bind("mouseout",c.item_onmouseout).bind("click",function(){return d[1](a, +function GoogieSpell(s,t,u){var l=this,r=getCookie("language");GOOGIE_CUR_LANG=null!=r?r:GOOGIE_DEFAULT_LANG;this.array_keys=function(a){var b=[],c;for(c in a)b.push([c]);return b};this.img_dir=s;this.server_url=t;this.lang_to_word=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",fi:"Suomi",sv:"Svenska"};this.langlist_codes=this.array_keys(this.lang_to_word);this.show_change_lang_pic=!0;this.change_lang_pic_placement= +"right";this.report_state_change=!0;this.el_scroll_top=this.ta_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=!1;this.decoration=!0;this.use_close_btn=!1;this.report_ta_not_found=this.edit_layer_dbl_click=!0;this.custom_no_spelling_error=this.custom_ajax_error= +null;this.custom_menu_builder=[];this.custom_item_evaulator=null;this.extra_menu_items=[];this.custom_spellcheck_starter=null;this.main_controller=!0;this.has_dictionary=u;this.all_errors_fixed_observer=this.show_menu_observer=this.spelling_state_observer=this.lang_state_observer=null;this.use_focus=!1;this.focus_link_b=this.focus_link_t=null;this.cnt_errors_fixed=this.cnt_errors=0;$(document).bind("click",function(a){a=$(a.target);"1"!=a.attr("googie_action_btn")&&l.isLangWindowShown()&&l.hideLangWindow(); +"1"!=a.attr("googie_action_btn")&&l.isErrorWindowShown()&&l.hideErrorWindow()});this.decorateTextarea=function(a){if(this.text_area="string"===typeof a?document.getElementById(a):a){if(!this.spell_container&&this.decoration){var a=document.createElement("table"),b=document.createElement("tbody"),c=document.createElement("tr"),d=document.createElement("td"),e=this.isDefined(this.force_width)?this.force_width:this.text_area.offsetWidth,f=this.isDefined(this.force_height)?this.force_height:16;c.appendChild(d); +b.appendChild(c);$(a).append(b).insertBefore(this.text_area).width("100%").height(f);$(d).height(f).width(e).css("text-align","right");this.spell_container=d}this.checkSpellingState()}else this.report_ta_not_found&&alert("Text area not found")};this.setSpellContainer=function(a){this.spell_container="string"===typeof a?document.getElementById(a):a};this.setLanguages=function(a){this.lang_to_word=a;this.langlist_codes=this.array_keys(a)};this.setCurrentLanguage=function(a){GOOGIE_CUR_LANG=a;var b= +new Date;b.setTime(b.getTime()+31536E6);setCookie("language",a,b)};this.setForceWidthHeight=function(a,b){this.force_width=a;this.force_height=b};this.setDecoration=function(a){this.decoration=a};this.dontUseCloseButtons=function(){this.use_close_btn=!1};this.appendNewMenuItem=function(a,b,c){this.extra_menu_items.push([a,b,c])};this.appendCustomMenuBuilder=function(a,b){this.custom_menu_builder.push([a,b])};this.setFocus=function(){try{return this.focus_link_b.focus(),this.focus_link_t.focus(),!0}catch(a){return!1}}; +this.setStateChanged=function(a){this.state=a;null!=this.spelling_state_observer&&this.report_state_change&&this.spelling_state_observer(a,this)};this.setReportStateChange=function(a){this.report_state_change=a};this.getUrl=function(){return this.server_url+GOOGIE_CUR_LANG};this.escapeSpecial=function(a){return a?a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"):""};this.createXMLReq=function(a){return'<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>'+ +a+"</text></spellrequest>"};this.spellCheck=function(a){this.prepare(a);var a=this.escapeSpecial(this.orginal_text),b=this;$.ajax({type:"POST",url:this.getUrl(),data:this.createXMLReq(a),dataType:"text",error:function(){b.custom_ajax_error?b.custom_ajax_error(b):alert("An error was encountered on the server. Please try again later.");b.main_controller&&($(b.spell_span).remove(),b.removeIndicator());b.checkSpellingState()},success:function(a){b.processData(a);b.results.length||(b.custom_no_spelling_error? +b.custom_no_spelling_error(b):b.flashNoSpellingErrorState());b.removeIndicator()}})};this.learnWord=function(a){var a=this.escapeSpecial(a.innerHTML),b=this,a='<?xml version="1.0" encoding="utf-8" ?><learnword><text>'+a+"</text></learnword>";$.ajax({type:"POST",url:this.getUrl(),data:a,dataType:"text",error:function(){b.custom_ajax_error?b.custom_ajax_error(b):alert("An error was encountered on the server. Please try again later.")},success:function(){}})};this.prepare=function(a,b){this.cnt_errors= +this.cnt_errors_fixed=0;this.setStateChanged("checking_spell");!b&&this.main_controller&&this.appendIndicator(this.spell_span);this.error_links=[];this.ta_scroll_top=this.text_area.scrollTop;this.ignore=a;this.hideLangWindow();if(""==$(this.text_area).val()||a)this.custom_no_spelling_error?this.custom_no_spelling_error(this):this.flashNoSpellingErrorState(),this.removeIndicator();else{this.createEditLayer(this.text_area.offsetWidth,this.text_area.offsetHeight);this.createErrorWindow();$("body").append(this.error_window); +try{netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead")}catch(c){}this.main_controller&&$(this.spell_span).unbind("click");this.orginal_text=$(this.text_area).val()}};this.parseResult=function(a){var b=/\w+="(\d+|true)"/g,c=/\t/g,a=a.match(/<c[^>]*>[^<]*<\/c>/g),d=[];if(null==a)return d;for(var e=0,f=a.length;e<f;e++){var j=[];this.errorFound();j.attrs=[];for(var g,h,l=a[e].match(b),k=0;k<l.length;k++)g=l[k].split(/=/),h=g[1].replace(/"/g,""),j.attrs[g[0]]="true"!=h?parseInt(h): +h;j.suggestions=[];g=a[e].replace(/<[^>]*>/g,"").split(c);for(h=0;h<g.length;h++)""!=g[h]&&j.suggestions.push(g[h]);d.push(j)}return d};this.processData=function(a){this.results=this.parseResult(a);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(a,b,c,d){var e=this.orginal_text.substring(0,a),a=this.orginal_text.substring(a+b.length),b=c.length-b.length;this.orginal_text=e+c+a;$(this.text_area).val(this.orginal_text);c=0;for(e=this.results.length;c<e;c++)c!=d&&c>d&&(this.results[c].attrs.o+=b)};this.saveOldValue=function(a,b){a.is_changed=!0;a.old_value=b};this.createListSeparator=function(){var a=document.createElement("td"), +b=document.createElement("tr");$(a).html(" ").attr("googie_action_btn","1").css({cursor:"default","font-size":"3px","border-top":"1px solid #ccc","padding-top":"3px"});b.appendChild(a);return b};this.correctError=function(a,b,c,d){var e=b.innerHTML,c=3==c.nodeType?c.nodeValue:c.innerHTML,f=this.results[a].attrs.o;if(d)d=b.previousSibling.innerHTML,b.previousSibling.innerHTML=d.slice(0,d.length-1),e=" "+e,f--;this.hideErrorWindow();this.updateOrginalText(f,e,c,a);$(b).html(c).css("color","green").attr("is_corrected", +!0);this.results[a].attrs.l=c.length;this.isDefined(b.old_value)||this.saveOldValue(b,e);this.errorFixed()};this.ignoreError=function(a){$(a).removeAttr("class").css("color","").unbind();this.hideErrorWindow()};this.showErrorWindow=function(a,b){this.show_menu_observer&&this.show_menu_observer(this);var c=this,d=$(a).offset(),e=document.createElement("table"),f=document.createElement("tbody");$(this.error_window).html("");$(e).addClass("googie_list").attr("googie_action_btn","1");for(var j=!1,g=0;g< +this.custom_menu_builder.length;g++){var h=this.custom_menu_builder[g];if(h[0](this.results[b])){j=h[1](this,f,a);break}}if(!j){var j=this.results[b].suggestions,l=this.results[b].attrs.o,g=this.results[b].attrs.l,k,m;this.has_dictionary&&!$(a).attr("is_corrected")&&(h=document.createElement("tr"),k=document.createElement("td"),m=document.createElement("span"),$(m).text(this.lang_learn_word),$(k).attr("googie_action_btn","1").css("cursor","default").mouseover(c.item_onmouseover).mouseout(c.item_onmouseout).click(function(){c.learnWord(a, +b);c.ignoreError(a,b)}),k.appendChild(m),h.appendChild(k),f.appendChild(h));for(var o=0,g=j.length;o<g;o++)h=document.createElement("tr"),k=document.createElement("td"),m=document.createElement("span"),$(m).html(j[o]),$(k).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout).click(function(d){c.correctError(b,a,d.target.firstChild)}),k.appendChild(m),h.appendChild(k),f.appendChild(h);if(a.is_changed&&a.innerHTML!=a.old_value){var p=a.old_value,j=document.createElement("tr"),g=document.createElement("td"), +h=document.createElement("span");$(h).addClass("googie_list_revert").html(this.lang_revert+" "+p);$(g).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout).click(function(){c.updateOrginalText(l,a.innerHTML,p,b);$(a).removeAttr("is_corrected").css("color","#b91414").html(p);c.hideErrorWindow()});g.appendChild(h);j.appendChild(g);f.appendChild(j)}var j=document.createElement("tr"),g=document.createElement("td"),n=document.createElement("input"),h=document.createElement("img");k=document.createElement("form"); +m=function(){""!=n.value&&(c.isDefined(a.old_value)||c.saveOldValue(a,a.innerHTML),c.updateOrginalText(l,a.innerHTML,n.value,b),$(a).attr("is_corrected",!0).css("color","green").html(n.value),c.hideErrorWindow());return!1};$(n).width(120).css({margin:0,padding:0});$(n).val(a.innerHTML).attr("googie_action_btn","1");$(g).css("cursor","default").attr("googie_action_btn","1");$(h).attr("src",this.img_dir+"ok.gif").width(32).height(16).css({cursor:"pointer","margin-left":"2px","margin-right":"2px"}).click(m); +$(k).attr("googie_action_btn","1").css({margin:0,padding:0,cursor:"default","white-space":"nowrap"}).submit(m);k.appendChild(n);k.appendChild(h);g.appendChild(k);j.appendChild(g);f.appendChild(j);0<this.extra_menu_items.length&&f.appendChild(this.createListSeparator());var q=function(b){if(b<c.extra_menu_items.length){var d=c.extra_menu_items[b];if(!d[2]||d[2](a,c)){var e=document.createElement("tr"),g=document.createElement("td");$(g).html(d[0]).mouseover(c.item_onmouseover).mouseout(c.item_onmouseout).click(function(){return d[1](a, c)});e.appendChild(g);f.appendChild(e)}q(b+1)}};q(0);q=null;this.use_close_btn&&f.appendChild(this.createCloseButton(this.hideErrorWindow))}e.appendChild(f);this.error_window.appendChild(e);g=$(this.error_window).height();e=$(this.error_window).width();h=$(document).height();j=$(document).width();g=d.top+g+20<h?d.top+20:d.top-g;d=d.left+e<j?d.left:d.left-e;$(this.error_window).css({top:g+"px",left:d+"px"}).show();if($.browser.msie){if(!this.error_window_iframe)d=$("<iframe>").css({position:"absolute", -"z-index":-1}),$("body").append(d),this.error_window_iframe=d;$(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(a,b){this.edit_layer=document.createElement("div");$(this.edit_layer).addClass("googie_edit_layer").attr("id","googie_edit_layer").width("auto").height(b);this.text_area.nodeName.toLowerCase()!="input"||$(this.text_area).val()== -""?$(this.edit_layer).css("overflow","auto").height(b-4):$(this.edit_layer).css("overflow","hidden");var c=this;this.edit_layer_dbl_click&&$(this.edit_layer).dblclick(function(a){if(a.target.className!="googie_link"&&!c.isErrorWindowShown()){c.resumeEditing();var b=function(){$(c.text_area).focus();b=null};window.setTimeout(b,10)}return!1})};this.resumeEditing=function(){this.setStateChanged("ready");if(this.edit_layer)this.el_scroll_top=this.edit_layer.scrollTop;this.hideErrorWindow();this.main_controller&& -$(this.spell_span).removeClass().addClass("googie_no_style");if(!this.ignore&&(this.use_focus&&($(this.focus_link_t).remove(),$(this.focus_link_b).remove()),$(this.edit_layer).remove(),$(this.text_area).show(),this.el_scroll_top!=void 0))this.text_area.scrollTop=this.el_scroll_top;this.checkSpellingState(!1)};this.createErrorLink=function(a,b){var c=document.createElement("span"),d=this,e=function(){d.showErrorWindow(c,b);e=null;return!1};$(c).html(a).addClass("googie_link").bind("click",e).attr({googie_action_btn:"1", -g_id:b,is_corrected:!1});return c};this.createPart=function(a){if(a==" ")return document.createTextNode(" ");var a=this.escapeSpecial(a),a=a.replace(/\n/g,"<br>"),a=a.replace(/ /g," "),a=a.replace(/^ /g," "),a=a.replace(/ $/g," "),b=document.createElement("span");$(b).html(a);return b};this.showErrorsInIframe=function(){var a=document.createElement("div"),b=0,c=this.results;if(c.length>0){for(var d=0,e=c.length;d<e;d++){var f=c[d].attrs.o,j=c[d].attrs.l,g=this.createPart(this.orginal_text.substring(b, +"z-index":-1}),$("body").append(d),this.error_window_iframe=d;$(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(a,b){this.edit_layer=document.createElement("div");$(this.edit_layer).addClass("googie_edit_layer").attr("id","googie_edit_layer").width("auto").height(b);"input"!=this.text_area.nodeName.toLowerCase()||""==$(this.text_area).val()? +$(this.edit_layer).css("overflow","auto").height(b-4):$(this.edit_layer).css("overflow","hidden");var c=this;this.edit_layer_dbl_click&&$(this.edit_layer).dblclick(function(a){if("googie_link"!=a.target.className&&!c.isErrorWindowShown()){c.resumeEditing();var b=function(){$(c.text_area).focus();b=null};window.setTimeout(b,10)}return!1})};this.resumeEditing=function(){this.setStateChanged("ready");if(this.edit_layer)this.el_scroll_top=this.edit_layer.scrollTop;this.hideErrorWindow();this.main_controller&& +$(this.spell_span).removeClass().addClass("googie_no_style");if(!this.ignore&&(this.use_focus&&($(this.focus_link_t).remove(),$(this.focus_link_b).remove()),$(this.edit_layer).remove(),$(this.text_area).show(),void 0!=this.el_scroll_top))this.text_area.scrollTop=this.el_scroll_top;this.checkSpellingState(!1)};this.createErrorLink=function(a,b){var c=document.createElement("span"),d=this,e=function(){d.showErrorWindow(c,b);e=null;return!1};$(c).html(a).addClass("googie_link").click(e).removeAttr("is_corrected").attr({googie_action_btn:"1", +g_id:b});return c};this.createPart=function(a){if(" "==a)return document.createTextNode(" ");var a=this.escapeSpecial(a),a=a.replace(/\n/g,"<br>"),a=a.replace(/ /g," "),a=a.replace(/^ /g," "),a=a.replace(/ $/g," "),b=document.createElement("span");$(b).html(a);return b};this.showErrorsInIframe=function(){var a=document.createElement("div"),b=0,c=this.results;if(0<c.length){for(var d=0,e=c.length;d<e;d++){var f=c[d].attrs.o,j=c[d].attrs.l,g=this.createPart(this.orginal_text.substring(b, f));a.appendChild(g);b+=f-b;f=this.createErrorLink(this.orginal_text.substr(f,j),d);this.error_links.push(f);a.appendChild(f);b+=j}b=this.createPart(this.orginal_text.substr(b,this.orginal_text.length));a.appendChild(b)}else a.innerHTML=this.orginal_text;$(a).css("text-align","left");var h=this;this.custom_item_evaulator&&$.map(this.error_links,function(a){h.custom_item_evaulator(h,a)});$(this.edit_layer).append(a);$(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 a=document.createElement("table"),b=document.createElement("tbody"),c=this,d,e,f;$(a).addClass("googie_list").width("100%");this.lang_elms= -[];for(i=0;i<this.langlist_codes.length;i++)d=document.createElement("tr"),e=document.createElement("td"),f=document.createElement("span"),$(f).text(this.lang_to_word[this.langlist_codes[i]]),this.lang_elms.push(e),$(e).attr("googieId",this.langlist_codes[i]).bind("click",function(){c.deHighlightCurSel();c.setCurrentLanguage($(this).attr("googieId"));c.lang_state_observer!=null&&c.lang_state_observer();c.highlightCurSel();c.hideLangWindow()}).bind("mouseover",function(){if(this.className!="googie_list_selected")this.className= -"googie_list_onhover"}).bind("mouseout",function(){if(this.className!="googie_list_selected")this.className="googie_list_onout"}),e.appendChild(f),d.appendChild(e),b.appendChild(d);this.use_close_btn&&b.appendChild(this.createCloseButton(function(){c.hideLangWindow.apply(c)}));this.highlightCurSel();a.appendChild(b);this.language_window.appendChild(a)};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(a){this.show_menu_observer&&this.show_menu_observer(this);this.createLangWindow();$("body").append(this.language_window);var b=$(a).offset(),c=$(a).height(),d=$(a).width(),a=$(this.language_window).height(),e=$(document).height(),d=this.change_lang_pic_placement=="right"?b.left-100+d:b.left+d,b=b.top+a<e?b.top+c:b.top-a-4;$(this.language_window).css({top:b+"px",left:d+"px"}).show();this.highlightCurSel()};this.deHighlightCurSel=function(){$(this.lang_cur_elm).removeClass().addClass("googie_list_onout")}; -this.highlightCurSel=function(){GOOGIE_CUR_LANG==null&&(GOOGIE_CUR_LANG=GOOGIE_DEFAULT_LANG);for(var a=0;a<this.lang_elms.length;a++)$(this.lang_elms[a]).attr("googieId")==GOOGIE_CUR_LANG?(this.lang_elms[a].className="googie_list_selected",this.lang_cur_elm=this.lang_elms[a]):this.lang_elms[a].className="googie_list_onout"};this.createChangeLangPic=function(){var a=$("<img>").attr({src:this.img_dir+"change_lang.gif",alt:"Change language",googie_action_btn:"1"}),b=document.createElement("span");l= -this;$(b).addClass("googie_lang_3d_on").append(a).bind("click",function(){var a=this.tagName.toLowerCase()=="img"?this.parentNode:this;$(a).hasClass("googie_lang_3d_click")?(a.className="googie_lang_3d_on",l.hideLangWindow()):(a.className="googie_lang_3d_click",l.showLangWindow(a))});return b};this.createSpellDiv=function(){var a=document.createElement("span");$(a).addClass("googie_check_spelling_link").text(this.lang_chck_spell);this.show_spell_img&&$(a).append(" ").append($("<img>").attr("src", -this.img_dir+"spellc.gif"));return a};this.flashNoSpellingErrorState=function(a){this.setStateChanged("no_error_found");var b=this;if(this.main_controller){var c;c=a?function(){a();b.checkSpellingState()}:function(){b.checkSpellingState()};var d=$("<span>").text(this.lang_no_error_found);$(this.switch_lan_pic).hide();$(this.spell_span).empty().append(d).removeClass().addClass("googie_check_spelling_ok");window.setTimeout(c,1E3)}};this.resumeEditingState=function(){this.setStateChanged("resume_editing"); -if(this.main_controller){var a=$("<span>").text(this.lang_rsm_edt),b=this;$(this.switch_lan_pic).hide();$(this.spell_span).empty().unbind().append(a).bind("click",function(){b.resumeEditing()}).removeClass().addClass("googie_resume_editing")}try{this.edit_layer.scrollTop=this.ta_scroll_top}catch(c){}};this.checkSpellingState=function(a){a&&this.setStateChanged("ready");this.switch_lan_pic=this.show_change_lang_pic?this.createChangeLangPic():document.createElement("span");var a=this.createSpellDiv(), -b=this;this.custom_spellcheck_starter?$(a).bind("click",function(){b.custom_spellcheck_starter()}):$(a).bind("click",function(){b.spellCheck()});this.main_controller&&(this.change_lang_pic_placement=="left"?$(this.spell_container).empty().append(this.switch_lan_pic).append(" ").append(a):$(this.spell_container).empty().append(a).append(" ").append(this.switch_lan_pic));this.spell_span=a};this.isDefined=function(a){return a!==void 0&&a!==null};this.errorFixed=function(){this.cnt_errors_fixed++;this.all_errors_fixed_observer&& -this.cnt_errors_fixed==this.cnt_errors&&(this.hideErrorWindow(),this.all_errors_fixed_observer())};this.errorFound=function(){this.cnt_errors++};this.createCloseButton=function(a){return this.createButton(this.lang_close,"googie_list_close",a)};this.createButton=function(a,b,c){var d=document.createElement("tr"),e=document.createElement("td"),f;b?(f=document.createElement("span"),$(f).addClass(b).html(a)):f=document.createTextNode(a);$(e).bind("click",c).bind("mouseover",this.item_onmouseover).bind("mouseout", -this.item_onmouseout);e.appendChild(f);d.appendChild(e);return d};this.removeIndicator=function(){window.rcmail&&rcmail.set_busy(!1,null,this.rc_msg_id)};this.appendIndicator=function(){if(window.rcmail)this.rc_msg_id=rcmail.set_busy(!0,"checking")};this.createFocusLink=function(a){var b=document.createElement("a");$(b).attr({href:"javascript:;",name:a});return b};this.item_onmouseover=function(){this.className!="googie_list_revert"&&this.className!="googie_list_close"?this.className="googie_list_onhover": -this.parentNode.className="googie_list_onhover"};this.item_onmouseout=function(){this.className!="googie_list_revert"&&this.className!="googie_list_close"?this.className="googie_list_onout":this.parentNode.className="googie_list_onout"}}; +[];for(i=0;i<this.langlist_codes.length;i++)d=document.createElement("tr"),e=document.createElement("td"),f=document.createElement("span"),$(f).text(this.lang_to_word[this.langlist_codes[i]]),this.lang_elms.push(e),$(e).attr("googieId",this.langlist_codes[i]).bind("click",function(){c.deHighlightCurSel();c.setCurrentLanguage($(this).attr("googieId"));null!=c.lang_state_observer&&c.lang_state_observer();c.highlightCurSel();c.hideLangWindow()}).bind("mouseover",function(){if("googie_list_selected"!= +this.className)this.className="googie_list_onhover"}).bind("mouseout",function(){if("googie_list_selected"!=this.className)this.className="googie_list_onout"}),e.appendChild(f),d.appendChild(e),b.appendChild(d);this.use_close_btn&&b.appendChild(this.createCloseButton(function(){c.hideLangWindow.apply(c)}));this.highlightCurSel();a.appendChild(b);this.language_window.appendChild(a)};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(a){this.show_menu_observer&&this.show_menu_observer(this);this.createLangWindow();$("body").append(this.language_window);var b=$(a).offset(),c=$(a).height(),d=$(a).width(),a=$(this.language_window).height(),e=$(document).height(),d="right"==this.change_lang_pic_placement?b.left-100+d:b.left+d,b=b.top+a<e?b.top+c:b.top-a-4;$(this.language_window).css({top:b+"px",left:d+"px"}).show();this.highlightCurSel()}; +this.deHighlightCurSel=function(){$(this.lang_cur_elm).removeClass().addClass("googie_list_onout")};this.highlightCurSel=function(){null==GOOGIE_CUR_LANG&&(GOOGIE_CUR_LANG=GOOGIE_DEFAULT_LANG);for(var a=0;a<this.lang_elms.length;a++)$(this.lang_elms[a]).attr("googieId")==GOOGIE_CUR_LANG?(this.lang_elms[a].className="googie_list_selected",this.lang_cur_elm=this.lang_elms[a]):this.lang_elms[a].className="googie_list_onout"};this.createChangeLangPic=function(){var a=$("<img>").attr({src:this.img_dir+ +"change_lang.gif",alt:"Change language",googie_action_btn:"1"}),b=document.createElement("span");l=this;$(b).addClass("googie_lang_3d_on").append(a).bind("click",function(){var a="img"==this.tagName.toLowerCase()?this.parentNode:this;$(a).hasClass("googie_lang_3d_click")?(a.className="googie_lang_3d_on",l.hideLangWindow()):(a.className="googie_lang_3d_click",l.showLangWindow(a))});return b};this.createSpellDiv=function(){var a=document.createElement("span");$(a).addClass("googie_check_spelling_link").text(this.lang_chck_spell); +this.show_spell_img&&$(a).append(" ").append($("<img>").attr("src",this.img_dir+"spellc.gif"));return a};this.flashNoSpellingErrorState=function(a){this.setStateChanged("no_error_found");var b=this;if(this.main_controller){var c;c=a?function(){a();b.checkSpellingState()}:function(){b.checkSpellingState()};var d=$("<span>").text(this.lang_no_error_found);$(this.switch_lan_pic).hide();$(this.spell_span).empty().append(d).removeClass().addClass("googie_check_spelling_ok");window.setTimeout(c,1E3)}}; +this.resumeEditingState=function(){this.setStateChanged("resume_editing");if(this.main_controller){var a=$("<span>").text(this.lang_rsm_edt),b=this;$(this.switch_lan_pic).hide();$(this.spell_span).empty().unbind().append(a).bind("click",function(){b.resumeEditing()}).removeClass().addClass("googie_resume_editing")}try{this.edit_layer.scrollTop=this.ta_scroll_top}catch(c){}};this.checkSpellingState=function(a){a&&this.setStateChanged("ready");this.switch_lan_pic=this.show_change_lang_pic?this.createChangeLangPic(): +document.createElement("span");var a=this.createSpellDiv(),b=this;this.custom_spellcheck_starter?$(a).bind("click",function(){b.custom_spellcheck_starter()}):$(a).bind("click",function(){b.spellCheck()});this.main_controller&&("left"==this.change_lang_pic_placement?$(this.spell_container).empty().append(this.switch_lan_pic).append(" ").append(a):$(this.spell_container).empty().append(a).append(" ").append(this.switch_lan_pic));this.spell_span=a};this.isDefined=function(a){return void 0!==a&&null!== +a};this.errorFixed=function(){this.cnt_errors_fixed++;this.all_errors_fixed_observer&&this.cnt_errors_fixed==this.cnt_errors&&(this.hideErrorWindow(),this.all_errors_fixed_observer())};this.errorFound=function(){this.cnt_errors++};this.createCloseButton=function(a){return this.createButton(this.lang_close,"googie_list_close",a)};this.createButton=function(a,b,c){var d=document.createElement("tr"),e=document.createElement("td"),f;b?(f=document.createElement("span"),$(f).addClass(b).html(a)):f=document.createTextNode(a); +$(e).bind("click",c).bind("mouseover",this.item_onmouseover).bind("mouseout",this.item_onmouseout);e.appendChild(f);d.appendChild(e);return d};this.removeIndicator=function(){window.rcmail&&rcmail.set_busy(!1,null,this.rc_msg_id)};this.appendIndicator=function(){if(window.rcmail)this.rc_msg_id=rcmail.set_busy(!0,"checking")};this.createFocusLink=function(a){var b=document.createElement("a");$(b).attr({href:"javascript:;",name:a});return b};this.item_onmouseover=function(){"googie_list_revert"!=this.className&& +"googie_list_close"!=this.className?this.className="googie_list_onhover":this.parentNode.className="googie_list_onhover"};this.item_onmouseout=function(){"googie_list_revert"!=this.className&&"googie_list_close"!=this.className?this.className="googie_list_onout":this.parentNode.className="googie_list_onout"}}; diff --git a/program/js/googiespell.js.src b/program/js/googiespell.js.src index de8890f..96d612c 100644 --- a/program/js/googiespell.js.src +++ b/program/js/googiespell.js.src @@ -1,8 +1,11 @@ /* SpellCheck jQuery'fied spell checker based on GoogieSpell 4.0 - Copyright Amir Salihefendic 2006 - Copyright Aleksander Machniak 2009 + (which was published under GPL "version 2 or any later version") + + Copyright (C) 2006 Amir Salihefendic + Copyright (C) 2009 Aleksander Machniak + Copyright (C) 2011 Kolab Systems AG LICENSE GPL AUTHORS @@ -13,7 +16,8 @@ var GOOGIE_CUR_LANG, GOOGIE_DEFAULT_LANG = 'en'; -function GoogieSpell(img_dir, server_url) { +function GoogieSpell(img_dir, server_url, has_dict) +{ var ref = this, cookie_value = getCookie('language'); @@ -49,6 +53,7 @@ function GoogieSpell(img_dir, server_url) { 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; @@ -64,6 +69,7 @@ function GoogieSpell(img_dir, server_url) { this.extra_menu_items = []; this.custom_spellcheck_starter = null; this.main_controller = true; + this.has_dictionary = has_dict; // Observers this.lang_state_observer = null; @@ -90,7 +96,8 @@ function GoogieSpell(img_dir, server_url) { }); -this.decorateTextarea = function(id) { +this.decorateTextarea = function(id) +{ this.text_area = typeof id === 'string' ? document.getElementById(id) : id; if (this.text_area) { @@ -119,16 +126,19 @@ this.decorateTextarea = function(id) { ////// // API Functions (the ones that you can call) ///// -this.setSpellContainer = function(id) { +this.setSpellContainer = function(id) +{ this.spell_container = typeof id === 'string' ? document.getElementById(id) : id; }; -this.setLanguages = function(lang_dict) { +this.setLanguages = function(lang_dict) +{ this.lang_to_word = lang_dict; this.langlist_codes = this.array_keys(lang_dict); }; -this.setCurrentLanguage = function(lan_code) { +this.setCurrentLanguage = function(lan_code) +{ GOOGIE_CUR_LANG = lan_code; //Set cookie @@ -137,29 +147,35 @@ this.setCurrentLanguage = function(lan_code) { setCookie('language', lan_code, now); }; -this.setForceWidthHeight = function(width, height) { +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.setDecoration = function(bool) +{ this.decoration = bool; }; -this.dontUseCloseButtons = function() { +this.dontUseCloseButtons = function() +{ this.use_close_btn = false; }; -this.appendNewMenuItem = function(name, call_back_fn, checker) { +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.appendCustomMenuBuilder = function(eval_fn, builder) +{ this.custom_menu_builder.push([eval_fn, builder]); }; -this.setFocus = function() { +this.setFocus = function() +{ try { this.focus_link_b.focus(); this.focus_link_t.focus(); @@ -174,13 +190,15 @@ this.setFocus = function() { ////// // Set functions (internal) ///// -this.setStateChanged = function(current_state) { +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.setReportStateChange = function(bool) +{ this.report_state_change = bool; }; @@ -188,28 +206,31 @@ this.setReportStateChange = function(bool) { ////// // Request functions ///// -this.getUrl = function() { +this.getUrl = function() +{ return this.server_url + GOOGIE_CUR_LANG; }; -this.escapeSpecial = function(val) { +this.escapeSpecial = function(val) +{ return val ? val.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") : ''; }; -this.createXMLReq = function (text) { +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.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', + $.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); @@ -234,6 +255,25 @@ this.spellCheck = function(ignore) { }); }; +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 @@ -274,7 +314,8 @@ this.prepare = function(ignore, no_indicator) this.orginal_text = $(this.text_area).val(); }; -this.parseResult = function(r_text) { +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, @@ -324,21 +365,25 @@ this.processData = function(data) ////// // Error menu functions ///// -this.createErrorWindow = function() { +this.createErrorWindow = function() +{ this.error_window = document.createElement('div'); $(this.error_window).addClass('googie_window popupmenu').attr('googie_action_btn', '1'); }; -this.isErrorWindowShown = function() { +this.isErrorWindowShown = function() +{ return $(this.error_window).is(':visible'); }; -this.hideErrorWindow = function() { +this.hideErrorWindow = function() +{ $(this.error_window).hide(); $(this.error_window_iframe).hide(); }; -this.updateOrginalText = function(offset, old_value, new_value, id) { +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; @@ -357,18 +402,20 @@ this.saveOldValue = function(elm, old_value) { elm.old_value = old_value; }; -this.createListSeparator = function() { +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'}); + .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) { +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']; @@ -393,7 +440,15 @@ this.correctError = function(id, elm, l_elm, rm_pre_space) { this.errorFixed(); }; -this.showErrorWindow = function(elm, id) { +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); @@ -414,6 +469,7 @@ this.showErrorWindow = function(elm, id) { break; } } + if (!changed) { // Build up the result list var suggestions = this.results[id]['suggestions'], @@ -421,6 +477,26 @@ this.showErrorWindow = function(elm, id) { 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'), @@ -433,7 +509,7 @@ this.showErrorWindow = function(elm, id) { row.appendChild(item); list.appendChild(row); } - +*/ for (var i=0, len=suggestions.length; i < len; i++) { row = document.createElement('tr'), item = document.createElement('td'), @@ -441,16 +517,15 @@ this.showErrorWindow = function(elm, id) { $(dummy).html(suggestions[i]); - $(item).bind('mouseover', this.item_onmouseover) - .bind('mouseout', this.item_onmouseout) - .bind('click', function(e) { ref.correctError(id, elm, e.target.firstChild) }); + $(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 + // 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'), @@ -459,11 +534,10 @@ this.showErrorWindow = function(elm, id) { $(rev_span).addClass('googie_list_revert').html(this.lang_revert + ' ' + old_value); - $(revert).bind('mouseover', this.item_onmouseover) - .bind('mouseout', this.item_onmouseout) - .bind('click', function(e) { + $(revert).mouseover(this.item_onmouseover).mouseout(this.item_onmouseout) + .click(function(e) { ref.updateOrginalText(offset, elm.innerHTML, old_value, id); - $(elm).attr('is_corrected', true).css('color', '#b91414').html(old_value); + $(elm).removeAttr('is_corrected').css('color', '#b91414').html(old_value); ref.hideErrorWindow(); }); @@ -498,11 +572,11 @@ this.showErrorWindow = function(elm, id) { $(ok_pic).attr('src', this.img_dir + 'ok.gif') .width(32).height(16) .css({'cursor': 'pointer', 'margin-left': '2px', 'margin-right': '2px'}) - .bind('click', onsub); + .click(onsub); $(edit_form).attr('googie_action_btn', '1') .css({'margin': 0, 'padding': 0, 'cursor': 'default', 'white-space': 'nowrap'}) - .bind('submit', onsub); + .submit(onsub); edit_form.appendChild(edit_input); edit_form.appendChild(ok_pic); @@ -523,9 +597,9 @@ this.showErrorWindow = function(elm, id) { e_col = document.createElement('td'); $(e_col).html(e_elm[0]) - .bind('mouseover', ref.item_onmouseover) - .bind('mouseout', ref.item_onmouseout) - .bind('click', function() { return e_elm[1](elm, ref) }); + .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); @@ -575,7 +649,8 @@ this.showErrorWindow = function(elm, id) { ////// // Edit layer (the layer where the suggestions are stored) ////// -this.createEditLayer = function(width, height) { +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); @@ -603,7 +678,8 @@ this.createEditLayer = function(width, height) { } }; -this.resumeEditing = function() { +this.resumeEditing = function() +{ this.setStateChanged('ready'); if (this.edit_layer) @@ -629,7 +705,8 @@ this.resumeEditing = function() { this.checkSpellingState(false); }; -this.createErrorLink = function(text, id) { +this.createErrorLink = function(text, id) +{ var elm = document.createElement('span'), ref = this, d = function (e) { @@ -638,13 +715,14 @@ this.createErrorLink = function(text, id) { return false; }; - $(elm).html(text).addClass('googie_link').bind('click', d) - .attr({'googie_action_btn' : '1', 'g_id' : id, 'is_corrected' : 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) { +this.createPart = function(txt_part) +{ if (txt_part == " ") return document.createTextNode(" "); @@ -659,7 +737,8 @@ this.createPart = function(txt_part) { return span; }; -this.showErrorsInIframe = function() { +this.showErrorsInIframe = function() +{ var output = document.createElement('div'), pointer = 0, results = this.results; @@ -717,7 +796,8 @@ this.showErrorsInIframe = function() { ////// // Choose language menu ////// -this.createLangWindow = function() { +this.createLangWindow = function() +{ this.language_window = document.createElement('div'); $(this.language_window).addClass('googie_window popupmenu') .width(100).attr('googie_action_btn', '1'); @@ -776,16 +856,19 @@ this.createLangWindow = function() { this.language_window.appendChild(table); }; -this.isLangWindowShown = function() { +this.isLangWindowShown = function() +{ return $(this.language_window).is(':visible'); }; -this.hideLangWindow = function() { +this.hideLangWindow = function() +{ $(this.language_window).hide(); $(this.switch_lan_pic).removeClass().addClass('googie_lang_3d_on'); }; -this.showLangWindow = function(elm) { +this.showLangWindow = function(elm) +{ if (this.show_menu_observer) this.show_menu_observer(this); @@ -806,11 +889,13 @@ this.showLangWindow = function(elm) { this.highlightCurSel(); }; -this.deHighlightCurSel = function() { +this.deHighlightCurSel = function() +{ $(this.lang_cur_elm).removeClass().addClass('googie_list_onout'); }; -this.highlightCurSel = function() { +this.highlightCurSel = function() +{ if (GOOGIE_CUR_LANG == null) GOOGIE_CUR_LANG = GOOGIE_DEFAULT_LANG; for (var i=0; i < this.lang_elms.length; i++) { @@ -824,7 +909,8 @@ this.highlightCurSel = function() { } }; -this.createChangeLangPic = function() { +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'); @@ -847,7 +933,8 @@ this.createChangeLangPic = function() { return switch_lan; }; -this.createSpellDiv = function() { +this.createSpellDiv = function() +{ var span = document.createElement('span'); $(span).addClass('googie_check_spelling_link').text(this.lang_chck_spell); @@ -862,7 +949,8 @@ this.createSpellDiv = function() { ////// // State functions ///// -this.flashNoSpellingErrorState = function(on_finish) { +this.flashNoSpellingErrorState = function(on_finish) +{ this.setStateChanged('no_error_found'); var ref = this; @@ -888,7 +976,8 @@ this.flashNoSpellingErrorState = function(on_finish) { } }; -this.resumeEditingState = function() { +this.resumeEditingState = function() +{ this.setStateChanged('resume_editing'); //Change link text to resume @@ -906,7 +995,8 @@ this.resumeEditingState = function() { catch (e) {}; }; -this.checkSpellingState = function(fire) { +this.checkSpellingState = function(fire) +{ if (fire) this.setStateChanged('ready'); @@ -939,12 +1029,14 @@ this.checkSpellingState = function(fire) { ////// // Misc. functions ///// -this.isDefined = function(o) { +this.isDefined = function(o) +{ return (o !== undefined && o !== null) }; -this.errorFixed = function() { - this.cnt_errors_fixed++; +this.errorFixed = function() +{ + this.cnt_errors_fixed++; if (this.all_errors_fixed_observer) if (this.cnt_errors_fixed == this.cnt_errors) { this.hideErrorWindow(); @@ -952,15 +1044,18 @@ this.errorFixed = function() { } }; -this.errorFound = function() { +this.errorFound = function() +{ this.cnt_errors++; }; -this.createCloseButton = function(c_fn) { +this.createCloseButton = function(c_fn) +{ return this.createButton(this.lang_close, 'googie_list_close', c_fn); }; -this.createButton = function(name, css_class, c_fn) { +this.createButton = function(name, css_class, c_fn) +{ var btn_row = document.createElement('tr'), btn = document.createElement('td'), spn_btn; @@ -982,14 +1077,16 @@ this.createButton = function(name, css_class, c_fn) { return btn_row; }; -this.removeIndicator = function(elm) { +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) { +this.appendIndicator = function(elm) +{ // modified by roundcube if (window.rcmail) this.rc_msg_id = rcmail.set_busy(true, 'checking'); @@ -1005,19 +1102,23 @@ this.appendIndicator = function(elm) { */ } -this.createFocusLink = function(name) { +this.createFocusLink = function(name) +{ var link = document.createElement('a'); $(link).attr({'href': 'javascript:;', 'name': name}); return link; }; -this.item_onmouseover = function(e) { +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) { + +this.item_onmouseout = function(e) +{ if (this.className != 'googie_list_revert' && this.className != 'googie_list_close') this.className = 'googie_list_onout'; else diff --git a/program/js/list.js b/program/js/list.js index 1e326e2..5116df7 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -1,39 +1,39 @@ -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.colcount=this.rowcount=0;this.subject_col=-1;this.col_drag_active=this.drag_active=this.dont_select=this.toggleselect=this.keyboard=this.column_movable=this.draggable=this.multi_selecting=this.multiexpand=this.multiselect=this.shiftkey=!1;this.column_fixed=null;this.shift_start=this.last_selected=0;this.focused=this.in_selection_before=!1; -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 a,b,c=this.list.tBodies[0].rows;for(a=0,b=c.length;a<b;a++)this.init_row(c[a]),this.rowcount++;this.init_header();this.frame=this.list.parentNode;this.keyboard&&(rcube_event.add_listener({event:bw.opera?"keypress":"keydown",object:this,method:"key_press"}),rcube_event.add_listener({event:"keydown",object:this,method:"key_down"}))}},init_row:function(a){if(a&&String(a.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)){var b= -this,c=RegExp.$1;a.uid=c;this.rows[c]={uid:c,id:a.id,obj:a};a.onmousedown=function(a){return b.drag_row(a,this.uid)};a.onmouseup=function(a){return b.click_row(a,this.uid)};if(bw.iphone||bw.ipad)a.addEventListener("touchstart",function(a){a.touches.length==1&&(b.drag_row(rcube_event.touchevent(a.touches[0]),this.uid)||a.preventDefault())},!1),a.addEventListener("touchend",function(a){a.changedTouches.length==1&&(b.click_row(rcube_event.touchevent(a.changedTouches[0]),this.uid)||a.preventDefault())}, +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.colcount=this.rowcount=0;this.subject_col=-1;this.modkey=0;this.col_drag_active=this.drag_active=this.dont_select=this.toggleselect=this.keyboard=this.column_movable=this.draggable=this.multi_selecting=this.multiexpand=this.multiselect=!1;this.column_fixed=null;this.shift_start=this.last_selected=0;this.focused=this.in_selection_before=!1; +this.drag_mouse_start=null;this.dblclick_time=600;this.row_init=function(){};if(b&&"object"===typeof b)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 a,b,c=this.list.tBodies[0].rows;for(a=0,b=c.length;a<b;a++)this.init_row(c[a]),this.rowcount++;this.init_header();this.frame=this.list.parentNode;this.keyboard&&(rcube_event.add_listener({event:bw.opera?"keypress":"keydown",object:this,method:"key_press"}),rcube_event.add_listener({event:"keydown",object:this,method:"key_down"}))}},init_row:function(a){if(a&&(""+a.id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)){var b= +this,c=RegExp.$1;a.uid=c;this.rows[c]={uid:c,id:a.id,obj:a};a.onmousedown=function(a){return b.drag_row(a,this.uid)};a.onmouseup=function(a){return b.click_row(a,this.uid)};if(bw.iphone||bw.ipad)a.addEventListener("touchstart",function(a){1==a.touches.length&&(b.drag_row(rcube_event.touchevent(a.touches[0]),this.uid)||a.preventDefault())},!1),a.addEventListener("touchend",function(a){1==a.changedTouches.length&&(b.click_row(rcube_event.touchevent(a.changedTouches[0]),this.uid)||a.preventDefault())}, !1);if(document.all)a.onselectstart=function(){return!1};this.row_init(this.rows[c])}},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)a=this.list.tHead.rows[0].cells[b],a.onmousedown=function(a){return c.drag_column(a,this)},this.colcount++}},clear:function(a){this.list.insertBefore(document.createElement("tbody"),this.list.tBodies[0]); this.list.removeChild(this.list.tBodies[1]);this.rows=[];this.rowcount=0;a&&this.clear_selection();if(this.frame)this.frame.scrollTop=0},remove_row:function(a,b){if(this.rows[a].obj)this.rows[a].obj.style.display="none";b&&this.select_next();delete this.rows[a];this.rowcount--},insert_row:function(a,b){var c=this.list.tBodies[0];b&&c.rows.length?c.insertBefore(a,c.firstChild):c.appendChild(a);this.init_row(a);this.rowcount++},focus:function(a){var b,c;this.focused=!0;for(b in this.selection)c=this.selection[b], -this.rows[c]&&this.rows[c].obj&&$(this.rows[c].obj).addClass("selected").removeClass("unfocused");$("*:focus",window).blur();$("iframe").each(function(){this.blur()});(a||(a=window.event))&&rcube_event.cancel(a)},blur:function(){var a,b;this.focused=!1;for(a in this.selection)b=this.selection[a],this.rows[b]&&this.rows[b].obj&&$(this.rows[b].obj).removeClass("selected").addClass("unfocused")},drag_column:function(a,b){if(this.colcount>1){this.drag_start=!0;this.drag_mouse_start=rcube_event.get_mouse_pos(a); -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 c=0;c<this.list.tHead.rows[0].cells.length;c++)if(b==this.list.tHead.rows[0].cells[c]){this.selected_column=c;break}}return!1},drag_row:function(a,b){var c=rcube_event.get_target(a),d=c.tagName.toLowerCase();if(this.dont_select||c&&(d=="input"||d=="img"))return!0;if(rcube_event.get_button(a)==2)return!0; -this.in_selection_before=this.in_selection(b)?b:!1;this.in_selection_before||(c=rcube_event.get_modifier(a),this.select_row(b,c,!1));if(this.draggable&&this.selection.length){this.drag_start=!0;this.drag_mouse_start=rcube_event.get_mouse_pos(a);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.iphone||bw.ipad)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!1},click_row:function(a,b){var c=(new Date).getTime(),d=rcube_event.get_modifier(a),e=rcube_event.get_target(a),f=e.tagName.toLowerCase();if(e&&(f=="input"||f=="img"))return!0;if(this.dont_select)return this.dont_select=!1;e=c-this.rows[b].clicked<this.dblclick_time;!this.drag_active&&this.in_selection_before==b&&!e&&this.select_row(b,d,!1);this.in_selection_before=this.drag_start=!1;this.rows&& -e&&this.in_selection(b)?this.triggerEvent("dblclick"):this.triggerEvent("click");this.drag_active||(this.del_dragfix(),rcube_event.cancel(a));this.rows[b].clicked=c;return!1},find_root:function(a){var b=this.rows[a];return b&&b.parent_uid?this.find_root(b.parent_uid):a},expand_row:function(a,b){var c=this.rows[b],d=rcube_event.get_target(a),e=rcube_event.get_modifier(a);this.dont_select=!0;c.clicked=0;c.expanded?(d.className="collapsed",e==CONTROL_KEY||this.multiexpand?this.collapse_all(c):this.collapse(c)): -(d.className="expanded",e==CONTROL_KEY||this.multiexpand?this.expand_all(c):this.expand(c))},collapse:function(a){a.expanded=!1;this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded});for(var b=a.depth,a=a?a.obj.nextSibling:null,c;a;){if(a.nodeType==1){if((c=this.rows[a.uid])&&c.depth<=b)break;$(a).css("display","none");if(c.expanded)c.expanded=!1,this.triggerEvent("expandcollapse",{uid:c.uid,expanded:c.expanded})}a=a.nextSibling}return!1},expand:function(a){var b,c,d,e,f;a?(a.expanded= -!0,d=a.depth,e=a.obj.nextSibling,this.update_expando(a.uid,!0),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded})):(e=this.list.tBodies[0].firstChild,f=d=0);for(;e;){if(e.nodeType==1&&(b=this.rows[e.uid])){if(a&&(!b.depth||b.depth<=d))break;if(b.parent_uid)if((c=this.rows[b.parent_uid])&&c.expanded){if(a&&c==a||f>=c.depth-1)f=c.depth,$(e).css("display",""),b.expanded=!0,this.triggerEvent("expandcollapse",{uid:b.uid,expanded:b.expanded})}else if(a&&(!c||c.depth<=d))break}e=e.nextSibling}return!1}, -collapse_all:function(a){var b,c,d;if(a){if(a.expanded=!1,b=a.depth,c=a.obj.nextSibling,this.update_expando(a.uid),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded}),b&&this.multiexpand)return!1}else c=this.list.tBodies[0].firstChild,b=0;for(;c;){if(c.nodeType==1&&(d=this.rows[c.uid])){if(a&&(!d.depth||d.depth<=b))break;(a||d.depth)&&$(c).css("display","none");if(d.has_children&&d.expanded)d.expanded=!1,this.update_expando(d.uid,!1),this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded})}c= -c.nextSibling}return!1},expand_all:function(a){var b,c,d;a?(a.expanded=!0,b=a.depth,c=a.obj.nextSibling,this.update_expando(a.uid,!0),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded})):(c=this.list.tBodies[0].firstChild,b=0);for(;c;){if(c.nodeType==1&&(d=this.rows[c.uid])){if(a&&d.depth<=b)break;$(c).css("display","");if(d.has_children&&!d.expanded)d.expanded=!0,this.update_expando(d.uid,!0),this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded})}c=c.nextSibling}return!1}, -update_expando:function(a,b){var c=document.getElementById("rcmexpando"+a);if(c)c.className=b?"expanded":"collapsed"},get_next_row:function(){if(!this.rows)return!1;for(var a=this.rows[this.last_selected],a=a?a.obj.nextSibling:null;a&&(a.nodeType!=1||a.style.display=="none");)a=a.nextSibling;return a},get_prev_row:function(){if(!this.rows)return!1;for(var a=this.rows[this.last_selected],a=a?a.obj.previousSibling:null;a&&(a.nodeType!=1||a.style.display=="none");)a=a.previousSibling;return a},get_first_row:function(){if(this.rowcount){var a, -b,c=this.list.tBodies[0].rows;for(a=0,b=c.length-1;a<b;a++)if(c[a].id&&String(c[a].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(a,b,c){var d=this.selection.join(",");this.multiselect||(b=0);if(!this.shift_start)this.shift_start= -a;if(b){switch(b){case SHIFT_KEY:this.shift_select(a,!1);break;case CONTROL_KEY:c||this.highlight_row(a,!0);break;case CONTROL_SHIFT_KEY:this.shift_select(a,!0);break;default:this.highlight_row(a,!1)}this.multi_selecting=!0}else this.shift_start=a,this.highlight_row(a,!1),this.multi_selecting=!1;this.selection.join(",")!=d&&this.triggerEvent("select");this.last_selected!=0&&this.rows[this.last_selected]&&$(this.rows[this.last_selected].obj).removeClass("focused");this.toggleselect&&this.last_selected== -a?(this.clear_selection(),a=null):$(this.rows[a].obj).addClass("focused");if(!this.selection.length)this.shift_start=null;this.last_selected=a},select:function(a){this.select_row(a,!1);this.scrollto(a)},select_next:function(){var a=this.get_next_row(),b=this.get_prev_row();(a=a?a:b)&&this.select_row(a.uid,!1,!1)},select_first:function(a){var b=this.get_first_row();b&&(a?(this.shift_select(b,a),this.triggerEvent("select"),this.scrollto(b)):this.select(b))},select_last:function(a){var b=this.get_last_row(); -b&&(a?(this.shift_select(b,a),this.triggerEvent("select"),this.scrollto(b)):this.select(b))},select_childs:function(a){if(this.rows[a]&&this.rows[a].has_children)for(var b=this.rows[a].depth,a=this.rows[a].obj.nextSibling;a;){if(a.nodeType==1&&(r=this.rows[a.uid])){if(!r.depth||r.depth<=b)break;this.in_selection(r.uid)||this.select_row(r.uid,CONTROL_KEY)}a=a.nextSibling}},shift_select:function(a,b){if(!this.rows[this.shift_start]||!this.selection.length)this.shift_start=a;var c,d=this.rows[this.shift_start].obj.rowIndex, -e=this.rows[a].obj.rowIndex,f=d<e?d:e,d=d>e?d:e;for(c in this.rows)this.rows[c].obj.rowIndex>=f&&this.rows[c].obj.rowIndex<=d?this.in_selection(c)||this.highlight_row(c,!0):this.in_selection(c)&&!b&&this.highlight_row(c,!0)},in_selection:function(a){for(var b in this.selection)if(this.selection[b]==a)return!0;return!1},select_all:function(a){if(!this.rows||!this.rows.length)return!1;var b,c=this.selection.join(",");this.selection=[];for(b in this.rows)!a||this.rows[b][a]==!0?(this.last_selected=b, -this.highlight_row(b,!0)):$(this.rows[b].obj).removeClass("selected").removeClass("unfocused");this.selection.join(",")!=c&&this.triggerEvent("select");this.focus();return!0},invert_selection:function(){if(!this.rows||!this.rows.length)return!1;var a,b=this.selection.join(",");for(a in this.rows)this.highlight_row(a,!0);this.selection.join(",")!=b&&this.triggerEvent("select");this.focus();return!0},clear_selection:function(a){var b,c=this.selection.length;if(a)for(b in this.selection){if(this.selection[b]== -a){this.selection.splice(b,1);break}}else{for(b in this.selection)this.rows[this.selection[b]]&&$(this.rows[this.selection[b]].obj).removeClass("selected").removeClass("unfocused");this.selection=[]}c&&!this.selection.length&&this.triggerEvent("select")},get_selection:function(){return this.selection},get_single_selection:function(){return this.selection.length==1?this.selection[0]:null},highlight_row:function(a,b){if(this.rows[a]&&!b){if(this.selection.length>1||!this.in_selection(a))this.clear_selection(), -this.selection[0]=a,$(this.rows[a].obj).addClass("selected")}else if(this.rows[a])if(this.in_selection(a)){var c=$.inArray(a,this.selection),d=this.selection.slice(0,c),c=this.selection.slice(c+1,this.selection.length);this.selection=d.concat(c);$(this.rows[a].obj).removeClass("selected").removeClass("unfocused")}else this.selection[this.selection.length]=a,$(this.rows[a].obj).addClass("selected")},key_press:function(a){if(this.focused!=!0)return!0;var b=rcube_event.get_keycode(a),c=rcube_event.get_modifier(a); -switch(b){case 40:case 38:case 63233:case 63232:return rcube_event.cancel(a),this.use_arrow_key(b,c);case 61:case 107:case 109:case 32:return rcube_event.cancel(a),a=this.use_plusminus_key(b,c),this.key_pressed=b,this.triggerEvent("keypress"),a;case 36:return this.select_first(c),rcube_event.cancel(a);case 35:return this.select_last(c),rcube_event.cancel(a);default:if(this.shiftkey=a.shiftKey,this.key_pressed=b,this.triggerEvent("keypress"),this.shiftkey=!1,this.key_pressed==this.BACKSPACE_KEY)return rcube_event.cancel(a)}return!0}, -key_down:function(a){switch(rcube_event.get_keycode(a)){case 27:if(this.drag_active)return this.drag_mouse_up(a);if(this.col_drag_active)return this.selected_column=null,this.column_drag_mouse_up(a);case 40:case 38:case 63233:case 63232:case 61:case 107:case 109:case 32:if(!rcube_event.get_modifier(a)&&this.focused)return rcube_event.cancel(a)}return!0},use_arrow_key:function(a,b){var c;if(a==40||a==63233)c=this.get_next_row();else if(a==38||a==63232)c=this.get_prev_row();c&&(this.select_row(c.uid, -b,!0),this.scrollto(c.uid));return!1},use_plusminus_key:function(a,b){var c=this.rows[this.last_selected];if(c)return a==32&&(a=c.expanded?109:61),a==61||a==107?b==CONTROL_KEY||this.multiexpand?this.expand_all(c):this.expand(c):b==CONTROL_KEY||this.multiexpand?this.collapse_all(c):this.collapse(c),this.update_expando(c.uid,c.expanded),!1},scrollto:function(a){var b=this.rows[a].obj;if(b&&this.frame){var c=Number(b.offsetTop);!c&&this.rows[a].parent_uid&&(this.expand_all(this.rows[this.find_root(this.rows[a].uid)]), -c=Number(b.offsetTop));if(c<Number(this.frame.scrollTop))this.frame.scrollTop=c;else if(c+Number(b.offsetHeight)>Number(this.frame.scrollTop)+Number(this.frame.offsetHeight))this.frame.scrollTop=c+Number(b.offsetHeight)-Number(this.frame.offsetHeight)}},drag_mouse_move:function(a){if(a.type=="touchmove")if(a.changedTouches.length==1)a=rcube_event.touchevent(a.changedTouches[0]);else return rcube_event.cancel(a);if(this.drag_start){var b=rcube_event.get_mouse_pos(a);if(!this.drag_mouse_start||Math.abs(b.x- -this.drag_mouse_start.x)<3&&Math.abs(b.y-this.drag_mouse_start.y)<3)return!1;if(!this.draglayer)this.draglayer=$("<div>").attr("id","rcmdraglayer").css({position:"absolute",display:"none","z-index":2E3}).appendTo(document.body);var c,d,e=$.merge([],this.selection);for(c in e)d=e[c],this.rows[d].has_children&&!this.rows[d].expanded&&this.select_childs(d);this.draglayer.html("");for(c=0;c<this.selection.length;c++){if(c>12){this.draglayer.append("...");break}if(e=this.rows[this.selection[c]].obj)for(b= -0,d=0;d<e.childNodes.length;d++)if(e.childNodes[d].nodeName=="TD"){if(c==0)this.drag_start_pos=$(e.childNodes[d]).offset();if(this.subject_col<0||this.subject_col>=0&&this.subject_col==b){for(var f,g,h=e.childNodes[d].childNodes,b=0;b<h.length;b++)if((g=e.childNodes[d].childNodes[b])&&(g.nodeType==3||g.nodeName=="A"))f=g;if(!f)break;d=$(f).text();d=$.trim(d);d=d.length>50?d.substring(0,50)+"...":d;this.draglayer.append($("<div>").text(d));break}b++}}this.draglayer.show();this.drag_active=!0;this.triggerEvent("dragstart")}this.drag_active&& -this.draglayer&&(c=rcube_event.get_mouse_pos(a),this.draglayer.css({left:c.x+20+"px",top:c.y-5+(bw.ie?document.documentElement.scrollTop:0)+"px"}),this.triggerEvent("dragmove",a?a:window.event));return this.drag_start=!1},drag_mouse_up:function(a){document.onmousemove=null;if(a.type=="touchend"&&a.changedTouches.length!=1)return rcube_event.cancel(a);this.draglayer&&this.draglayer.is(":visible")&&(this.drag_start_pos?this.draglayer.animate(this.drag_start_pos,300,"swing").hide(20):this.draglayer.hide()); -this.drag_active&&this.focus();this.drag_active=!1;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.iphone||bw.ipad)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(a){if(this.drag_start){var b; -b=rcube_event.get_mouse_pos(a);if(!this.drag_mouse_start||Math.abs(b.x-this.drag_mouse_start.x)<3&&Math.abs(b.y-this.drag_mouse_start.y)<3)return!1;if(!this.col_draglayer){b=$(this.list).offset();var c=this.list.tHead.rows[0].cells;this.col_draglayer=$("<div>").attr("id","rcmcoldraglayer").css(b).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=b.left;for(b=0;b<c.length;b++)this.cols[b]=c[b].offsetWidth,this.column_fixed!==null&&b<=this.column_fixed&&(this.list_min_pos+=this.cols[b])}this.col_draglayer.show();this.col_drag_active=!0;this.triggerEvent("column_dragstart")}if(this.col_drag_active&&this.col_draglayer){var c=0,d=rcube_event.get_mouse_pos(a);for(b= -0;b<this.cols.length;b++)if(d.x>=this.cols[b]/2+this.list_pos+c)c+=this.cols[b];else break;b==0&&this.list_min_pos>d.x?c=this.list_min_pos-this.list_pos:!this.list.rowcount&&b==this.cols.length&&(c-=2);$("#rcmcolumnindicator").css({width:c+"px"});this.triggerEvent("column_dragmove",a?a:window.event)}return this.drag_start=!1},column_drag_mouse_up:function(a){document.onmousemove=null;if(this.col_draglayer)this.col_draglayer.remove(),this.col_draglayer=null;this.col_drag_active&&this.focus();this.col_drag_active= -!1;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 b,c=0,d=rcube_event.get_mouse_pos(a);for(b=0;b<this.cols.length;b++)if(d.x>=this.cols[b]/2+this.list_pos+c)c+=this.cols[b];else break;b!=this.selected_column&&b!=this.selected_column+1&&this.column_replace(this.selected_column,b)}this.triggerEvent("column_dragend"); -return rcube_event.cancel(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:1E3}).css($(this).offset()).appendTo(document.body)})},del_dragfix:function(){$("div.iframe-dragdrop-fix").each(function(){this.parentNode.removeChild(this)})},column_replace:function(a,b){var c;c=this.list.tHead.rows[0].cells;var d=c[a],e=c[b],f=document.createElement("td"); -e?c[0].parentNode.insertBefore(f,e):c[0].parentNode.appendChild(f);c[0].parentNode.replaceChild(d,f);for(r=0,c=this.list.tBodies[0].rows.length;r<c;r++)row=this.list.tBodies[0].rows[r],d=row.cells[a],e=row.cells[b],f=document.createElement("td"),e?row.insertBefore(f,e):row.appendChild(f),row.replaceChild(d,f);this.subject_col==a?this.subject_col=b>a?b-1:b:this.subject_col<a&&b<=this.subject_col?this.subject_col++:this.subject_col>a&&b>=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; +this.rows[c]&&this.rows[c].obj&&$(this.rows[c].obj).addClass("selected").removeClass("unfocused");$("*:focus",window).blur();$("iframe").each(function(){this.blur()});(a||(a=window.event))&&rcube_event.cancel(a)},blur:function(){var a,b;this.focused=!1;for(a in this.selection)b=this.selection[a],this.rows[b]&&this.rows[b].obj&&$(this.rows[b].obj).removeClass("selected").addClass("unfocused")},drag_column:function(a,b){if(1<this.colcount){this.drag_start=!0;this.drag_mouse_start=rcube_event.get_mouse_pos(a); +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 c=0;c<this.list.tHead.rows[0].cells.length;c++)if(b==this.list.tHead.rows[0].cells[c]){this.selected_column=c;break}}return!1},drag_row:function(a,b){var c=rcube_event.get_target(a),d=c.tagName.toLowerCase();if(this.dont_select||c&&("input"==d||"img"==d)||2==rcube_event.get_button(a))return!0;this.in_selection_before= +this.in_selection(b)?b:!1;this.in_selection_before||(c=rcube_event.get_modifier(a),this.select_row(b,c,!1));if(this.draggable&&this.selection.length){this.drag_start=!0;this.drag_mouse_start=rcube_event.get_mouse_pos(a);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.iphone||bw.ipad)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!1},click_row:function(a,b){var c=(new Date).getTime(),d=rcube_event.get_modifier(a),e=rcube_event.get_target(a),f=e.tagName.toLowerCase();if(e&&("input"==f||"img"==f))return!0;if(this.dont_select)return this.dont_select=!1;e=c-this.rows[b].clicked<this.dblclick_time;!this.drag_active&&this.in_selection_before==b&&!e&&this.select_row(b,d,!1);this.in_selection_before=this.drag_start=!1;this.rows&&e&&this.in_selection(b)?this.triggerEvent("dblclick"): +this.triggerEvent("click");this.drag_active||(this.del_dragfix(),rcube_event.cancel(a));this.rows[b].clicked=c;return!1},find_root:function(a){var b=this.rows[a];return b&&b.parent_uid?this.find_root(b.parent_uid):a},expand_row:function(a,b){var c=this.rows[b],d=rcube_event.get_target(a),e=rcube_event.get_modifier(a);this.dont_select=!0;c.clicked=0;c.expanded?(d.className="collapsed",e==CONTROL_KEY||this.multiexpand?this.collapse_all(c):this.collapse(c)):(d.className="expanded",e==CONTROL_KEY||this.multiexpand? +this.expand_all(c):this.expand(c))},collapse:function(a){a.expanded=!1;this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded});for(var b=a.depth,a=a?a.obj.nextSibling:null,c;a;){if(1==a.nodeType){if((c=this.rows[a.uid])&&c.depth<=b)break;$(a).css("display","none");if(c.expanded)c.expanded=!1,this.triggerEvent("expandcollapse",{uid:c.uid,expanded:c.expanded})}a=a.nextSibling}return!1},expand:function(a){var b,c,d,e,f;a?(a.expanded=!0,d=a.depth,e=a.obj.nextSibling,this.update_expando(a.uid, +!0),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded})):(e=this.list.tBodies[0].firstChild,f=d=0);for(;e;){if(1==e.nodeType&&(b=this.rows[e.uid])){if(a&&(!b.depth||b.depth<=d))break;if(b.parent_uid)if((c=this.rows[b.parent_uid])&&c.expanded){if(a&&c==a||f>=c.depth-1)f=c.depth,$(e).css("display",""),b.expanded=!0,this.triggerEvent("expandcollapse",{uid:b.uid,expanded:b.expanded})}else if(a&&(!c||c.depth<=d))break}e=e.nextSibling}return!1},collapse_all:function(a){var b,c,d;if(a){if(a.expanded= +!1,b=a.depth,c=a.obj.nextSibling,this.update_expando(a.uid),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded}),b&&this.multiexpand)return!1}else c=this.list.tBodies[0].firstChild,b=0;for(;c;){if(1==c.nodeType&&(d=this.rows[c.uid])){if(a&&(!d.depth||d.depth<=b))break;(a||d.depth)&&$(c).css("display","none");if(d.has_children&&d.expanded)d.expanded=!1,this.update_expando(d.uid,!1),this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded})}c=c.nextSibling}return!1},expand_all:function(a){var b, +c,d;a?(a.expanded=!0,b=a.depth,c=a.obj.nextSibling,this.update_expando(a.uid,!0),this.triggerEvent("expandcollapse",{uid:a.uid,expanded:a.expanded})):(c=this.list.tBodies[0].firstChild,b=0);for(;c;){if(1==c.nodeType&&(d=this.rows[c.uid])){if(a&&d.depth<=b)break;$(c).css("display","");if(d.has_children&&!d.expanded)d.expanded=!0,this.update_expando(d.uid,!0),this.triggerEvent("expandcollapse",{uid:d.uid,expanded:d.expanded})}c=c.nextSibling}return!1},update_expando:function(a,b){var c=document.getElementById("rcmexpando"+ +a);if(c)c.className=b?"expanded":"collapsed"},get_next_row:function(){if(!this.rows)return!1;for(var a=this.rows[this.last_selected],a=a?a.obj.nextSibling:null;a&&(1!=a.nodeType||"none"==a.style.display);)a=a.nextSibling;return a},get_prev_row:function(){if(!this.rows)return!1;for(var a=this.rows[this.last_selected],a=a?a.obj.previousSibling:null;a&&(1!=a.nodeType||"none"==a.style.display);)a=a.previousSibling;return a},get_first_row:function(){if(this.rowcount){var a,b,c=this.list.tBodies[0].rows; +for(a=0,b=c.length-1;a<b;a++)if(c[a].id&&(""+c[a].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)&&null!=this.rows[RegExp.$1])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;0<=a;a--)if(b[a].id&&(""+b[a].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i)&&null!=this.rows[RegExp.$1])return RegExp.$1}return null},select_row:function(a,b,c){var d=this.selection.join(",");this.multiselect||(b=0);if(!this.shift_start)this.shift_start=a;if(b){switch(b){case SHIFT_KEY:this.shift_select(a, +!1);break;case CONTROL_KEY:c||this.highlight_row(a,!0);break;case CONTROL_SHIFT_KEY:this.shift_select(a,!0);break;default:this.highlight_row(a,!1)}this.multi_selecting=!0}else this.shift_start=a,this.highlight_row(a,!1),this.multi_selecting=!1;this.selection.join(",")!=d&&this.triggerEvent("select");0!=this.last_selected&&this.rows[this.last_selected]&&$(this.rows[this.last_selected].obj).removeClass("focused");this.toggleselect&&this.last_selected==a?(this.clear_selection(),a=null):$(this.rows[a].obj).addClass("focused"); +if(!this.selection.length)this.shift_start=null;this.last_selected=a},select:function(a){this.select_row(a,!1);this.scrollto(a)},select_next:function(){var a=this.get_next_row(),b=this.get_prev_row();(a=a?a:b)&&this.select_row(a.uid,!1,!1)},select_first:function(a){var b=this.get_first_row();b&&(a?(this.shift_select(b,a),this.triggerEvent("select"),this.scrollto(b)):this.select(b))},select_last:function(a){var b=this.get_last_row();b&&(a?(this.shift_select(b,a),this.triggerEvent("select"),this.scrollto(b)): +this.select(b))},select_childs:function(a){if(this.rows[a]&&this.rows[a].has_children)for(var b=this.rows[a].depth,a=this.rows[a].obj.nextSibling;a;){if(1==a.nodeType&&(r=this.rows[a.uid])){if(!r.depth||r.depth<=b)break;this.in_selection(r.uid)||this.select_row(r.uid,CONTROL_KEY)}a=a.nextSibling}},shift_select:function(a,b){if(!this.rows[this.shift_start]||!this.selection.length)this.shift_start=a;var c,d=this.rows[this.shift_start].obj.rowIndex,e=this.rows[a].obj.rowIndex,f=d<e?d:e,d=d>e?d:e;for(c in this.rows)this.rows[c].obj.rowIndex>= +f&&this.rows[c].obj.rowIndex<=d?this.in_selection(c)||this.highlight_row(c,!0):this.in_selection(c)&&!b&&this.highlight_row(c,!0)},in_selection:function(a){for(var b in this.selection)if(this.selection[b]==a)return!0;return!1},select_all:function(a){if(!this.rows||!this.rows.length)return!1;var b,c=this.selection.join(",");this.selection=[];for(b in this.rows)!a||!0==this.rows[b][a]?(this.last_selected=b,this.highlight_row(b,!0)):$(this.rows[b].obj).removeClass("selected").removeClass("unfocused"); +this.selection.join(",")!=c&&this.triggerEvent("select");this.focus();return!0},invert_selection:function(){if(!this.rows||!this.rows.length)return!1;var a,b=this.selection.join(",");for(a in this.rows)this.highlight_row(a,!0);this.selection.join(",")!=b&&this.triggerEvent("select");this.focus();return!0},clear_selection:function(a){var b,c=this.selection.length;if(a)for(b in this.selection){if(this.selection[b]==a){this.selection.splice(b,1);break}}else{for(b in this.selection)this.rows[this.selection[b]]&& +$(this.rows[this.selection[b]].obj).removeClass("selected").removeClass("unfocused");this.selection=[]}c&&!this.selection.length&&this.triggerEvent("select")},get_selection:function(){return this.selection},get_single_selection:function(){return 1==this.selection.length?this.selection[0]:null},highlight_row:function(a,b){if(this.rows[a]&&!b){if(1<this.selection.length||!this.in_selection(a))this.clear_selection(),this.selection[0]=a,$(this.rows[a].obj).addClass("selected")}else if(this.rows[a])if(this.in_selection(a)){var c= +$.inArray(a,this.selection),d=this.selection.slice(0,c),c=this.selection.slice(c+1,this.selection.length);this.selection=d.concat(c);$(this.rows[a].obj).removeClass("selected").removeClass("unfocused")}else this.selection[this.selection.length]=a,$(this.rows[a].obj).addClass("selected")},key_press:function(a){var b=a.target||{};if(!0!=this.focused||"INPUT"==b.nodeName||"TEXTAREA"==b.nodeName||"SELECT"==b.nodeName)return!0;var b=rcube_event.get_keycode(a),c=rcube_event.get_modifier(a);switch(b){case 40:case 38:case 63233:case 63232:return rcube_event.cancel(a), +this.use_arrow_key(b,c);case 61:case 107:case 109:case 32:return rcube_event.cancel(a),a=this.use_plusminus_key(b,c),this.key_pressed=b,this.modkey=c,this.triggerEvent("keypress"),this.modkey=0,a;case 36:return this.select_first(c),rcube_event.cancel(a);case 35:return this.select_last(c),rcube_event.cancel(a);default:if(this.key_pressed=b,this.modkey=c,this.triggerEvent("keypress"),this.modkey=0,this.key_pressed==this.BACKSPACE_KEY)return rcube_event.cancel(a)}return!0},key_down:function(a){var b= +a.target||{};if(!0!=this.focused||"INPUT"==b.nodeName||"TEXTAREA"==b.nodeName||"SELECT"==b.nodeName)return!0;switch(rcube_event.get_keycode(a)){case 27:if(this.drag_active)return this.drag_mouse_up(a);if(this.col_drag_active)return this.selected_column=null,this.column_drag_mouse_up(a);case 40:case 38:case 63233:case 63232:case 61:case 107:case 109:case 32:if(!rcube_event.get_modifier(a)&&this.focused)return rcube_event.cancel(a)}return!0},use_arrow_key:function(a,b){var c;if(40==a||63233==a)c=this.get_next_row(); +else if(38==a||63232==a)c=this.get_prev_row();c&&(this.select_row(c.uid,b,!1),this.scrollto(c.uid));return!1},use_plusminus_key:function(a,b){var c=this.rows[this.last_selected];if(c)return 32==a&&(a=c.expanded?109:61),61==a||107==a?b==CONTROL_KEY||this.multiexpand?this.expand_all(c):this.expand(c):b==CONTROL_KEY||this.multiexpand?this.collapse_all(c):this.collapse(c),this.update_expando(c.uid,c.expanded),!1},scrollto:function(a){var b=this.rows[a].obj;if(b&&this.frame){var c=Number(b.offsetTop); +!c&&this.rows[a].parent_uid&&(this.expand_all(this.rows[this.find_root(this.rows[a].uid)]),c=Number(b.offsetTop));if(c<Number(this.frame.scrollTop))this.frame.scrollTop=c;else if(c+Number(b.offsetHeight)>Number(this.frame.scrollTop)+Number(this.frame.offsetHeight))this.frame.scrollTop=c+Number(b.offsetHeight)-Number(this.frame.offsetHeight)}},drag_mouse_move:function(a){if("touchmove"==a.type)if(1==a.changedTouches.length)a=rcube_event.touchevent(a.changedTouches[0]);else return rcube_event.cancel(a); +if(this.drag_start){var b=rcube_event.get_mouse_pos(a);if(!this.drag_mouse_start||3>Math.abs(b.x-this.drag_mouse_start.x)&&3>Math.abs(b.y-this.drag_mouse_start.y))return!1;if(!this.draglayer)this.draglayer=$("<div>").attr("id","rcmdraglayer").css({position:"absolute",display:"none","z-index":2E3}).appendTo(document.body);var c,d,e=$.merge([],this.selection);for(c in e)d=e[c],this.rows[d].has_children&&!this.rows[d].expanded&&this.select_childs(d);this.draglayer.html("");for(c=0;c<this.selection.length;c++){if(12< +c){this.draglayer.append("...");break}if(e=this.rows[this.selection[c]].obj)for(b=0,d=0;d<e.childNodes.length;d++)if("TD"==e.childNodes[d].nodeName){if(0==c)this.drag_start_pos=$(e.childNodes[d]).offset();if(0>this.subject_col||0<=this.subject_col&&this.subject_col==b){for(var f,g,h=e.childNodes[d].childNodes,b=0;b<h.length;b++)if((g=e.childNodes[d].childNodes[b])&&(3==g.nodeType||"A"==g.nodeName))f=g;if(!f)break;d=$(f).text();d=$.trim(d);d=50<d.length?d.substring(0,50)+"...":d;this.draglayer.append($("<div>").text(d)); +break}b++}}this.draglayer.show();this.drag_active=!0;this.triggerEvent("dragstart")}this.drag_active&&this.draglayer&&(c=rcube_event.get_mouse_pos(a),this.draglayer.css({left:c.x+20+"px",top:c.y-5+(bw.ie?document.documentElement.scrollTop:0)+"px"}),this.triggerEvent("dragmove",a?a:window.event));return this.drag_start=!1},drag_mouse_up:function(a){document.onmousemove=null;if("touchend"==a.type&&1!=a.changedTouches.length)return rcube_event.cancel(a);this.draglayer&&this.draglayer.is(":visible")&& +(this.drag_start_pos?this.draglayer.animate(this.drag_start_pos,300,"swing").hide(20):this.draglayer.hide());this.drag_active&&this.focus();this.drag_active=!1;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.iphone||bw.ipad)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(a){if(this.drag_start){var b;b=rcube_event.get_mouse_pos(a);if(!this.drag_mouse_start||3>Math.abs(b.x-this.drag_mouse_start.x)&&3>Math.abs(b.y-this.drag_mouse_start.y))return!1;if(!this.col_draglayer){b=$(this.list).offset();var c=this.list.tHead.rows[0].cells;this.col_draglayer=$("<div>").attr("id","rcmcoldraglayer").css(b).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=b.left;for(b=0;b<c.length;b++)this.cols[b]=c[b].offsetWidth,null!==this.column_fixed&&b<=this.column_fixed&&(this.list_min_pos+=this.cols[b])}this.col_draglayer.show();this.col_drag_active= +!0;this.triggerEvent("column_dragstart")}if(this.col_drag_active&&this.col_draglayer){var c=0,d=rcube_event.get_mouse_pos(a);for(b=0;b<this.cols.length;b++)if(d.x>=this.cols[b]/2+this.list_pos+c)c+=this.cols[b];else break;0==b&&this.list_min_pos>d.x?c=this.list_min_pos-this.list_pos:!this.list.rowcount&&b==this.cols.length&&(c-=2);$("#rcmcolumnindicator").css({width:c+"px"});this.triggerEvent("column_dragmove",a?a:window.event)}return this.drag_start=!1},column_drag_mouse_up:function(a){document.onmousemove= +null;if(this.col_draglayer)this.col_draglayer.remove(),this.col_draglayer=null;this.col_drag_active&&this.focus();this.col_drag_active=!1;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(null!==this.selected_column&&this.cols&&this.cols.length){var b,c=0,d=rcube_event.get_mouse_pos(a);for(b=0;b<this.cols.length;b++)if(d.x>=this.cols[b]/2+this.list_pos+ +c)c+=this.cols[b];else break;b!=this.selected_column&&b!=this.selected_column+1&&this.column_replace(this.selected_column,b)}this.triggerEvent("column_dragend");return rcube_event.cancel(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:1E3}).css($(this).offset()).appendTo(document.body)})},del_dragfix:function(){$("div.iframe-dragdrop-fix").each(function(){this.parentNode.removeChild(this)})}, +column_replace:function(a,b){var c;c=this.list.tHead.rows[0].cells;var d=c[a],e=c[b],f=document.createElement("td");e?c[0].parentNode.insertBefore(f,e):c[0].parentNode.appendChild(f);c[0].parentNode.replaceChild(d,f);for(r=0,c=this.list.tBodies[0].rows.length;r<c;r++)row=this.list.tBodies[0].rows[r],d=row.cells[a],e=row.cells[b],f=document.createElement("td"),e?row.insertBefore(f,e):row.appendChild(f),row.replaceChild(d,f);this.subject_col==a?this.subject_col=b>a?b-1:b:this.subject_col<a&&b<=this.subject_col? +this.subject_col++:this.subject_col>a&&b>=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; diff --git a/program/js/list.js.src b/program/js/list.js.src index e47b547..c8864c3 100644 --- a/program/js/list.js.src +++ b/program/js/list.js.src @@ -13,7 +13,7 @@ | Requires: common.js | +-----------------------------------------------------------------------+ - $Id: list.js 4750 2011-05-12 09:27:17Z alec $ + $Id: list.js 5271 2011-09-22 20:51:42Z thomasb $ */ @@ -36,7 +36,7 @@ function rcube_list_widget(list, p) this.colcount = 0; this.subject_col = -1; - this.shiftkey = false; + this.modkey = 0; this.multiselect = false; this.multiexpand = false; this.multi_selecting = false; @@ -648,7 +648,7 @@ select_row: function(id, mod_key, with_mouse) case CONTROL_KEY: if (!with_mouse) this.highlight_row(id, true); - break; + break; case CONTROL_SHIFT_KEY: this.shift_select(id, true); @@ -954,7 +954,8 @@ highlight_row: function(id, multiple) */ key_press: function(e) { - if (this.focused != true) + 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), @@ -962,7 +963,7 @@ key_press: function(e) switch (keyCode) { case 40: - case 38: + case 38: case 63233: // "down", in safari keypress case 63232: // "up", in safari keypress // Stop propagation so that the browser doesn't scroll @@ -976,7 +977,9 @@ key_press: function(e) 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); @@ -985,11 +988,10 @@ key_press: function(e) this.select_last(mod_key); return rcube_event.cancel(e); default: - this.shiftkey = e.shiftKey; this.key_pressed = keyCode; + this.modkey = mod_key; this.triggerEvent('keypress'); - // reset shiftkey flag, we need it only for registered events - this.shiftkey = false; + this.modkey = 0; if (this.key_pressed == this.BACKSPACE_KEY) return rcube_event.cancel(e); @@ -1003,13 +1005,17 @@ key_press: function(e) */ key_down: function(e) { + var target = e.target || {}; + if (this.focused != true || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT') + return true; + switch (rcube_event.get_keycode(e)) { case 27: if (this.drag_active) - return this.drag_mouse_up(e); + return this.drag_mouse_up(e); if (this.col_drag_active) { this.selected_column = null; - return this.column_drag_mouse_up(e); + return this.column_drag_mouse_up(e); } case 40: @@ -1044,7 +1050,7 @@ use_arrow_key: function(keyCode, mod_key) new_row = this.get_prev_row(); if (new_row) { - this.select_row(new_row.uid, mod_key, true); + this.select_row(new_row.uid, mod_key, false); this.scrollto(new_row.uid); } diff --git a/program/lib/html2text.php b/program/lib/html2text.php index 1ab1605..9fc96ea 100644 --- a/program/lib/html2text.php +++ b/program/lib/html2text.php @@ -145,7 +145,6 @@ class html2text var $search = array( "/\r/", // Non-legal carriage return "/[\n\t]+/", // Newlines and tabs - '/[ ]{2,}/', // Runs of spaces, pre-handling '/<script[^>]*>.*?<\/script>/i', // <script>s -- which strip_tags supposedly has problems with '/<style[^>]*>.*?<\/style>/i', // <style>s -- which strip_tags supposedly has problems with '/<p[^>]*>/i', // <P> @@ -161,22 +160,6 @@ class html2text '/(<table[^>]*>|<\/table>)/i', // <table> and </table> '/(<tr[^>]*>|<\/tr>)/i', // <tr> and </tr> '/<td[^>]*>(.*?)<\/td>/i', // <td> and </td> - '/&(nbsp|#160);/i', // Non-breaking space - '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i', - // Double quotes - '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes - '/>/i', // Greater-than - '/</i', // Less-than - '/&(copy|#169);/i', // Copyright - '/&(trade|#8482|#153);/i', // Trademark - '/&(reg|#174);/i', // Registered - '/&(mdash|#151|#8212);/i', // mdash - '/&(ndash|minus|#8211|#8722);/i', // ndash - '/&(bull|#149|#8226);/i', // Bullet - '/&(pound|#163);/i', // Pound sign - '/&(euro|#8364);/i', // Euro sign - '/&(amp|#38);/i', // Ampersand: see _converter() - '/[ ]{2,}/' // Runs of spaces, post-handling ); /** @@ -189,7 +172,6 @@ class html2text var $replace = array( '', // Non-legal carriage return ' ', // Newlines and tabs - ' ', // Runs of spaces, pre-handling '', // <script>s -- which strip_tags supposedly has problems with '', // <style>s -- which strip_tags supposedly has problems with "\n\n", // <P> @@ -205,6 +187,43 @@ class html2text "\n\n", // <table> and </table> "\n", // <tr> and </tr> "\t\t\\1\n", // <td> and </td> + ); + + /** + * List of preg* regular expression patterns to search for, + * used in conjunction with $ent_replace. + * + * @var array $ent_search + * @access public + * @see $ent_replace + */ + var $ent_search = array( + '/&(nbsp|#160);/i', // Non-breaking space + '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i', + // Double quotes + '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes + '/>/i', // Greater-than + '/</i', // Less-than + '/&(copy|#169);/i', // Copyright + '/&(trade|#8482|#153);/i', // Trademark + '/&(reg|#174);/i', // Registered + '/&(mdash|#151|#8212);/i', // mdash + '/&(ndash|minus|#8211|#8722);/i', // ndash + '/&(bull|#149|#8226);/i', // Bullet + '/&(pound|#163);/i', // Pound sign + '/&(euro|#8364);/i', // Euro sign + '/&(amp|#38);/i', // Ampersand: see _converter() + '/[ ]{2,}/', // Runs of spaces, post-handling + ); + + /** + * List of pattern replacements corresponding to patterns searched. + * + * @var array $ent_replace + * @access public + * @see $ent_search + */ + var $ent_replace = array( ' ', // Non-breaking space '"', // Double quotes "'", // Single quotes @@ -219,7 +238,7 @@ class html2text '£', 'EUR', // Euro sign. ? '|+|amp|+|', // Ampersand: see _converter() - ' ' // Runs of spaces, post-handling + ' ', // Runs of spaces, post-handling ); /** @@ -303,7 +322,7 @@ class html2text * @see _build_link_list() */ var $_link_list = ''; - + /** * Number of valid links detected in the text, used for plain text * display (rendered similar to footnotes). @@ -314,15 +333,15 @@ class html2text */ var $_link_count = 0; - /** - * Boolean flag, true if a table of link URLs should be listed after the text. - * - * @var boolean $_do_links - * @access private - * @see html2text() + /** + * Boolean flag, true if a table of link URLs should be listed after the text. + * + * @var boolean $_do_links + * @access private + * @see html2text() */ var $_do_links = true; - + /** * Constructor. * @@ -492,15 +511,21 @@ class html2text // Convert <PRE> $this->_convert_pre($text); - // Run our defined search-and-replace + // Run our defined tags search-and-replace $text = preg_replace($this->search, $this->replace, $text); + // Run our defined tags search-and-replace with callback + $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text); + + // Strip any other HTML tags + $text = strip_tags($text, $this->allowed_tags); + + // Run our defined entities/characters search-and-replace + $text = preg_replace($this->ent_search, $this->ent_replace, $text); + // Replace known html entities $text = html_entity_decode($text, ENT_COMPAT, 'UTF-8'); - // Run our defined search-and-replace with callback - $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text); - // Remove unknown/unhandled entities (this cannot be done in search-and-replace block) $text = preg_replace('/&([a-zA-Z0-9]{2,6}|#[0-9]{2,4});/', '', $text); @@ -508,15 +533,12 @@ class html2text // This properly handles situation of "&quot;" in input string $text = str_replace('|+|amp|+|', '&', $text); - // Strip any other HTML tags - $text = strip_tags($text, $this->allowed_tags); - // Bring down number of empty lines to 2 max $text = preg_replace("/\n\s+\n/", "\n\n", $text); $text = preg_replace("/[\n]{3,}/", "\n\n", $text); // remove leading empty lines (can be produced by eg. P tag on the beginning) - $text = preg_replace('/^\n+/', '', $text); + $text = ltrim($text, "\n"); // Wrap the text to a readable format // for PHP versions >= 4.0.2. Default width is 75 @@ -544,9 +566,7 @@ class html2text if ( !$this->_do_links ) return $display; - if ( substr($link, 0, 7) == 'http://' || substr($link, 0, 8) == 'https://' || - substr($link, 0, 7) == 'mailto:' - ) { + if ( preg_match('!^(https?://|mailto:)!', $link) ) { $this->_link_count++; $this->_link_list .= '[' . $this->_link_count . "] $link\n"; $additional = ' [' . $this->_link_count . ']'; diff --git a/program/lib/washtml.php b/program/lib/washtml.php index a5eeb84..f8c3251 100644 --- a/program/lib/washtml.php +++ b/program/lib/washtml.php @@ -81,17 +81,35 @@ class washtml { /* Allowed HTML elements (default) */ - static $html_elements = array('a', 'abbr', 'acronym', 'address', 'area', 'b', 'basefont', 'bdo', 'big', 'blockquote', 'br', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'ins', 'label', 'legend', 'li', 'map', 'menu', 'nobr', 'ol', 'p', 'pre', 'q', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'wbr', 'img'); - + static $html_elements = array('a', 'abbr', 'acronym', 'address', 'area', 'b', + 'basefont', 'bdo', 'big', 'blockquote', 'br', 'caption', 'center', + 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', + 'dt', 'em', 'fieldset', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', + 'ins', 'label', 'legend', 'li', 'map', 'menu', 'nobr', 'ol', 'p', 'pre', 'q', + 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'table', + 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'wbr', 'img', + // form elements + 'button', 'input', 'textarea', 'select', 'option', 'optgroup' + ); + /* Ignore these HTML tags and their content */ static $ignore_elements = array('script', 'applet', 'embed', 'object', 'style'); - + /* Allowed HTML attributes */ - static $html_attribs = array('name', 'class', 'title', 'alt', 'width', 'height', 'align', 'nowrap', 'col', 'row', 'id', 'rowspan', 'colspan', 'cellspacing', 'cellpadding', 'valign', 'bgcolor', 'color', 'border', 'bordercolorlight', 'bordercolordark', 'face', 'marginwidth', 'marginheight', 'axis', 'border', 'abbr', 'char', 'charoff', 'clear', 'compact', 'coords', 'vspace', 'hspace', 'cellborder', 'size', 'lang', 'dir'); + static $html_attribs = array('name', 'class', 'title', 'alt', 'width', 'height', + 'align', 'nowrap', 'col', 'row', 'id', 'rowspan', 'colspan', 'cellspacing', + 'cellpadding', 'valign', 'bgcolor', 'color', 'border', 'bordercolorlight', + 'bordercolordark', 'face', 'marginwidth', 'marginheight', 'axis', 'border', + 'abbr', 'char', 'charoff', 'clear', 'compact', 'coords', 'vspace', 'hspace', + 'cellborder', 'size', 'lang', 'dir', + // attributes of form elements + 'type', 'rows', 'cols', 'disabled', 'readonly', 'checked', 'multiple', 'value' + ); /* Block elements which could be empty but cannot be returned in short form (<tag />) */ - static $block_elements = array('div', 'p', 'pre', 'blockquote', 'a', 'font', 'center', 'table', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'dl', 'strong', 'i', 'b'); - + static $block_elements = array('div', 'p', 'pre', 'blockquote', 'a', 'font', 'center', + 'table', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'dl', 'strong', 'i', 'b', 'u'); + /* State for linked objects in HTML */ public $extlinks = false; @@ -100,7 +118,7 @@ class washtml /* Registered callback functions for tags */ private $handlers = array(); - + /* Allowed HTML elements */ private $_html_elements = array(); @@ -112,7 +130,7 @@ class washtml /* Allowed HTML attributes */ private $_html_attribs = array(); - + /* Constructor */ public function __construct($p = array()) { @@ -123,13 +141,13 @@ class washtml unset($p['html_elements'], $p['html_attribs'], $p['ignore_elements'], $p['block_elements']); $this->config = $p + array('show_washed'=>true, 'allow_remote'=>false, 'cid_map'=>array()); } - + /* Register a callback function for a certain tag */ public function add_callback($tagName, $callback) { $this->handlers[$tagName] = $callback; } - + /* Check CSS style */ private function wash_style($style) { $s = ''; @@ -143,14 +161,14 @@ class washtml preg_match('/^(url\(\s*[\'"]?([^\'"\)]*)[\'"]?\s*\)'./*1,2*/ '|rgb\(\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*\)'. '|-?[0-9.]+\s*(em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)?'. - '|#[0-9a-f]{3,6}|[a-z0-9\-]+'. + '|#[0-9a-f]{3,6}|[a-z0-9", -]+'. ')\s*/i', $str, $match)) { if ($match[2]) { if (($src = $this->config['cid_map'][$match[2]]) || ($src = $this->config['cid_map'][$this->config['base_url'].$match[2]])) { $value .= ' url('.htmlspecialchars($src, ENT_QUOTES) . ')'; } - else if (preg_match('/^(http|https|ftp):.*$/i', $match[2], $url)) { + else if (preg_match('!^(https?:)?//[a-z0-9/._+-]+$!i', $match[2], $url)) { if ($this->config['allow_remote']) $value .= ' url('.htmlspecialchars($url[0], ENT_QUOTES).')'; else @@ -160,8 +178,9 @@ class washtml $value .= ' url('.htmlspecialchars($match[2], ENT_QUOTES).')'; } } - else if ($match[0] != 'url' && $match[0] != 'rbg') //whitelist ? + else if ($match[0] != 'url' && $match[0] != 'rgb') //whitelist ? $value .= ' ' . $match[0]; + $str = substr($str, strlen($match[0])); } if ($value) @@ -182,8 +201,10 @@ class washtml if (isset($this->_html_attribs[$key]) || ($key == 'href' && preg_match('/^(http:|https:|ftp:|mailto:|#).+/i', $value))) $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; - else if ($key == 'style' && ($style = $this->wash_style($value))) - $t .= ' style="' . $style . '"'; + else if ($key == 'style' && ($style = $this->wash_style($value))) { + $quot = strpos($style, '"') !== false ? "'" : '"'; + $t .= ' style=' . $quot . $style . $quot; + } else if ($key == 'background' || ($key == 'src' && strtolower($node->tagName) == 'img')) { //check tagName anyway if (($src = $this->config['cid_map'][$value]) || ($src = $this->config['cid_map'][$this->config['base_url'].$value])) { @@ -222,7 +243,7 @@ class washtml case XML_ELEMENT_NODE: //Check element $tagName = strtolower($node->tagName); if ($callback = $this->handlers[$tagName]) { - $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node)); + $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node), $this); } else if (isset($this->_html_elements[$tagName])) { $content = $this->dumpHtml($node); @@ -280,6 +301,14 @@ class washtml return $this->dumpHtml($node); } + /** + * Getter for config parameters + */ + public function get_config($prop) + { + return $this->config[$prop]; + } + } ?> diff --git a/program/localization/ar_SA/labels.inc b/program/localization/ar_SA/labels.inc index 657917a..04a4879 100644 --- a/program/localization/ar_SA/labels.inc +++ b/program/localization/ar_SA/labels.inc @@ -13,7 +13,7 @@ | Author: Ossama Khayat <okhayat@yahoo.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -117,7 +117,7 @@ $labels['markread'] = 'ÙÙ ÙØ±Ùءة'; $labels['markunread'] = 'ÙØºÙر Ù ÙØ±Ùءة'; $labels['markflagged'] = 'ÙÙ ÙÙØ³ÙÙ Ø©'; $labels['markunflagged'] = 'ÙØºÙر Ù ÙÙØ³ÙÙ Ø©'; -$labels['messageactions'] = 'إجراءات إضاÙÙØ©...'; +$labels['moreactions'] = 'إجراءات إضاÙÙØ©...'; $labels['select'] = 'ØªØØ¯Ùد'; $labels['all'] = 'اÙÙÙ'; $labels['none'] = 'ÙØ§ Ø´ÙØ¡'; @@ -170,6 +170,8 @@ $labels['charset'] = 'Ù Ø¬Ù ÙØ¹Ø© اÙÙ ØØ§Ø±Ù'; $labels['editortype'] = 'ÙÙØ¹ اÙÙ ÙØØ±ÙØ±'; $labels['returnreceipt'] = 'Ø§ÙØµØ§Ù Ø§Ø³ØªÙØ§Ù '; $labels['dsn'] = 'تÙÙÙÙ ØØ§ÙØ© Ø§ÙØªÙصÙÙ'; +$labels['mailreplyintro'] = 'ÙØªØ¨ $sender ÙÙ $date:'; +$labels['originalmessage'] = 'Ø§ÙØ±Ø³Ø§ÙØ© Ø§ÙØ£Ø³Ø§Ø³ÙØ©'; $labels['editidents'] = 'تعدÙ٠اÙÙÙÙØ§Øª'; $labels['checkspelling'] = 'Ø§ÙØªØ¯ÙÙÙ Ø§ÙØ¥Ù ÙØ§Ø¦Ù'; $labels['resumeediting'] = '٠تابعة Ø§ÙØªØØ±Ùر'; @@ -187,6 +189,7 @@ $labels['highest'] = 'Ø§ÙØ£Ø¹ÙÙ'; $labels['nosubject'] = '(دÙÙ Ù ÙØ¶Ùع)'; $labels['showimages'] = 'Ø¥Ø¸ÙØ§Ø± Ø§ÙØµÙر'; $labels['alwaysshow'] = 'Ø¯Ø§Ø¦Ù Ø§Ù Ø£Ø¸ÙØ± Ø§ÙØµÙÙØ± اÙÙØ§Ø¯Ù Ø© Ù Ù $sender'; +$labels['isdraft'] = 'ÙØ°Ù Ù Ø³ÙØ¯ÙØ© Ø±Ø³Ø§ÙØ©'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'ÙØµ ٠جرد'; $labels['savesentmessagein'] = 'اØÙظ Ø§ÙØ±Ø³Ø§ÙØ© اÙÙ ÙØ±Ø³ÙØ© ÙÙ'; @@ -245,6 +248,8 @@ $labels['typepager'] = 'Ø§ÙØ±ÙاÙ'; $labels['typevideo'] = 'اÙÙÙØ¯ÙÙ'; $labels['typeassistant'] = 'اÙ٠ساعد'; $labels['typehomepage'] = 'Ø§ÙØ±Ø¦ÙØ³ÙØ©'; +$labels['typeblog'] = 'اÙ٠دÙÙÙØ©'; +$labels['typeprofile'] = 'اÙÙ ÙÙ Ø§ÙØ´Ø®ØµÙ'; $labels['addfield'] = 'Ø¥Ø¶Ø§ÙØ© ØÙÙ...'; $labels['addcontact'] = 'Ø¥Ø¶Ø§ÙØ© اÙ٠راس٠اÙÙ ØØ¯Ø¯ Ø¥ÙÙ Ø¯ÙØªØ± Ø¹ÙØ§ÙÙÙÙ'; $labels['editcontact'] = 'ØªØØ±Ùر Ø¨ÙØ§Ùات اÙ٠راسÙ'; @@ -266,7 +271,6 @@ $labels['print'] = 'طباعة'; $labels['export'] = 'ØªØµØ¯ÙØ±'; $labels['exportvcards'] = 'ØµØ¯ÙØ± اÙ٠راسÙÙÙ Ø¨ÙØ³Ù vCard'; $labels['newcontactgroup'] = 'Ø¥ÙØ´Ø§Ø¡ Ù Ø¬Ù ÙØ¹Ø© ٠راسÙÙÙ Ø¬Ø¯ÙØ¯Ø©'; -$labels['groupactions'] = 'إجراءات Ù Ø¬Ù ÙØ¹Ø§Øª اÙ٠راسÙÙÙ...'; $labels['grouprename'] = 'تغÙÙØ± اس٠اÙÙ Ø¬Ù ÙØ¹Ø©'; $labels['groupdelete'] = 'ØØ°Ù اÙÙ Ø¬Ù ÙØ¹Ø©'; $labels['previouspage'] = 'عرض اÙÙ Ø¬Ù ÙØ¹Ø© Ø§ÙØ³Ø§Ø¨ÙØ©'; @@ -276,6 +280,8 @@ $labels['lastpage'] = 'عرض اÙÙ Ø¬Ù ÙØ¹Ø© Ø§ÙØ£Ø®Ùرة'; $labels['group'] = 'Ù Ø¬Ù ÙØ¹Ø©'; $labels['groups'] = 'اÙÙ Ø¬Ù ÙØ¹Ø§Øª'; $labels['personaladrbook'] = 'Ø§ÙØ¹ÙاÙÙÙ Ø§ÙØ´Ø®ØµÙØ©'; +$labels['searchsave'] = 'ØÙظ Ø§ÙØ¨ØØ«'; +$labels['searchdelete'] = 'ØØ°Ù Ø§ÙØ¨ØØ«'; $labels['import'] = 'Ø§Ø³ØªÙØ±Ø¯'; $labels['importcontacts'] = 'Ø§Ø³ØªÙØ±Ø¯ اÙ٠راسÙÙÙ'; $labels['importfromfile'] = 'Ø§Ø³ØªÙØ±Ø¯ Ù Ù Ù ÙÙ:'; @@ -284,6 +290,7 @@ $labels['importreplace'] = 'Ø§Ø³ØªØ¨Ø¯Ù Ø¯ÙØªØ± Ø§ÙØ¹ÙاÙÙ٠بأÙÙ ÙÙ' $labels['importtext'] = 'ÙÙ ÙÙÙ Ø±ÙØ¹ ÙØ§Ø¦Ù Ø© اÙ٠راسÙÙÙ Ù Ù Ø¯ÙØªØ± Ø¹ÙØ§ÙÙÙ Ù ÙØ¬Ùد.<br/>ÙØ¯Ø¹Ù ØØ§ÙÙØ§Ù Ø§Ø³ØªÙØ±Ø§Ø¯ Ø§ÙØ¹ÙاÙÙÙ Ù Ù ÙØ³Ù Ø¨ÙØ§Ùات <a href="http://en.wikipedia.org/wiki/VCard">vCard</a>.'; $labels['done'] = 'ت٠'; $labels['settingsfor'] = 'إعدادات'; +$labels['about'] = 'ÙØ¨Ø°Ø©'; $labels['preferences'] = 'Ø§ÙØªÙضÙÙØ§Øª'; $labels['userpreferences'] = 'ØªÙØ¶ÙÙØ§Øª اÙ٠ستخد٠'; $labels['editpreferences'] = 'ØªØØ±Ùر ØªÙØ¶ÙÙØ§Øª اÙ٠ستخد٠'; @@ -295,6 +302,8 @@ $labels['edititem'] = 'ØªØØ±Ùر Ø¹ÙØµØ±'; $labels['preferhtml'] = 'ØªÙØ¶ÙÙ ØµÙØºØ© HTML'; $labels['defaultcharset'] = 'ØªØ±Ù ÙØ² اÙÙ ØØ§Ø±Ù Ø§ÙØ§ÙتراضÙ'; $labels['htmlmessage'] = 'Ø±Ø³Ø§ÙØ© Ø¨ÙØ³Ù HTML'; +$labels['dateformat'] = 'ÙØ³Ù Ø§ÙØªØ§Ø±ÙØ®'; +$labels['timeformat'] = 'ÙØ³Ù اÙÙÙØª'; $labels['prettydate'] = 'ØªÙØ§Ø±ÙØ® Ù ÙÙ ÙØ©'; $labels['setdefault'] = 'تعÙÙÙ ÙØ¥ÙتراضÙ'; $labels['autodetect'] = 'Ø¢ÙÙ'; @@ -366,7 +375,13 @@ $labels['reqmdn'] = 'Ø·ÙØ¨ إشعار Ø§Ø³ØªÙØ§Ù دائ٠اÙ'; $labels['reqdsn'] = 'Ø·ÙØ¨ تÙÙÙÙ ÙØØ§ÙØ© Ø§ÙØªÙصÙ٠دائ٠اÙ'; $labels['replysamefolder'] = 'ÙØ¶Ø¹ Ø§ÙØ±Ø¯Ùد Ù٠اÙÙ Ø¬ÙØ¯ Ø§ÙØ°Ù ÙØÙÙ Ø§ÙØ±Ø³Ø§ÙØ© اÙÙ Ø±Ø¯ÙØ¯ عÙÙÙØ§'; $labels['defaultaddressbook'] = 'أض٠اÙ٠راسÙÙÙ Ø§ÙØ¬Ø¯Ùد Ø¥ÙÙ Ø¯ÙØªØ± Ø§ÙØ¹ÙاÙÙ٠اÙÙ ØØ¯Ø¯'; +$labels['autocompletesingle'] = 'تجاÙ٠عÙÙØ§Ù Ø§ÙØ¨Ø±Ùد Ø§ÙØ¥ÙÙØªØ±ÙÙÙ Ø§ÙØ¨Ø¯ÙÙ ÙÙ Ø§ÙØªÙÙ ÙØ© Ø§ÙØªÙÙØ§Ø¦ÙØ©'; $labels['spellcheckbeforesend'] = 'تØÙÙ Ù Ù Ø§ÙØ¥Ù ÙØ§Ø¡ ÙØ¨Ù Ø¥Ø±Ø³Ø§Ù Ø§ÙØ±Ø³Ø§Ø¦Ù'; +$labels['spellcheckoptions'] = 'Ø®ÙØ§Ø±Ø§Øª Ø§ÙØªØ¯ÙÙÙ Ø§ÙØ¥Ù ÙØ§Ø¡Ù'; +$labels['spellcheckignoresyms'] = 'تجاÙ٠اÙÙÙ٠ات Ø§ÙØªÙ ØªØØªÙÙ Ø±Ù ÙØ²'; +$labels['spellcheckignorenums'] = 'تجاÙ٠اÙÙÙ٠ات Ø§ÙØªÙ ØªØØªÙÙ Ø£Ø±ÙØ§Ù '; +$labels['spellcheckignorecaps'] = 'تجاÙ٠اÙÙÙ٠ات Ø§ÙØªÙ Ø¨ÙØ§ Ø£ØØ±Ù ÙØ¨Ùرة'; +$labels['addtodict'] = 'Ø¥Ø¶Ø§ÙØ© Ø¥Ù٠اÙÙØ§Ù س'; $labels['folder'] = 'Ù Ø¬ÙØ¯'; $labels['folders'] = 'Ù Ø¬ÙØ¯Ø§Øª'; $labels['foldername'] = 'اس٠اÙÙ Ø¬ÙØ¯'; @@ -391,6 +406,11 @@ $labels['sortby'] = 'ØªØ±ØªÙØ¨ Ø¨ØØ³Ø¨'; $labels['sortasc'] = 'ØªØ±ØªÙØ¨ تصاعدÙ'; $labels['sortdesc'] = 'ØªØ±ØªÙØ¨ ØªÙØ§Ø²ÙÙ'; $labels['undo'] = 'تراجع'; +$labels['plugin'] = 'Ø¥Ø¶Ø§ÙØ©'; +$labels['version'] = 'اÙÙØ³Ø®Ø©'; +$labels['source'] = 'اÙ٠صدر'; +$labels['license'] = 'Ø§ÙØªØ±Ø®Ùص'; +$labels['support'] = 'Ø§ØØµÙ عÙÙ Ø§ÙØ¯Ø¹Ù اÙÙÙÙ'; $labels['B'] = 'ب'; $labels['KB'] = 'Ù.ب'; $labels['MB'] = 'Ù .ب'; diff --git a/program/localization/ar_SA/messages.inc b/program/localization/ar_SA/messages.inc index 8678cc2..8215d33 100644 --- a/program/localization/ar_SA/messages.inc +++ b/program/localization/ar_SA/messages.inc @@ -13,7 +13,7 @@ | Author: Ossama Khayat <okhayat@yahoo.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -24,7 +24,7 @@ $messages['sessionerror'] = 'Ø§ÙØªÙت ØµÙØ§ØÙØ© Ø§ÙØ¬Ùسة Ø§ÙØØ§ÙÙØ© $messages['imaperror'] = 'ÙØ´Ù Ø§ÙØ§ØªØµØ§Ù بخاد٠IMAP'; $messages['servererror'] = 'خطأ ÙÙ Ø§ÙØ®Ø§Ø¯Ù !'; $messages['servererrormsg'] = 'خطأ خاد٠: $msg'; -$messages['databaserror'] = 'خطأ ÙÙ ÙØ§Ø¹Ø¯Ø© Ø§ÙØ¨ÙØ§ÙØ§Øª!'; +$messages['dberror'] = 'خطأ ÙÙ ÙØ§Ø¹Ø¯Ø© Ø§ÙØ¨ÙØ§ÙØ§Øª!'; $messages['errorreadonly'] = 'تعذر تÙÙÙØ° Ø§ÙØ¹Ù ÙÙØ©. اÙÙ Ø¬ÙØ¯ ÙÙÙØ±Ø§Ø¡Ø© ÙÙØ·.'; $messages['errornoperm'] = 'تعذر تÙÙÙØ° Ø§ÙØ¹Ù ÙÙØ©. ÙÙØ³Øª ÙØ¯ÙÙ Ø§ÙØµÙاØÙØ©.'; $messages['invalidrequest'] = 'Ø·ÙØ¨ ØºÙØ± ØµØ§ÙØ! Ù٠تØÙظ Ø£ÙØ© Ø¨ÙØ§Ùات.'; @@ -48,6 +48,7 @@ $messages['blockedimages'] = 'ÙØÙ Ø§ÙØ© Ø®ØµÙØµÙØªÙØ ØªÙ ØØ¬Ø¨ Ø§ÙØµÙ $messages['encryptedmessage'] = 'ÙØ°Ù Ø§ÙØ±Ø³Ø§ÙØ© Ù Ø´ÙØ±Ø© ÙÙØ§ ÙÙ ÙÙ Ø¹Ø±Ø¶ÙØ§. عذراÙ!'; $messages['nocontactsfound'] = 'ÙÙ ÙØ¹Ø«Ø± عÙ٠أ٠٠راسÙ'; $messages['contactnotfound'] = 'تعذر Ø§ÙØ¹Ø«Ùر عÙ٠اÙ٠راس٠اÙÙ Ø·ÙÙØ¨'; +$messages['contactsearchonly'] = 'Ø§ÙØªØ¨ بعض ÙÙ٠ات Ø§ÙØ¨ØØ« ÙÙØ¹Ø«Ùر عÙ٠اÙÙ ÙØ±Ø§Ø³ÙÙÙ'; $messages['sendingfailed'] = 'ÙØ´Ù Ø¥Ø±Ø³Ø§Ù Ø§ÙØ±Ø³Ø§ÙØ©'; $messages['senttooquickly'] = 'رجاء Ø§ÙØªØ¸Ø± $sec Ø«ÙØ§Ù ÙØ¨Ù Ø¥Ø±Ø³Ø§Ù ÙØ°Ù Ø§ÙØ±Ø³Ø§ÙØ©'; $messages['errorsavingsent'] = 'ØØ¯Ø« خطأ Ø£Ø«ÙØ§Ø¡ ØÙظ Ø§ÙØ±Ø³Ø§ÙØ© اÙÙ ÙØ±Ø³ÙØ©'; @@ -61,6 +62,7 @@ $messages['deletegroupconfirm'] = 'ÙÙ ØªØ±ÙØ¯ ÙØ¹ÙØ§Ù ØØ°Ù اÙ٠ج٠٠$messages['deletemessagesconfirm'] = 'ÙÙ ØªØ±ÙØ¯ ØØ°Ù Ø§ÙØ±Ø³Ø§Ø¦Ù اÙÙ ØØ¯Ø¯Ø©Ø'; $messages['deletefolderconfirm'] = 'ÙÙ ØªØ±ÙØ¯ ØÙØ§Ù ØØ°Ù ÙØ°Ø§ اÙÙ Ø¬ÙØ¯Ø'; $messages['purgefolderconfirm'] = 'ÙÙ ØªØ±ÙØ¯ ØÙØ§Ù ØØ°Ù Ø¬Ù ÙØ¹ Ø§ÙØ±Ø³Ø§Ø¦Ù ÙÙ ÙØ°Ø§ اÙÙ Ø¬ÙØ¯Ø'; +$messages['contactdeleting'] = 'Ø¬Ø§Ø±Ù ØØ°Ù اÙÙ ÙØ±Ø§Ø³ÙÙÙ...'; $messages['groupdeleting'] = 'Ø¬Ø§Ø±Ù ØØ°Ù اÙÙ Ø¬Ù ÙØ¹Ø©...'; $messages['folderdeleting'] = 'Ø¬Ø§Ø±Ù ØØ°Ù اÙÙ Ø¬ÙØ¯...'; $messages['foldermoving'] = 'جار٠ÙÙ٠اÙÙ Ø¬ÙØ¯...'; @@ -76,10 +78,10 @@ $messages['nosubjectwarning'] = 'ØÙÙ \"اÙÙ ÙØ¶Ùع\" ÙØ§Ø±Øº. Ù٠تر٠$messages['nobodywarning'] = 'Ø¥Ø±Ø³Ø§Ù ÙØ°Ù Ø§ÙØ±Ø³Ø§ÙØ© دÙÙ ÙØµØ'; $messages['notsentwarning'] = 'ÙÙ ÙØªÙ Ø¥Ø±Ø³Ø§Ù Ø§ÙØ±Ø³Ø§ÙØ©. ÙÙ ØªØ±ÙØ¯ تجاÙÙ Ø§ÙØ±Ø³Ø§ÙØ©Ø'; $messages['noldapserver'] = 'Ø§ÙØ±Ø¬Ø§Ø¡ Ø§Ø®ØªÙØ§Ø± خاد٠ldap ÙÙØ¨ØØ« ÙÙÙ'; -$messages['nocontactsreturned'] = 'ÙÙ ÙØ¹Ø«Ø± عÙ٠أ٠٠راسÙÙÙ'; $messages['nosearchname'] = 'Ø§ÙØ±Ø¬Ø§Ø¡ إدخا٠اس٠٠راس٠أ٠عÙÙØ§Ù Ø¨Ø±ÙØ¯ Ø¥ÙÙØªØ±ÙÙÙ'; $messages['notuploadedwarning'] = 'ÙÙ ÙØªÙ Ø±ÙØ¹ Ø¬Ù ÙØ¹ اÙ٠رÙÙØ§Øª بعد. Ø±Ø¬Ø§Ø¡Ù Ø§ÙØ§Ùتظار Ø£Ù Ø¥ÙØºØ§Ø¡ ع٠ÙÙØ© Ø§ÙØ±Ùع.'; $messages['searchsuccessful'] = 'عثر عÙÙ $nr رسائÙ'; +$messages['contactsearchsuccessful'] = 'Ø¹ÙØ«Ø± عÙÙ $nr Ù ÙØ±Ø§Ø³ÙÙ'; $messages['searchnomatch'] = 'ÙÙ ÙØ¹Ø«Ø± عÙÙ Ø´ÙØ¡'; $messages['searching'] = 'Ø¬Ø§Ø±Ù Ø§ÙØ¨ØØ«...'; $messages['checking'] = 'Ø¬Ø§Ø±Ù Ø§ÙØªØÙÙ...'; @@ -126,7 +128,6 @@ $messages['smtpautherror'] = 'خطأ SMTP ($code): تعذر Ø§ÙØªØÙÙ Ù Ù Ù $messages['smtpfromerror'] = 'خطأ SMTP ($code): تعذر ØªØØ¯Ùد اÙ٠رس٠"$from" ($msg)'; $messages['smtptoerror'] = 'خطأ SMTP ($code): تعذرت Ø¥Ø¶Ø§ÙØ© اÙ٠ستÙÙ "$to" ($msg)'; $messages['smtprecipientserror'] = 'خطأ SMTP: تعذرت ÙØ±Ø§Ø¡Ø© ÙØ§Ø¦Ù Ø© اÙ٠رس٠إÙÙÙÙ '; -$messages['smtpdsnerror'] = 'خطأ SMTP: ÙØ§ ÙÙØ¬Ø¯ Ø¯Ø¹Ù ÙØªÙÙÙÙØ§Øª ØØ§ÙØ© Ø§ÙØªÙصÙÙ'; $messages['smtperror'] = 'خطأ SMTP: $msg'; $messages['emailformaterror'] = 'عÙÙØ§Ù Ø¨Ø±ÙØ¯ Ø¥ÙÙØªØ±ÙÙÙ ØºÙØ± ØµØ§ÙØ: $email'; $messages['toomanyrecipients'] = 'عدد اÙ٠رس٠إÙÙÙÙ ÙØ¨Ùر. ÙÙØµ Ø§ÙØ¹Ø¯Ø¯ Ø¥ÙÙ $max.'; @@ -139,11 +140,16 @@ $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['autocompletemore'] = 'ÙÙØ§Ù اÙÙ Ø²ÙØ¯ ٠٠اÙÙØªØ§Ø¦Ø¬ اÙÙ Ø·Ø§Ø¨ÙØ©. رجاء Ø§ÙØªØ¨ ÙÙ٠ات Ø¨ØØ« Ø£ÙØ«Ø±.'; $messages['namecannotbeempty'] = 'ÙØ§ ÙÙ ÙÙ ØªØ±Ù Ø§ÙØ¥Ø³Ù ÙØ§Ø±ØºØ§Ù'; $messages['nametoolong'] = 'Ø§ÙØ¥Ø³Ù Ø·ÙÙ٠جداÙ'; $messages['folderupdated'] = 'ØªÙ ØªØØ¯ÙØ« اÙÙ Ø¬ÙØ¯ Ø¨ÙØ¬Ø§Ø'; @@ -151,5 +157,6 @@ $messages['foldercreated'] = 'ØªÙ Ø¥ÙØ´Ø§Ø¡ اÙÙ Ø¬ÙØ¯ Ø¨ÙØ¬Ø§Ø'; $messages['invalidimageformat'] = 'ÙÙØ³Øª ØµÙØºØ© ØµÙØ±Ø© صØÙØØ©'; $messages['mispellingsfound'] = 'Ø¹ÙØ«Ø± عÙ٠أخطاء Ø¥Ù ÙØ§Ø¦ÙØ© ÙÙ Ø§ÙØ±Ø³Ø§ÙØ©'; $messages['parentnotwritable'] = 'تعذر Ø¥ÙØ´Ø§Ø¡/ÙÙ٠اÙÙ Ø¬ÙØ¯ Ø¥Ù٠اÙÙ Ø¬ÙØ¯ اÙÙ ØØ¯Ø¯. ÙÙØ³Øª ÙØ¯ÙÙ Ø§ÙØµÙاØÙØ©.'; +$messages['messagetoobig'] = 'جزء Ø§ÙØ±Ø³Ø§ÙØ© Ø£ÙØ¨Ø± Ø¨ÙØ«Ùر ٠٠ا ÙÙ ÙÙ Ù Ø¹Ø§ÙØ¬ØªÙ.'; ?> diff --git a/program/localization/bg_BG/labels.inc b/program/localization/bg_BG/labels.inc index da8c9c3..dffa2c6 100644 --- a/program/localization/bg_BG/labels.inc +++ b/program/localization/bg_BG/labels.inc @@ -14,7 +14,7 @@ | Nickolay Bunev <just4nick@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4463 2011-01-28 16:03:31Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -101,18 +101,16 @@ $labels['replytomessage'] = 'ÐÑговоÑи на пиÑмоÑо'; $labels['replytoallmessage'] = 'ÐÑÐ³Ð¾Ð²Ð¾Ñ Ð´Ð¾ изпÑаÑаÑа и вÑиÑки полÑÑаÑели'; $labels['replyall'] = 'ÐÑÐ³Ð¾Ð²Ð¾Ñ Ð½Ð° вÑиÑки'; $labels['replylist'] = 'СпиÑÑк за оÑговоÑ'; +$labels['forwardinline'] = 'ÐÑепÑаÑи каÑо ÑаÑÑ Ð¾Ñ ÑÑобÑениеÑо'; +$labels['forwardattachment'] = 'ÐÑепÑаÑи каÑо пÑикаÑен Ñайл'; $labels['forwardmessage'] = 'ÐÑепÑаÑи пиÑмоÑо'; $labels['deletemessage'] = 'ÐзÑÑий пиÑмоÑо'; $labels['movemessagetotrash'] = 'ÐÑемеÑÑи пиÑмоÑо в коÑÑеÑо'; $labels['printmessage'] = 'РазпеÑаÑай пиÑмоÑо'; $labels['previousmessage'] = 'ÐÑедиÑно пиÑмо'; -$labels['previousmessages'] = 'ÐÑедиÑна ÑÑÑаниÑа'; $labels['firstmessage'] = 'ÐÑÑво пиÑмо'; -$labels['firstmessages'] = 'ÐÑÑва ÑÑÑаниÑа'; $labels['nextmessage'] = 'СледваÑо пиÑмо'; -$labels['nextmessages'] = 'СледваÑа ÑÑÑаниÑа'; $labels['lastmessage'] = 'ÐоÑледно пиÑмо'; -$labels['lastmessages'] = 'ÐоÑледна ÑÑÑаниÑа'; $labels['backtolist'] = 'ÐбÑаÑно кÑм ÑпиÑÑка'; $labels['viewsource'] = 'Ðиж каÑо код'; $labels['markmessages'] = 'ÐаÑкиÑай пиÑмаÑа'; @@ -120,7 +118,7 @@ $labels['markread'] = 'ÐаÑо пÑоÑеÑени'; $labels['markunread'] = 'ÐаÑо нови'; $labels['markflagged'] = 'ÐаÑо оÑбелÑзани'; $labels['markunflagged'] = 'ÐаÑо неоÑбелÑзани'; -$labels['messageactions'] = 'ÐÑе дейÑÑвиÑ'; +$labels['moreactions'] = 'ÐовеÑе дейÑÑвиÑ...'; $labels['select'] = 'ÐзбеÑи'; $labels['all'] = 'ÐÑиÑки'; $labels['none'] = 'ÐиÑо'; @@ -152,7 +150,7 @@ $labels['listcolumns'] = 'Ðолони за ÑпиÑÑк'; $labels['listsorting'] = 'Ðолона за ÑоÑÑиÑане'; $labels['listorder'] = 'Режим на ÑоÑÑиÑане'; $labels['listmode'] = 'ÐÑаÑÑк ÑпиÑÑк'; -$labels['folderactions'] = 'ÐеÑйÑÐ²Ð¸Ñ Ð·Ð° папки...'; +$labels['folderactions'] = 'ÐейÑÑÐ²Ð¸Ñ Ð·Ð° папки...'; $labels['compact'] = 'Свий'; $labels['empty'] = 'ÐзпÑазни'; $labels['quota'] = 'Ðзползвано мÑÑÑо'; @@ -173,12 +171,15 @@ $labels['charset'] = 'ÐодиÑовка'; $labels['editortype'] = 'Ðид ÑедакÑоÑ'; $labels['returnreceipt'] = 'ÐбÑаÑна ÑазпиÑка'; $labels['dsn'] = 'ÐнÑоÑмиÑане пÑи доÑÑавка'; +$labels['mailreplyintro'] = 'Ðа $date, $sender напиÑа:'; +$labels['originalmessage'] = 'ÐÑÑвонаÑалноÑо ÑÑобÑение'; $labels['editidents'] = 'РедакÑиÑане на ÑамолиÑноÑÑи'; $labels['checkspelling'] = 'ÐÑовеÑи пÑавопиÑа'; $labels['resumeediting'] = 'ÐÑодÑлжи ÑеÑноваÑа'; $labels['revertto'] = 'ÐÑÑни Ñе кÑм'; $labels['attachments'] = 'ÐÑикаÑени Ñайлове'; $labels['upload'] = 'ÐаÑи'; +$labels['uploadprogress'] = '$percent ($current Ð¾Ñ $total)'; $labels['close'] = 'ÐаÑвоÑи'; $labels['messageoptions'] = 'ÐаÑÑÑойки на ÑÑобÑениÑ...'; $labels['low'] = 'ÐиÑÑк'; @@ -189,6 +190,7 @@ $labels['highest'] = 'Ðай-виÑок'; $labels['nosubject'] = '(нÑма заглавие)'; $labels['showimages'] = 'Ðоказвай изобÑажениÑ'; $labels['alwaysshow'] = 'Ðинаги показвай изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ $ '; +$labels['isdraft'] = 'Това ÑÑобÑение е ÑеÑнова'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'ÑекÑÑов'; $labels['savesentmessagein'] = 'Ðапази ÑÑобÑениеÑо в'; @@ -231,6 +233,24 @@ $labels['female'] = 'Ðена'; $labels['manager'] = 'ÐениджÑÑ'; $labels['assistant'] = 'ÐÑиÑÑенÑ'; $labels['spouse'] = 'СÑпÑÑг (а)'; +$labels['allfields'] = 'ÐÑиÑки полеÑа'; +$labels['search'] = 'ТÑÑÑене'; +$labels['advsearch'] = 'РазÑиÑено ÑÑÑÑене'; +$labels['other'] = 'ÐÑÑги'; +$labels['typehome'] = 'ÐаÑало'; +$labels['typework'] = 'РабоÑа'; +$labels['typeother'] = 'ÐÑÑги'; +$labels['typemobile'] = 'Ðобилни'; +$labels['typemain'] = 'Ðлавни'; +$labels['typehomefax'] = 'ÐомаÑен ÑакÑ'; +$labels['typeworkfax'] = 'СлÑжебен ÑакÑ'; +$labels['typecar'] = 'ÐвÑомобил'; +$labels['typepager'] = 'ÐейджÑÑ'; +$labels['typevideo'] = 'Ðидео'; +$labels['typeassistant'] = 'ÐÑиÑÑенÑ'; +$labels['typehomepage'] = 'ÐаÑална ÑÑÑаниÑа'; +$labels['typeblog'] = 'Ðлог'; +$labels['typeprofile'] = 'ÐÑоÑил'; $labels['addfield'] = 'Ðобави поле'; $labels['addcontact'] = 'Ðобави'; $labels['editcontact'] = 'РедакÑиÑай'; @@ -252,7 +272,8 @@ $labels['print'] = 'РазпеÑаÑай'; $labels['export'] = 'ÐзнаÑÑне'; $labels['exportvcards'] = 'ÐзнаÑÑне вÑв vCard ÑоÑмаÑ'; $labels['newcontactgroup'] = 'СÑздаване на нова гÑÑпа'; -$labels['groupactions'] = 'ÐейÑÑÐ²Ð¸Ñ Ð·Ð° гÑÑпи Ð¾Ñ ÐºÐ¾Ð½ÑакÑи...'; +$labels['grouprename'] = 'ÐÑеименÑвай гÑÑпа'; +$labels['groupdelete'] = 'ÐзÑÑиване на гÑÑпа'; $labels['previouspage'] = 'ÐÑедна ÑÑÑаниÑа'; $labels['firstpage'] = 'ÐÑÑва ÑÑÑаниÑа'; $labels['nextpage'] = 'СледваÑа ÑÑÑаниÑа'; @@ -260,9 +281,12 @@ $labels['lastpage'] = 'ÐоÑледна ÑÑÑаниÑа'; $labels['group'] = 'ÐÑÑпа'; $labels['groups'] = 'ÐÑÑпи'; $labels['personaladrbook'] = 'ÐиÑни адÑеÑи'; +$labels['searchsave'] = 'Ðапази ÑÑÑÑенеÑо'; +$labels['searchdelete'] = 'ÐзÑÑий ÑÑÑÑенеÑо'; $labels['import'] = 'ÐнаÑÑне'; $labels['importcontacts'] = 'ÐнаÑÑне'; $labels['importfromfile'] = 'ÐнаÑÑне Ð¾Ñ Ñайл'; +$labels['importtarget'] = 'Ðобави нови конÑакÑи в книгаÑа Ñ Ð°Ð´ÑеÑи'; $labels['importreplace'] = 'Ðамени ÑÑлаÑа книга Ñ Ð°Ð´ÑеÑи'; $labels['importtext'] = 'ÐожеÑе да внеÑеÑе конÑакÑи Ð¾Ñ ÑÑÑеÑÑвÑваÑа книга Ñ Ð°Ð´ÑеÑи. РмоменÑа поддÑÑжане внаÑÑнеÑо на адÑеÑи Ð¾Ñ vCard ÑоÑÐ¼Ð°Ñ Ð·Ð° данни.'; $labels['done'] = 'ÐзвÑÑÑено'; @@ -278,6 +302,8 @@ $labels['edititem'] = 'РедакÑиÑане на ÑамолиÑноÑÑ'; $labels['preferhtml'] = 'Ðоказвай пÑÑво HTML веÑÑиÑ'; $labels['defaultcharset'] = 'ÐодÑазбиÑаÑо Ñе кодиÑане'; $labels['htmlmessage'] = 'HTML ÑÑобÑение'; +$labels['dateformat'] = 'ФоÑÐ¼Ð°Ñ Ð½Ð° даÑаÑа'; +$labels['timeformat'] = 'ФоÑÐ¼Ð°Ñ Ð½Ð° вÑемеÑо'; $labels['prettydate'] = 'ÐÑаÑки даÑи'; $labels['setdefault'] = 'Ðо подÑазбиÑане'; $labels['autodetect'] = 'ÐвÑомаÑиÑно'; @@ -348,6 +374,14 @@ $labels['afternseconds'] = 'Ñлед $n ÑекÑнди'; $labels['reqmdn'] = 'Ðинаги вÑÑÑай обÑаÑна ÑазпиÑка'; $labels['reqdsn'] = 'Ðинаги изиÑквай оÑÐ³Ð¾Ð²Ð¾Ñ Ð¿Ñи доÑÑавка на ÑÑобÑение'; $labels['replysamefolder'] = 'ÐоÑÑави оÑговоÑа в папкаÑа на ÑÑобÑениеÑо, на коеÑо Ñе оÑговаÑÑ'; +$labels['defaultaddressbook'] = 'Ðобави нови конÑакÑи в избÑанаÑа книга Ñ Ð°Ð´ÑеÑи'; +$labels['autocompletesingle'] = 'ÐÑопÑÑни алÑеÑнаÑивниÑе email адÑеÑи пÑи авÑомаÑиÑно попÑлване'; +$labels['spellcheckbeforesend'] = 'ÐÑовеÑи за пÑавопиÑни гÑеÑки пÑеди изпÑаÑане на ÑÑобÑениеÑо'; +$labels['spellcheckoptions'] = 'ÐаÑÑÑойки на пÑовеÑкаÑа за пÑавопиÑ'; +$labels['spellcheckignoresyms'] = 'ÐгноÑиÑай дÑми ÑÑдÑÑжаÑи Ñимволи'; +$labels['spellcheckignorenums'] = 'ÐгноÑиÑай дÑми ÑÑдÑÑжаÑи ÑиÑла'; +$labels['spellcheckignorecaps'] = 'ÐгноÑиÑай дÑми ÑÑдÑÑжаÑи единÑÑвено главни бÑкви'; +$labels['addtodict'] = 'Ðобави в ÑеÑника'; $labels['folder'] = 'Ðапка'; $labels['folders'] = 'Ðапки'; $labels['foldername'] = 'Ðме на папкаÑа'; @@ -364,9 +398,14 @@ $labels['location'] = 'ÐеÑÑоположение'; $labels['info'] = 'ÐнÑоÑмаÑиÑ'; $labels['getfoldersize'] = 'ЩÑакни за големина на папкаÑа'; $labels['changesubscription'] = 'ЩÑакни за пÑомÑна на абонаменÑ'; +$labels['foldertype'] = 'Ðид на папкаÑа'; +$labels['personalfolder'] = 'ÐиÑна папка'; +$labels['otherfolder'] = 'Ðапка на дÑÑг поÑÑебиÑел'; +$labels['sharedfolder'] = 'ÐÑблиÑна папка'; $labels['sortby'] = 'СоÑÑиÑай по'; $labels['sortasc'] = 'СоÑÑиÑай вÑÐ·Ñ Ð¾Ð´ÑÑо'; $labels['sortdesc'] = 'СоÑÑиÑай Ð½Ð¸Ð·Ñ Ð¾Ð´ÑÑо'; +$labels['undo'] = 'ÐÑмени'; $labels['B'] = 'Ð'; $labels['KB'] = 'ÐÐ'; $labels['MB'] = 'ÐÐ'; diff --git a/program/localization/bg_BG/messages.inc b/program/localization/bg_BG/messages.inc index a23a63c..17eb50c 100644 --- a/program/localization/bg_BG/messages.inc +++ b/program/localization/bg_BG/messages.inc @@ -14,7 +14,7 @@ | Nickolay Bunev <just4nick@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 4463 2011-01-28 16:03:31Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -25,6 +25,7 @@ $messages['sessionerror'] = 'Ðевалидна или изÑекла ÑеÑÐ¸Ñ $messages['imaperror'] = 'ÐеÑÑпеÑно ÑвÑÑзване кÑм IMAP ÑÑÑвÑÑа'; $messages['servererror'] = 'ÐÑеÑка!'; $messages['servererrormsg'] = 'СÑÑвÑÑна гÑеÑка: $msg'; +$messages['dberror'] = 'ÐÑеÑка Ñ Ð±Ð°Ð·Ð°Ñа данни!'; $messages['errorreadonly'] = 'ÐпеÑаÑиÑÑа не може да бÑде изпÑлнена. ÐапкаÑа е Ñ Ð¿Ñава Ñамо за ÑеÑене'; $messages['errornoperm'] = 'ÐпеÑаÑиÑÑа не може да бÑде изпÑлнена. ÐÑказани пÑава за доÑÑÑп'; $messages['invalidrequest'] = 'Ðевалидна заÑвка! ÐанниÑе не Ñа ÑÑÑ Ñанени.'; @@ -33,6 +34,7 @@ $messages['loggedout'] = 'Ðовиждане!'; $messages['mailboxempty'] = 'ÐÑÑиÑÑа е пÑазна'; $messages['loading'] = 'ÐаÑеждане...'; $messages['uploading'] = 'ÐаÑване на Ñайла...'; +$messages['uploadingmany'] = 'ÐаÑване на Ñайлове...'; $messages['loadingdata'] = 'ÐаÑеждане на данни...'; $messages['checkingmail'] = 'ÐÑовеÑка за нови пиÑма...'; $messages['sendingmessage'] = 'ÐзпÑаÑане на пиÑмоÑо...'; @@ -42,10 +44,12 @@ $messages['messagesaved'] = 'ÐиÑмоÑо е запиÑано в ЧеÑнов $messages['successfullysaved'] = 'ÐапиÑано'; $messages['addedsuccessfully'] = 'ÐонÑакÑа е добавен в адÑеÑнаÑа книга'; $messages['contactexists'] = 'ÐонÑÐ°ÐºÑ Ñ Ñози e-mail адÑÐµÑ Ð²ÐµÑе ÑÑÑеÑÑÑва'; +$messages['contactnameexists'] = 'ÐонÑÐ°ÐºÑ ÑÑÑ ÑÑÑоÑо име веÑе ÑÑÑеÑÑвÑва'; $messages['blockedimages'] = 'С оглед на ÐаÑаÑа ÑигÑÑноÑÑ, изобÑажениÑÑа в Ñова пиÑмо Ñа блокиÑани.'; $messages['encryptedmessage'] = 'Това е кодиÑано пиÑмо и не може да бÑде показано. СÑжалÑваме!'; -$messages['nocontactsfound'] = 'ÐÑма конÑакÑи'; +$messages['nocontactsfound'] = 'ÐÑма намеÑени конÑакÑи'; $messages['contactnotfound'] = 'ÐÑканиÑÑ ÐºÐ¾Ð½ÑÐ°ÐºÑ Ð½Ðµ е намеÑен'; +$messages['contactsearchonly'] = 'ÐÑведеÑе неÑо в полеÑо за ÑÑÑÑене за да ÑÑÑÑиÑе конÑакÑи'; $messages['sendingfailed'] = 'ÐзпÑаÑанеÑо неÑÑпеÑно'; $messages['senttooquickly'] = 'ÐолÑ, изÑакайÑе $sec ÑекÑнда(и) пÑеди да изпÑаÑиÑе ÑÑобÑениеÑо'; $messages['errorsavingsent'] = 'ÐÑзникна гÑеÑка пÑи запиÑванеÑо на ÑÑобÑениеÑо'; @@ -55,9 +59,12 @@ $messages['errorcopying'] = 'СÑобÑениÑÑа не Ð¼Ð¾Ð³Ð°Ñ Ð´Ð° бÑд $messages['errordeleting'] = 'ÐиÑмоÑо не може да бÑде изÑÑиÑо'; $messages['errormarking'] = 'СÑобÑениеÑо не може да бÑде маÑкиÑано'; $messages['deletecontactconfirm'] = 'ÐÑкаÑе ли да изÑÑиеÑе маÑкиÑаниÑе конÑакÑи?'; +$messages['deletegroupconfirm'] = 'ÐÑкаÑе ли да изÑÑиеÑе избÑанаÑа гÑÑпа?'; $messages['deletemessagesconfirm'] = 'ÐÑкаÑе ли да изÑÑиеÑе маÑкиÑаниÑе ÑÑобÑениÑ?'; $messages['deletefolderconfirm'] = 'ÐÑкаÑе ли да изÑÑиеÑе Ñази папка?'; $messages['purgefolderconfirm'] = 'ÐÑкаÑе ли да изÑÑиеÑе вÑиÑки пиÑма в Ñази папка?'; +$messages['contactdeleting'] = 'ÐзÑÑиване на конÑакÑ(и)...'; +$messages['groupdeleting'] = 'ÐзÑÑиване на гÑÑпа...'; $messages['folderdeleting'] = 'ÐзÑÑиване на папка...'; $messages['foldermoving'] = 'ÐÑемеÑÑване на папка...'; $messages['foldersubscribing'] = 'ÐбониÑане...'; @@ -72,10 +79,10 @@ $messages['nosubjectwarning'] = 'ÐолеÑо "Ðаглавие" е пÑазно $messages['nobodywarning'] = 'ÐзпÑаÑи Ñова пиÑмо без ÑекÑÑ?'; $messages['notsentwarning'] = 'ÐиÑмоÑо не е изпÑаÑено. ÐÑкаÑе ли да бÑде ÑниÑожено?'; $messages['noldapserver'] = 'ÐзбеÑеÑе LDAP ÑÑÑвÑÑ Ð·Ð° ÑÑÑÑене'; -$messages['nocontactsreturned'] = 'Ðе Ñа намеÑени конÑакÑи'; $messages['nosearchname'] = 'ÐолÑ, вÑведеÑе Ðме на конÑакÑа или e-mail адÑеÑ'; $messages['notuploadedwarning'] = 'ÐÑе оÑе не Ñа каÑени вÑиÑки пÑикаÑени Ñайлове. ÐÐ¾Ð»Ñ Ð¸Ð·ÑакайÑе или оÑкажеÑе каÑванеÑо.'; $messages['searchsuccessful'] = '$nr намеÑени пиÑма'; +$messages['contactsearchsuccessful'] = '$nr намеÑени конÑакÑи.'; $messages['searchnomatch'] = 'ТÑÑÑенеÑо не оÑкÑи ÑÑвпадениÑ'; $messages['searching'] = 'ТÑÑÑене...'; $messages['checking'] = 'ÐÑовеÑка...'; @@ -94,10 +101,13 @@ $messages['copysuccess'] = 'УÑпеÑно копиÑани $nr адÑеÑа'; $messages['copyerror'] = 'ÐÑеÑка пÑи копиÑанеÑо на адÑеÑиÑе'; $messages['sourceisreadonly'] = 'Този изÑоÑник на адÑеÑи е Ñамо за ÑеÑене'; $messages['errorsavingcontact'] = 'ÐÑеÑка пÑи запиÑванеÑо на адÑеÑа'; -$messages['movingmessage'] = 'ÐÑемеÑÑване на пиÑмоÑо...'; -$messages['copyingmessage'] = 'ÐопиÑане на ÑÑобÑение...'; -$messages['deletingmessage'] = 'ÐзÑÑиване на ÑÑобÑение'; -$messages['markingmessage'] = 'ÐаÑкиÑане на ÑÑобÑение'; +$messages['movingmessage'] = 'ÐÑемеÑÑване на ÑÑобÑение...'; +$messages['copyingmessage'] = 'ÐопиÑане на ÑÑобÑение(Ñ)...'; +$messages['copyingcontact'] = 'ÐопиÑане на конÑакÑ(и)...'; +$messages['deletingmessage'] = 'ÐзÑÑиване на ÑÑобÑение(Ñ)...'; +$messages['markingmessage'] = 'ÐаÑкиÑане на ÑÑобÑение(Ñ)...'; +$messages['addingmember'] = 'ÐобавÑне на конÑакÑ(и) в гÑÑпаÑа...'; +$messages['removingmember'] = 'ÐÑÐµÐ¼Ð°Ñ Ð²Ð°Ð½Ðµ на конÑакÑ(и) Ð¾Ñ Ð³ÑÑпаÑа...'; $messages['receiptsent'] = 'ÐбÑаÑнаÑа ÑазпиÑка е изпÑаÑена.'; $messages['errorsendingreceipt'] = 'ÐÑеÑка пÑи изпÑаÑанеÑо на обÑаÑна ÑазпиÑка.'; $messages['nodeletelastidentity'] = 'Ðе можеÑе да изÑÑиеÑе Ñази ÑамолиÑноÑÑ, ÑÑÑбва да имаÑе поне една.'; @@ -109,6 +119,7 @@ $messages['contactremovedfromgroup'] = 'ÐонÑакÑиÑе бÑÑ Ð° ÑÑÐ¿ÐµÑ $messages['importwait'] = 'ÐнаÑÑне, Ð¼Ð¾Ð»Ñ Ð¸Ð·ÑакайÑе...'; $messages['importerror'] = 'ÐнаÑÑнеÑо неÑÑпеÑно! ÐаÑениÑÑ Ñайл не е вÑв валиден vCard ÑоÑмаÑ.'; $messages['importconfirm'] = '<b>УÑпеÑно Ñа внеÑени $inserted конÑакÑа, веÑе ÑÑÑеÑÑвÑваÑиÑе $skipped конÑакÑа Ñа пÑопÑÑнаÑи</b>:<p><em>$names</em></p>'; +$messages['importconfirmskipped'] = 'b>СÑÑеÑÑвÑваÑиÑе запиÑи $skipped Ñа пÑопÑÑнаÑи</b>'; $messages['opnotpermitted'] = 'ÐпеÑаÑиÑÑа не е позволена!'; $messages['nofromaddress'] = 'ÐипÑва e-mail адÑÐµÑ Ð·Ð° избÑанаÑа ÑамолиÑноÑÑ'; $messages['editorwarning'] = 'ÐÑевклÑÑванеÑо на ÑедакÑоÑа в ÑекÑÑов Ñежим Ñе доведе до загÑба на ÑоÑмаÑиÑанеÑо на ÑекÑа. СигÑÑни ли ÑÑе, Ñе иÑкаÑе да пÑодÑлжиÑе?'; @@ -118,7 +129,6 @@ $messages['smtpautherror'] = 'SMTP гÑеÑка ($code): ÐÑеÑни поÑÑе $messages['smtpfromerror'] = 'SMTP гÑеÑка ($code): Ðе може да бÑде изпÑаÑено пиÑмо Ð¾Ñ "$from" ($msg)'; $messages['smtptoerror'] = 'SMTP гÑеÑка ($code): Ðе може да бÑде изпÑаÑено пиÑмо до "$to" ($msg)'; $messages['smtprecipientserror'] = 'SMTP гÑеÑка: Ðе може да бÑде обÑабоÑен ÑпиÑÑка Ñ Ð¿Ð¾Ð»ÑÑаÑели'; -$messages['smtpdsnerror'] = 'SMTP гÑеÑка: Ðе Ñе поддÑÑжа ÑÑобÑаване за ÑÑпеÑни полÑÑено ÑÑобÑение'; $messages['smtperror'] = 'SMTP гÑеÑка: $msg'; $messages['emailformaterror'] = 'Ðевалиден e-mail адÑеÑ: $email'; $messages['toomanyrecipients'] = 'ÐÑекалено много адÑеÑи за изпÑаÑане (макÑимÑм: $max).'; @@ -126,18 +136,27 @@ $messages['maxgroupmembersreached'] = 'ÐÑÐ¾Ñ Ð½Ð° ÑленовеÑе на г $messages['internalerror'] = 'ÐÑзникна вÑÑÑеÑна гÑеÑка. ÐÐ¾Ð»Ñ Ð¾Ð¿Ð¸ÑайÑе оÑново'; $messages['contactdelerror'] = 'Ðе мога да изÑÑÐ¸Ñ ÐºÐ¾Ð½ÑакÑа'; $messages['contactdeleted'] = 'ÐонÑакÑÑÑ Ð±ÐµÑе изÑÑиÑ'; +$messages['contactrestoreerror'] = 'ÐеÑÑпеÑно вÑзÑÑановÑване на изÑÑиÑе конÑакÑ(и).'; +$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['autocompletemore'] = 'ÐамеÑениÑе ÑÑÐ²Ð¿Ð°Ð´ÐµÐ½Ð¸Ñ Ñа пÑекалено много. ÐÐ¾Ð»Ñ Ð½Ð°Ð¿Ð¸ÑеÑе оÑе Ñимволи.'; $messages['namecannotbeempty'] = 'ÐолеÑо за име не може да бÑде пÑазно'; $messages['nametoolong'] = 'ÐмеÑо е пÑекалено дÑлго'; $messages['folderupdated'] = 'ÐапкаÑа е обновена'; $messages['foldercreated'] = 'ÐапкаÑа е ÑÑздадена'; $messages['invalidimageformat'] = 'Ðевалиден ÑоÑÐ¼Ð°Ñ Ð½Ð° изобÑажениеÑо'; +$messages['mispellingsfound'] = 'Ð ÑÑобÑениеÑо Ñа намеÑени пÑавопиÑни гÑеÑки.'; +$messages['parentnotwritable'] = 'СÑздаванеÑо/пÑемеÑÑванеÑо на папка в избÑанаÑа ÑодиÑелÑка папка е неÑÑпеÑно. ÐÑма пÑава за доÑÑÑп.'; ?> diff --git a/program/localization/ca_ES/labels.inc b/program/localization/ca_ES/labels.inc index 3127dd0..d4d99db 100644 --- a/program/localization/ca_ES/labels.inc +++ b/program/localization/ca_ES/labels.inc @@ -15,7 +15,7 @@ | Jordi Sanfeliu <jordi@fibranet.cat> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/ca_ES/messages.inc b/program/localization/ca_ES/messages.inc index 30817b5..e7b3d29 100644 --- a/program/localization/ca_ES/messages.inc +++ b/program/localization/ca_ES/messages.inc @@ -15,7 +15,7 @@ | Jordi Sanfeliu <jordi@fibranet.cat> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: messages.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/cs_CZ/labels.inc b/program/localization/cs_CZ/labels.inc index f63271d..cf66e1b 100644 --- a/program/localization/cs_CZ/labels.inc +++ b/program/localization/cs_CZ/labels.inc @@ -17,7 +17,7 @@ | Ales Pospichal <ales@pospichalales.info> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -103,6 +103,8 @@ $labels['replytomessage'] = 'OdpovÄdÄt odesÃlateli'; $labels['replytoallmessage'] = 'OdpovÄdÄt vÅ¡em'; $labels['replyall'] = 'OdpovÄdÄt vÅ¡em'; $labels['replylist'] = 'OdpovÄdÄt do e-mailové konference'; +$labels['forwardinline'] = 'PÅeposlat v textu'; +$labels['forwardattachment'] = 'PÅeposlat jako pÅÃlohu'; $labels['forwardmessage'] = 'PÅedat zprávu'; $labels['deletemessage'] = 'Odstranit zprávu'; $labels['movemessagetotrash'] = 'PÅesunout zprávu do koÅ¡e'; @@ -118,7 +120,7 @@ $labels['markread'] = 'Jako pÅeÄtené'; $labels['markunread'] = 'Jako nepÅeÄtené'; $labels['markflagged'] = 'Jako oznaÄené'; $labels['markunflagged'] = 'Jako neoznaÄené'; -$labels['messageactions'] = 'Dalšà akce...'; +$labels['moreactions'] = 'Dalšà akce...'; $labels['select'] = 'Vybrat'; $labels['all'] = 'VÅ¡e'; $labels['none'] = 'Nic'; @@ -171,12 +173,15 @@ $labels['charset'] = 'Znaková sada'; $labels['editortype'] = 'Typ editoru zpráv'; $labels['returnreceipt'] = 'DoruÄenka'; $labels['dsn'] = 'Stav doruÄenÃ'; +$labels['mailreplyintro'] = 'Dne $date, $sender napsal:'; +$labels['originalmessage'] = 'Původnà zpráva'; $labels['editidents'] = 'Editovat identity'; $labels['checkspelling'] = 'Zkontrolovat pravopis'; $labels['resumeediting'] = 'PokraÄovat v úpravách'; $labels['revertto'] = 'PÅejÃt na'; $labels['attachments'] = 'PÅÃlohy'; $labels['upload'] = 'Nahrát'; +$labels['uploadprogress'] = '$percent ($current z $total)'; $labels['close'] = 'ZavÅÃt'; $labels['messageoptions'] = 'Nastavenà zprávy...'; $labels['low'] = 'NÃzká'; @@ -223,11 +228,16 @@ $labels['birthday'] = 'Datum narozenÃ'; $labels['anniversary'] = 'VýroÄÃ'; $labels['website'] = 'WWW'; $labels['instantmessenger'] = 'Komunikace (ICQ, messenger...)'; +$labels['notes'] = 'Poznámky'; $labels['male'] = 'Muž'; $labels['female'] = 'Žena'; $labels['manager'] = 'Manažer'; $labels['assistant'] = 'Asistent'; $labels['spouse'] = 'Manžel/ka'; +$labels['allfields'] = 'VÅ¡echny položky'; +$labels['search'] = 'Hledat'; +$labels['advsearch'] = 'PokroÄilé vyhledávánÃ'; +$labels['other'] = 'Jiné'; $labels['typehome'] = 'DomacÃ'; $labels['typework'] = 'PracovnÃ'; $labels['typeother'] = 'OstatnÃ'; @@ -239,6 +249,9 @@ $labels['typecar'] = 'Automobil'; $labels['typepager'] = 'Pager'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Asistent'; +$labels['typehomepage'] = 'Domácà stránka'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; $labels['addfield'] = 'PÅidat položku'; $labels['addcontact'] = 'PÅidat kontakt'; $labels['editcontact'] = 'Upravit kontakt'; @@ -260,7 +273,8 @@ $labels['print'] = 'Tisk'; $labels['export'] = 'Export'; $labels['exportvcards'] = 'Exportovat kontakty ve formátu vCard'; $labels['newcontactgroup'] = 'VytvoÅit novou skupinu kontaktů'; -$labels['groupactions'] = 'Akce pro skupiny kontaktů...'; +$labels['grouprename'] = 'PÅejmenovat skupinu'; +$labels['groupdelete'] = 'Smazat skupinu'; $labels['previouspage'] = 'PÅedchozÃ'; $labels['firstpage'] = 'Zobrazit prvnà zprávy'; $labels['nextpage'] = 'DalÅ¡Ã'; @@ -268,9 +282,12 @@ $labels['lastpage'] = 'Zobrazit poslednà zprávy'; $labels['group'] = 'Skupina'; $labels['groups'] = 'Skupiny'; $labels['personaladrbook'] = 'Osobnà kontakty'; +$labels['searchsave'] = 'Uložit hledánÃ'; +$labels['searchdelete'] = 'Smazat hledánÃ'; $labels['import'] = 'Import'; $labels['importcontacts'] = 'Importovat kontakty'; $labels['importfromfile'] = 'Importovat ze souboru'; +$labels['importtarget'] = 'PÅidat nové kontakty do seznamu kontaktů:'; $labels['importreplace'] = 'Nahradit celý seznam kontaktů'; $labels['importtext'] = 'Můžete nahrát kontakty z existujÃcÃho seznamu kontaktů. Podporujeme formát vCard.'; $labels['done'] = 'Hotovo'; @@ -286,6 +303,8 @@ $labels['edititem'] = 'Upravit položku'; $labels['preferhtml'] = 'UpÅednostÅovat HTML zobrazenÃ'; $labels['defaultcharset'] = 'Výchozà kódovánÃ'; $labels['htmlmessage'] = 'HTML zpráva'; +$labels['dateformat'] = 'Formát data'; +$labels['timeformat'] = 'Formát Äasu'; $labels['prettydate'] = 'HezÄà datum'; $labels['setdefault'] = 'Nastavit výchozÃ'; $labels['autodetect'] = 'Automaticky'; @@ -356,6 +375,13 @@ $labels['afternseconds'] = 'po $n sekundách'; $labels['reqmdn'] = 'Vždy požadovat doruÄenku'; $labels['reqdsn'] = 'Vždy požádat o oznámenà o stavu doruÄenÃ'; $labels['replysamefolder'] = 'Ukládat odpovÄdi ve stejné složce jako je zodpovÄzená zpráva'; +$labels['defaultaddressbook'] = 'PÅidávat nové kontakty do seznamu kontaktů'; +$labels['spellcheckbeforesend'] = 'PÅed odeslánÃm zkontrolovat pravopis'; +$labels['spellcheckoptions'] = 'Nastavenà pravopisu'; +$labels['spellcheckignoresyms'] = 'Ignorovat slova obsahujÃcà symboly'; +$labels['spellcheckignorenums'] = 'Ignorovat slova obsahujÃcà ÄÃsla'; +$labels['spellcheckignorecaps'] = 'Ignorovat slova psaná velkými pÃsmeny'; +$labels['addtodict'] = 'PÅidat do slovnÃku'; $labels['folder'] = 'Složka'; $labels['folders'] = 'Složky'; $labels['foldername'] = 'Jméno složky'; @@ -379,6 +405,7 @@ $labels['sharedfolder'] = 'SdÃlená složka'; $labels['sortby'] = 'SeÅadit podle'; $labels['sortasc'] = 'SeÅadit vzestupnÄ'; $labels['sortdesc'] = 'SeÅadit sestupnÄ'; +$labels['undo'] = 'Vrátit zpÄt'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/cs_CZ/messages.inc b/program/localization/cs_CZ/messages.inc index 13c4dd4..a47b8d8 100644 --- a/program/localization/cs_CZ/messages.inc +++ b/program/localization/cs_CZ/messages.inc @@ -16,7 +16,7 @@ | Ales Pospichal <ales@pospichalales.info> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -27,6 +27,7 @@ $messages['sessionerror'] = 'VaÅ¡e pÅihlášenà je neplatné nebo vyprÅ¡elo'; $messages['imaperror'] = 'PÅipojenà na IMAP server selhalo'; $messages['servererror'] = 'Chyba serveru!'; $messages['servererrormsg'] = 'Chyba serveru: $msg'; +$messages['dberror'] = 'Chyba v databázi!'; $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Ã.'; $messages['invalidrequest'] = 'Nesprávný požadavek. Data nebyla uložena.'; @@ -35,6 +36,7 @@ $messages['loggedout'] = 'Byli jste úspÄÅ¡nÄ odhlášeni. Nashledanou!'; $messages['mailboxempty'] = 'Schránka je prázdná'; $messages['loading'] = 'NaÄÃtám...'; $messages['uploading'] = 'Nahrávám soubor...'; +$messages['uploadingmany'] = 'Nahrávám soubory...'; $messages['loadingdata'] = 'NaÄÃtám data...'; $messages['checkingmail'] = 'Kontroluji nové zprávy...'; $messages['sendingmessage'] = 'OdesÃlám zprávu...'; @@ -44,10 +46,12 @@ $messages['messagesaved'] = 'Zpráva uložena do Rozepsané'; $messages['successfullysaved'] = 'Uloženo'; $messages['addedsuccessfully'] = 'Kontakt byl úspÄÅ¡nÄ pÅidán do adresáÅe'; $messages['contactexists'] = 'Kontakt se zadanou e-mailovou adresou již existuje'; +$messages['contactnameexists'] = 'Kontakt se stejným jménem již existuje'; $messages['blockedimages'] = 'Z bezpeÄnostnÃch důvodů byly zablokovány obrázky ve zprávÄ.'; $messages['encryptedmessage'] = 'Tato zpráva je zaÅ¡ifrovaná a nelze ji zobrazit.'; -$messages['nocontactsfound'] = 'Nemáte žádné kontakty'; +$messages['nocontactsfound'] = 'Kontakty nebyly nalezeny'; $messages['contactnotfound'] = 'Požadovaný kontakt nebyl nalezen.'; +$messages['contactsearchonly'] = 'VyplÅte nÄkterou z položek'; $messages['sendingfailed'] = 'OdesÃlánà zprávy selhalo'; $messages['senttooquickly'] = 'ProsÃm poÄkejte $sec sekund pÅed odeslánÃm zprávy'; $messages['errorsavingsent'] = 'Nastala chyba pÅi ukládánà odeslané zprávy'; @@ -57,9 +61,12 @@ $messages['errorcopying'] = 'Nemohu zkopÃrovat zprávu'; $messages['errordeleting'] = 'Nemohu smazat zprávu'; $messages['errormarking'] = 'Zprávu nelze oznaÄit'; $messages['deletecontactconfirm'] = 'Opravdu chcete smazat oznaÄené kontakty?'; +$messages['deletegroupconfirm'] = 'Opravdu chcete smazat skupinu?'; $messages['deletemessagesconfirm'] = 'Opravdu chcete smazat oznaÄené zprávy?'; $messages['deletefolderconfirm'] = 'Chcete opravdu smazat tento adresáÅ?'; $messages['purgefolderconfirm'] = 'Opravdu chcete smazat vÅ¡echny zprávy v této složce?'; +$messages['contactdeleting'] = 'Mažu kontakty...'; +$messages['groupdeleting'] = 'Mažu skupinu...'; $messages['folderdeleting'] = 'OdstraÅuji složku...'; $messages['foldermoving'] = 'PÅesouvám složku...'; $messages['foldersubscribing'] = 'PÅipojuji složku...'; @@ -74,10 +81,10 @@ $messages['nosubjectwarning'] = 'PÅedmÄt nebyl vyplÅen. PÅejete si jej zadat $messages['nobodywarning'] = 'Opravdu chtete odeslat prázdnou zprávu?'; $messages['notsentwarning'] = 'Zpráva nebyla odeslána. PÅejete si zprávu zahodit?'; $messages['noldapserver'] = 'Zvolte, prosÃm, LDAP server k hledánÃ'; -$messages['nocontactsreturned'] = 'Nebyly nalezeny žádné kontakty'; $messages['nosearchname'] = 'Zadejte, prosÃm, jméno nebo e-mail kontaktu'; $messages['notuploadedwarning'] = 'JeÅ¡tÄ nebyly nahrány vÅ¡echny pÅÃlohy. PoÄkejte prosÃm nebo nahrávánà zruÅ¡te.'; -$messages['searchsuccessful'] = '$nr zpráv nalezeno'; +$messages['searchsuccessful'] = 'Nalezeno $nr zpráv'; +$messages['contactsearchsuccessful'] = 'Nalezeno $nr kontaktů'; $messages['searchnomatch'] = 'Nenalezena žádná zpráva'; $messages['searching'] = 'Vyhledávám...'; $messages['checking'] = 'Kontroluji...'; @@ -98,8 +105,11 @@ $messages['sourceisreadonly'] = 'Tento zdroj adres je pouze pro ÄtenÃ'; $messages['errorsavingcontact'] = 'Nemohu uložit adresu kontaktu'; $messages['movingmessage'] = 'PÅesouvám zprávu...'; $messages['copyingmessage'] = 'KopÃruji zprávu...'; +$messages['copyingcontact'] = 'KopÃruji kontakty...'; $messages['deletingmessage'] = 'OdstraÅuji zprávu...'; $messages['markingmessage'] = 'OznaÄuji zprávu...'; +$messages['addingmember'] = 'PÅidávám kontakty do skupiny...'; +$messages['removingmember'] = 'OdstraÅuji kontakty ze skupiny...'; $messages['receiptsent'] = 'Potvrzenà o pÅÅijetà zprávy odesláno'; $messages['errorsendingreceipt'] = 'Potvrzenà o pÅijetà zprávy nebylo možné odeslat'; $messages['nodeletelastidentity'] = 'AlespoÅ jedna identita musà být ponechána. Identitu nelze odstranit.'; @@ -111,7 +121,7 @@ $messages['contactremovedfromgroup'] = 'Kontakty byly odstranÄny z této skupin $messages['importwait'] = 'Importuji, prosÃm Äekejte...'; $messages['importerror'] = 'BÄhem importu nastala chyba! Nahraný soubor nenà ve formátu vCard.'; $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 existing entries</b>'; +$messages['importconfirmskipped'] = '<b>PÅeskoÄeno $skipped existujÃcÃch položek</b>'; $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?'; @@ -129,18 +139,27 @@ $messages['maxgroupmembersreached'] = 'PoÄet Älenských skupin dosáhl maximum $messages['internalerror'] = 'DoÅ¡lo k internà chybÄ. Zkuste to znovu'; $messages['contactdelerror'] = 'Kontakty nelze odstranit'; $messages['contactdeleted'] = 'Kontakty byly odstranÄny'; +$messages['contactrestoreerror'] = 'Nelze obnovit smazané kontakty'; +$messages['contactrestored'] = 'Kontakty byly obnoveny'; $messages['groupdeleted'] = 'Skupina byla odstranÄna'; $messages['grouprenamed'] = 'Skupina byla pÅejmenována'; $messages['groupcreated'] = 'Skupina vytvoÅena'; +$messages['savedsearchdeleted'] = 'Uložené hledánà bylo ostranÄno'; +$messages['savedsearchdeleteerror'] = 'Nelze odstranit uložené hledánÃ'; +$messages['savedsearchcreated'] = 'Nové hledánà bylo vytvoÅeno'; +$messages['savedsearchcreateerror'] = 'Nelze vytvoÅit uložené hledánÃ'; $messages['messagedeleted'] = 'Zpráva odstranÄna'; $messages['messagemoved'] = 'Zpráva byla pÅesunuta'; $messages['messagecopied'] = 'Zpráva byla zkopirována'; $messages['messagemarked'] = 'Zpráva oznaÄena'; $messages['autocompletechars'] = 'NapiÅ¡te alespoÅ $min znaků pro automatické doplnÄnÃ'; +$messages['autocompletemore'] = 'NapiÅ¡te vÃce znaků. Nalezeno pÅÃliÅ¡ mnoho položek'; $messages['namecannotbeempty'] = 'Jméno musà být vyplnÄno'; $messages['nametoolong'] = 'Jméno je pÅÃliÅ¡ dlouhé'; $messages['folderupdated'] = 'Složka byla úspÄÅ¡nÄ aktualizována'; $messages['foldercreated'] = 'Složka byla úspÄÅ¡nÄ vytvoÅena'; $messages['invalidimageformat'] = 'Formát obrázku nenà podporován'; +$messages['mispellingsfound'] = 'Ve zprávÄ byly zjiÅ¡tÄny pravopisné chyby'; +$messages['parentnotwritable'] = 'Nelze vytvoÅit/pÅesunout složku do vybrané rodiÄovské složky. Nemáte práva.'; ?> diff --git a/program/localization/cy_GB/labels.inc b/program/localization/cy_GB/labels.inc index e1588d0..f3d521b 100644 --- a/program/localization/cy_GB/labels.inc +++ b/program/localization/cy_GB/labels.inc @@ -114,7 +114,7 @@ $labels['markread'] = 'Wedi eu darllen'; $labels['markunread'] = 'Heb eu darllen'; $labels['markflagged'] = 'Wedi eu fflagio'; $labels['markunflagged'] = 'Heb eu fflagio'; -$labels['messageactions'] = 'Mwy o weithredoedd...'; +$labels['moreactions'] = 'Mwy o weithredoedd...'; $labels['select'] = 'Dewis'; $labels['all'] = 'Popeth'; $labels['none'] = 'Dim byd'; @@ -186,6 +186,7 @@ $labels['highest'] = 'Uchaf'; $labels['nosubject'] = '(dim pwnc)'; $labels['showimages'] = 'Dangos lluniau'; $labels['alwaysshow'] = 'Dangos lluniau bob amser o $sender'; +$labels['isdraft'] = 'Mae hwn yn neges ddrafft'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Testun plaen'; $labels['savesentmessagein'] = 'Cadw negeseuon a ddanfonir yn'; @@ -267,7 +268,6 @@ $labels['print'] = 'Argraffu'; $labels['export'] = 'Allforio'; $labels['exportvcards'] = 'Allforio cysylltiadau mewn fformat vCard'; $labels['newcontactgroup'] = 'Creu grŵp cysylltiadau newydd'; -$labels['groupactions'] = 'Gweithredoedd ar gyfer grwpiau cysylltiadau...'; $labels['grouprename'] = 'Ail-enwi grŵp'; $labels['groupdelete'] = 'Dileu grŵp'; $labels['previouspage'] = 'Dangos y set flaenorol'; @@ -277,6 +277,8 @@ $labels['lastpage'] = 'Dangos y set olaf'; $labels['group'] = 'Grŵp'; $labels['groups'] = 'Grwpiau'; $labels['personaladrbook'] = 'Cyfeiriadau Personol'; +$labels['searchsave'] = 'Cadw chwiliad'; +$labels['searchdelete'] = 'Dileu chwiliad'; $labels['import'] = 'Mewnforio'; $labels['importcontacts'] = 'Mewnforio cysylltiadau'; $labels['importfromfile'] = 'Mewnforio o ffeil:'; @@ -285,6 +287,7 @@ $labels['importreplace'] = 'Dileu y llyfr cyfeiriadau cyfan wrth lwytho'; $labels['importtext'] = 'Fe allwch chi lwytho fyny cysylltiadau o lyfr cyfeiriadau sy\'n bodoli yn barod. Ar hyn o bryd rydyn\' ni\'n cefnogi mewnforio cyfeiriadau yn y fformat <a href="http://en.wikipedia.org/wiki/VCard">vCard</a>.'; $labels['done'] = 'Wedi gorffen'; $labels['settingsfor'] = 'Gosodiadau ar gyfer'; +$labels['about'] = 'Amdan'; $labels['preferences'] = 'Dewisiadau'; $labels['userpreferences'] = 'Dewisiadau\'r defnyddiwr'; $labels['editpreferences'] = 'Golygu dewisiadau\'r defnyddiwr'; @@ -296,6 +299,8 @@ $labels['edititem'] = 'Golygu eitem'; $labels['preferhtml'] = 'Dangos HTML'; $labels['defaultcharset'] = 'Set Nodau Diofyn'; $labels['htmlmessage'] = 'Neges HTML'; +$labels['dateformat'] = 'Fformat dyddiad'; +$labels['timeformat'] = 'Fformat amser'; $labels['prettydate'] = 'Dyddiadau pert'; $labels['setdefault'] = 'Rhagosod'; $labels['autodetect'] = 'Awto'; @@ -367,7 +372,13 @@ $labels['reqmdn'] = 'Bob amser gofyn am dderbynneb danfon'; $labels['reqdsn'] = 'Gofyn am hysbysiad statws danfon bob amser'; $labels['replysamefolder'] = 'Rhoi atebion yn yr un ffolder i\'r neges sy\'n cael ei ateb'; $labels['defaultaddressbook'] = 'Ychwanegu cysylltiadau newydd i\'r llyfr cyfeiriad dewiswyd'; +$labels['autocompletesingle'] = 'Hepgor cyfeiriadau ebost amgen wrth awto-gwblhau'; $labels['spellcheckbeforesend'] = 'Gwirio sillafu cyn danfon neges'; +$labels['spellcheckoptions'] = 'Dewisiadau gwirio sillafu'; +$labels['spellcheckignoresyms'] = 'Anwybyddu geiriau gyda symbolau'; +$labels['spellcheckignorenums'] = 'Anwybyddu geiriau gyda rhifau'; +$labels['spellcheckignorecaps'] = 'Anwybyddu geiriau sy\'n briflythrennau yn gyfangwbl'; +$labels['addtodict'] = 'Ychwanegu i\'r geiriadur'; $labels['folder'] = 'Ffolder'; $labels['folders'] = 'Ffolderi'; $labels['foldername'] = 'Enw ffolder'; @@ -392,6 +403,11 @@ $labels['sortby'] = 'Trefnu yn ôl'; $labels['sortasc'] = 'Trefn esgynnol'; $labels['sortdesc'] = 'Trefn ddisgynnol'; $labels['undo'] = 'Dad-wneud'; +$labels['plugin'] = 'Ategyn'; +$labels['version'] = 'Fersiwn'; +$labels['source'] = 'Ffynhonnell'; +$labels['license'] = 'Trwydded'; +$labels['support'] = 'Gofyn am gymorth'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/cy_GB/messages.inc b/program/localization/cy_GB/messages.inc index 0e96597..5122301 100644 --- a/program/localization/cy_GB/messages.inc +++ b/program/localization/cy_GB/messages.inc @@ -45,6 +45,7 @@ $messages['blockedimages'] = 'I amddiffyn eich preifatrwydd, fe ataliwyd lluniau $messages['encryptedmessage'] = 'Mae hon yn neges amgryptedig a felly ni ellir ei ddangos. Flin iawn!'; $messages['nocontactsfound'] = 'Ni gafwyd hyd i unrhyw gysylltiadau'; $messages['contactnotfound'] = 'Ni gafwyd hyd i\'r cysylltiad gofynnwyd amdano'; +$messages['contactsearchonly'] = 'Rhowch dermau chwilio i ganfod cysylltiadau'; $messages['sendingfailed'] = 'Methwyd danfon y neges'; $messages['senttooquickly'] = 'Arhoswch $sec eiliad cyn danfon y neges'; $messages['errorsavingsent'] = 'Fe gafwyd gwall wrth cadw\'r neges ddanfonwyd'; @@ -58,6 +59,7 @@ $messages['deletegroupconfirm'] = 'Ydych chi wir am ddileu\'r grŵp dewiswyd?'; $messages['deletemessagesconfirm'] = 'Ydych chi wir am ddileu y neges(euon) ddewiswyd?'; $messages['deletefolderconfirm'] = 'Ydych chi wir am ddileu y ffolder yma?'; $messages['purgefolderconfirm'] = 'Ydych chi wir am ddileu yr holl negeseuon yn y ffolder yma?'; +$messages['contactdeleting'] = 'Dileu cyswllt/cysylltiadau...'; $messages['groupdeleting'] = 'Yn dileu grŵp...'; $messages['folderdeleting'] = 'Yn dileu ffolder...'; $messages['foldermoving'] = 'Yn symud ffolder...'; @@ -73,10 +75,10 @@ $messages['nosubjectwarning'] = 'Mae\'r pennawd \"Pwnc\" yn wag. Hoffech chi roi $messages['nobodywarning'] = 'Danfon y neges hwn heb destun?'; $messages['notsentwarning'] = 'Ni ddanfonwyd y neges. Hoffech chi gael gwared a\'r neges?'; $messages['noldapserver'] = 'Dewiswch weinydd ldap i chwilio'; -$messages['nocontactsreturned'] = 'Ni gafwyd hyd i unrhyw gysylltiadau'; $messages['nosearchname'] = 'Rhowch enw cyswllt neu gyfeiriad e-bost'; $messages['notuploadedwarning'] = 'Nid yw pob atodiad wedi eu llwytho i fyny eto. Triwch eto neu canslo.'; $messages['searchsuccessful'] = 'Cafwyd hyd i $nr neges'; +$messages['contactsearchsuccessful'] = 'Canfuwyd $nr cyswllt.'; $messages['searchnomatch'] = 'Ni gafwyd hyd i unrhyw ganlyniadau chwilio'; $messages['searching'] = 'Yn chwilio...'; $messages['checking'] = 'Yn gofyn...'; @@ -123,7 +125,6 @@ $messages['smtpautherror'] = 'Gwall SMTP ($code): Methwyd dilysu\'r cyfrif'; $messages['smtpfromerror'] = 'Gwall SMTP ($code): Methwyd gosod y danfonwr "$from" ($msg)'; $messages['smtptoerror'] = 'Gwall SMTP ($code): Methwyd ychwanegu derbynwr "$to" ($msg)'; $messages['smtprecipientserror'] = 'Gwall SMTP: Nid oedd yn bosib darllen y rhestr o dderbynnwyr'; -$messages['smtpdsnerror'] = 'Gwall SMTP: Dim cefnogaeth i Hysbysiadau Statws Danfon'; $messages['smtperror'] = 'Gwall SMTP: $msg'; $messages['emailformaterror'] = 'Cyfeiriad e-bost anghywir: $email'; $messages['toomanyrecipients'] = 'Gormod o dderbynnwyr. Lleihewch y nifer i $max'; @@ -136,11 +137,16 @@ $messages['contactrestored'] = 'Adferwyd y cyswllt/cysylltiadau'; $messages['groupdeleted'] = 'Grŵp wedi ei ddileu yn llwyddiannus'; $messages['grouprenamed'] = 'Grŵp wedi ei ailenwi yn llwyddiannus'; $messages['groupcreated'] = 'Grŵp wedi ei greu yn llwyddiannus'; +$messages['savedsearchdeleted'] = 'Dilëwyd y chwiliad yn llwyddiannus.'; +$messages['savedsearchdeleteerror'] = 'Methwyd dileu y chwiliad.'; +$messages['savedsearchcreated'] = 'Crëwyd y chwiliad yn llwyddiannus.'; +$messages['savedsearchcreateerror'] = 'Methwyd creu y chwiliad.'; $messages['messagedeleted'] = 'Neges(euon) wedi eu dileu yn llwyddiannus'; $messages['messagemoved'] = 'Neges(euon) wedi eu symud yn llwyddiannus'; $messages['messagecopied'] = 'Neges(euon) wedi eu copïo yn llwyddiannus'; $messages['messagemarked'] = 'Neges(euon) wedi eu marcio yn llwyddiannus'; $messages['autocompletechars'] = 'Rhowch o leia $min llythyren ar gyfer awto-gwblhau'; +$messages['autocompletemore'] = 'Canfuwyd mwy o gofnodion sy\'n cyfateb. Teipiwch fwy o lythrennau.'; $messages['namecannotbeempty'] = 'Ni all yr enw fod yn wag'; $messages['nametoolong'] = 'Mae\'r enw yn rhy hir'; $messages['folderupdated'] = 'Diweddarwyd y ffolder yn llwyddiannus'; @@ -148,5 +154,6 @@ $messages['foldercreated'] = 'Crëwyd y ffolder yn llwyddiannus'; $messages['invalidimageformat'] = 'Ddim yn fformat llun dilys.'; $messages['mispellingsfound'] = 'Gwelwyd camsillafu yn y neges.'; $messages['parentnotwritable'] = 'Methwyd creu/symud ffolder i\'r ffolder rhiant ddewiswyd. Dim hawl mynediad.'; +$messages['messagetoobig'] = 'Mae darn y neges yn rhy fawr i\'w brosesu.'; ?> diff --git a/program/localization/da_DK/labels.inc b/program/localization/da_DK/labels.inc index cf766ee..5922e6d 100644 --- a/program/localization/da_DK/labels.inc +++ b/program/localization/da_DK/labels.inc @@ -12,27 +12,35 @@ | Author: Martin Moeller <martin@liga.dk> | | Jesper R. Meyer <jrm@upthere.dk> | | Søren Aggeboe <soren@aggeboe.dk> | +| John Loft Christiansen <john@nansensvej.dk> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4462 2011-01-28 16:01:03Z thomasb $ - +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ $labels = array(); + +// login page $labels['welcome'] = 'Velkommen til $product'; $labels['username'] = 'Brugernavn'; $labels['password'] = 'Adgangskode'; $labels['server'] = 'Server'; $labels['login'] = 'Log pÃ¥'; + +// Taskbar $labels['logout'] = 'Log af'; $labels['mail'] = 'E-mail'; $labels['settings'] = 'Personlige indstillinger'; $labels['addressbook'] = 'Adressebog'; + +// mailbox names $labels['inbox'] = 'Indbakke'; $labels['drafts'] = 'Kladder'; $labels['sent'] = 'Sendt post'; $labels['trash'] = 'Skrald'; $labels['junk'] = 'Ragelse'; + +// message listing $labels['subject'] = 'Emne'; $labels['from'] = 'Afsender'; $labels['to'] = 'Modtager'; @@ -45,17 +53,23 @@ $labels['size'] = 'Størrelse'; $labels['priority'] = 'Prioritet'; $labels['organization'] = 'Organisation'; $labels['readstatus'] = 'Læst status'; + $labels['mailboxlist'] = 'Mapper'; $labels['messagesfromto'] = 'Besked $from til $to af $count'; $labels['threadsfromto'] = 'TrÃ¥d $from til $to af $count'; $labels['messagenrof'] = 'Besked $nr af $count'; + $labels['copy'] = 'Kopier'; $labels['move'] = 'Flyt'; $labels['moveto'] = 'Flyt til...'; $labels['download'] = 'Download'; + $labels['filename'] = 'Filnavn'; $labels['filesize'] = 'Filstørrelse'; + $labels['addtoaddressbook'] = 'Tilføj til adressebogen'; + +// weekdays short $labels['sun'] = 'Søn'; $labels['mon'] = 'Man'; $labels['tue'] = 'Tir'; @@ -63,6 +77,8 @@ $labels['wed'] = 'Ons'; $labels['thu'] = 'Tor'; $labels['fri'] = 'Fre'; $labels['sat'] = 'Lør'; + +// weekdays long $labels['sunday'] = 'Søndag'; $labels['monday'] = 'Mandag'; $labels['tuesday'] = 'Tirsdag'; @@ -70,6 +86,8 @@ $labels['wednesday'] = 'Onsdag'; $labels['thursday'] = 'Torsdag'; $labels['friday'] = 'Fredag'; $labels['saturday'] = 'Lørdag'; + +// month short $labels['jan'] = 'Jan'; $labels['feb'] = 'Feb'; $labels['mar'] = 'Mar'; @@ -82,6 +100,8 @@ $labels['sep'] = 'Sep'; $labels['oct'] = 'Okt'; $labels['nov'] = 'Nov'; $labels['dec'] = 'Dec'; + +//months long $labels['longjan'] = 'Januar'; $labels['longfeb'] = 'Februar'; $labels['longmar'] = 'Marts'; @@ -94,25 +114,26 @@ $labels['longsep'] = 'September'; $labels['longoct'] = 'Oktober'; $labels['longnov'] = 'November'; $labels['longdec'] = 'December'; + $labels['today'] = 'I dag'; + +// toolbar buttons $labels['checkmail'] = 'Se efter nye beskeder'; $labels['writenewmessage'] = 'Skriv en ny besked'; $labels['replytomessage'] = 'Svar pÃ¥ denne besked'; $labels['replytoallmessage'] = 'Svar til alle modtagere'; $labels['replyall'] = 'Svar alle'; $labels['replylist'] = 'Svar til listen'; +$labels['forwardinline'] = 'Videresend'; +$labels['forwardattachment'] = 'Videresend som vedhæftning'; $labels['forwardmessage'] = 'Videresend denne besked'; $labels['deletemessage'] = 'Slet besked'; $labels['movemessagetotrash'] = 'Flyt besked til skrald'; $labels['printmessage'] = 'Udskriv denne besked'; $labels['previousmessage'] = 'Vis forrige besked'; -$labels['previousmessages'] = 'Vis forrige sæt beskeder'; $labels['firstmessage'] = 'Vis første besked'; -$labels['firstmessages'] = 'Vis første sæt beskeder'; $labels['nextmessage'] = 'Vis næste besked'; -$labels['nextmessages'] = 'Vis næste sæt beskeder'; $labels['lastmessage'] = 'Vis sidste besked'; -$labels['lastmessages'] = 'Vis sidste sæt beskeder'; $labels['backtolist'] = 'Tilbage til beskedlisten'; $labels['viewsource'] = 'Vis rÃ¥ besked'; $labels['markmessages'] = 'Markér beskeder'; @@ -120,7 +141,9 @@ $labels['markread'] = 'Som læst'; $labels['markunread'] = 'Som ulæst'; $labels['markflagged'] = 'Som markeret'; $labels['markunflagged'] = 'Som umarkeret'; +$labels['moreactions'] = 'Flere funktioner...'; $labels['messageactions'] = 'Flere funktioner...'; + $labels['select'] = 'Vælg'; $labels['all'] = 'Alle'; $labels['none'] = 'Ingen'; @@ -136,7 +159,8 @@ $labels['threads'] = 'TrÃ¥de'; $labels['expand-all'] = 'Udfold alle'; $labels['expand-unread'] = 'Udfold ulæste'; $labels['collapse-all'] = 'Fold alle'; -$labels['threaded'] = 'TrÃ¥ded'; +$labels['threaded'] = 'TrÃ¥det'; + $labels['autoexpand_threads'] = 'Udfold besked trÃ¥de'; $labels['do_expand'] = 'alle trÃ¥de'; $labels['expand_only_unread'] = 'kun dem med ulæste beskeder'; @@ -152,18 +176,24 @@ $labels['listcolumns'] = 'Vist kolonne'; $labels['listsorting'] = 'Sorterings kolonne'; $labels['listorder'] = 'Sorter efter'; $labels['listmode'] = 'Listevisningsmode'; + $labels['folderactions'] = 'Mappe handlinger...'; $labels['compact'] = 'Ryd op'; $labels['empty'] = 'Tøm'; + $labels['quota'] = 'Disk forbrug'; $labels['unknown'] = 'ukendt'; $labels['unlimited'] = 'ubegrænset'; + $labels['quicksearch'] = 'Hurtigsøgning'; $labels['resetsearch'] = 'Nulstil søgning'; $labels['searchmod'] = 'Søgeparametere'; $labels['msgtext'] = 'Hele beskeden'; + $labels['openinextwin'] = 'à bn i nyt vindue'; $labels['emlsave'] = 'Download (.eml)'; + +// message compose $labels['compose'] = 'Forfat en besked'; $labels['editasnew'] = 'Redigér som ny'; $labels['savemessage'] = 'Gem denne kladde'; @@ -173,41 +203,58 @@ $labels['charset'] = 'Tegnsæt'; $labels['editortype'] = 'Tekstbehandler'; $labels['returnreceipt'] = 'Anmod om kvittering'; $labels['dsn'] = 'Notifikation om leveringstatus'; +$labels['mailreplyintro'] = 'Den $date, $sender skrev:'; +$labels['originalmessage'] = 'Original besked'; + $labels['editidents'] = 'Ret identiteter'; $labels['checkspelling'] = 'Stavekontrol'; $labels['resumeediting'] = 'Genoptag redigering'; $labels['revertto'] = 'Vend tilbage til'; + $labels['attachments'] = 'Vedhæftninger'; $labels['upload'] = 'Upload'; +$labels['uploadprogress'] = '$percent ($current af $total)'; $labels['close'] = 'Luk'; $labels['messageoptions'] = 'Besked muligheder...'; + $labels['low'] = 'Lav'; $labels['lowest'] = 'Lavest'; $labels['normal'] = 'Normal'; $labels['high'] = 'Høj'; $labels['highest'] = 'Højest'; + $labels['nosubject'] = '(intet emne)'; $labels['showimages'] = 'Vis billeder'; $labels['alwaysshow'] = 'Vis altid billeder fra $sender'; +$labels['isdraft'] = 'Dette er en kladde.'; + $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Almindelig tekst'; $labels['savesentmessagein'] = 'Gem afsendt besked i'; $labels['dontsave'] = 'gem ikke'; $labels['maxuploadsize'] = 'Maksimale tilladte filstørrelse er $size'; + $labels['addcc'] = 'Tilføj Cc'; $labels['addbcc'] = 'Tilføj Bcc'; $labels['addreplyto'] = 'Tilføj Svar-Til adresse'; $labels['addfollowupto'] = 'Tilføj følg-op adresse'; + +// mdn $labels['mdnrequest'] = 'Afsenderen af denne besked har bedt om at modtage en bekræftelse nÃ¥r du læser beskeden. Vil du sende kvittering for læsning?'; $labels['receiptread'] = 'Send kvittering for læsning'; $labels['yourmessage'] = 'Dette er en kvittering for at din besked er blevet vist'; $labels['receiptnote'] = 'Bemærk: Denne kvittering bekræfter udelukkende at beskeden blev vist pÃ¥ modtagerens computer. Der er ingen garanti for at modtageren har læst eller forstÃ¥et beskedens indhold.'; + +// address book $labels['name'] = 'Vist navn'; $labels['firstname'] = 'Fornavn'; $labels['surname'] = 'Efternavn'; $labels['middlename'] = 'Mellemnavn'; +$labels['nameprefix'] = 'Præfiks'; +$labels['namesuffix'] = 'Suffiks'; $labels['nickname'] = 'Alias/Kaldenavn'; $labels['jobtitle'] = 'Job titel'; +$labels['organization'] = 'Firma'; $labels['department'] = 'Afdeling'; $labels['gender'] = 'Køn'; $labels['maidenname'] = 'Pigenavn'; @@ -229,11 +276,33 @@ $labels['female'] = 'Kvinde'; $labels['manager'] = 'Manager'; $labels['assistant'] = 'Assistent'; $labels['spouse'] = 'Ãgtefælle'; +$labels['allfields'] = 'Alle felter'; +$labels['search'] = 'Søg'; +$labels['advsearch'] = 'Avanceret søg'; +$labels['other'] = 'Andet'; + +$labels['typehome'] = 'Hjem'; +$labels['typework'] = 'Arbejde'; +$labels['typeother'] = 'Andet'; +$labels['typemobile'] = 'Mobil'; +$labels['typemain'] = 'Fastnet'; +$labels['typehomefax'] = 'Hjemme fax'; +$labels['typeworkfax'] = 'Arbejde Fax'; +$labels['typecar'] = 'Bil'; +$labels['typepager'] = 'Personsøger'; +$labels['typevideo'] = 'Video'; +$labels['typeassistant'] = 'Assistent'; +$labels['typehomepage'] = 'Hjemmeside'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; + $labels['addfield'] = 'Tilføj felt...'; $labels['addcontact'] = 'Tilføj en ny kontakt'; $labels['editcontact'] = 'Redigér kontakt'; $labels['contacts'] = 'Kontakter'; $labels['contactproperties'] = 'Kontakt egenskaber'; +$labels['personalinfo'] = 'Personlig information'; + $labels['edit'] = 'Redigér'; $labels['cancel'] = 'Afbryd'; $labels['save'] = 'Gem'; @@ -241,6 +310,7 @@ $labels['delete'] = 'Slet'; $labels['rename'] = 'Omdøb'; $labels['addphoto'] = 'Tilføj'; $labels['replacephoto'] = 'Erstat'; + $labels['newcontact'] = 'Opret nyt kontaktkort'; $labels['deletecontact'] = 'Slet valgte kontakter'; $labels['composeto'] = 'Skriv brev til'; @@ -250,31 +320,47 @@ $labels['export'] = 'Eksport'; $labels['exportvcards'] = 'Eksportér kontakter i vCard format'; $labels['newcontactgroup'] = 'Opret ny kontaktgruppe'; $labels['groupactions'] = 'Funktioner for kontaktgrupper...'; +$labels['groupdelete'] = 'Slet gruppe'; + $labels['previouspage'] = 'Vis forrige sæt'; $labels['firstpage'] = 'Vis første sæt'; $labels['nextpage'] = 'Vis næste sæt'; $labels['lastpage'] = 'Vis sidste sæt'; + $labels['group'] = 'Gruppe'; $labels['groups'] = 'Grupper'; $labels['personaladrbook'] = 'Personlige Adresser'; + +$labels['searchsave'] = 'Gem søgning'; +$labels['searchdelete'] = 'Slet søgning'; + $labels['import'] = 'Importér'; $labels['importcontacts'] = 'Importér kontakter'; $labels['importfromfile'] = 'Importér fra fil:'; +$labels['importtarget'] = 'Tilføj nye kontakter til adressebogen:'; $labels['importreplace'] = 'Overskriv hele adressebogen'; $labels['importtext'] = 'Du kan uploade kontakter fra en eksisterende adressebog.Vi understøtter i øjeblikket import af adresser i vCard formatet.'; $labels['done'] = 'Færdig'; + +// settings $labels['settingsfor'] = 'Indstillinger for'; +$labels['about'] = 'Om'; $labels['preferences'] = 'Præferencer'; $labels['userpreferences'] = 'Brugerpræferencer'; $labels['editpreferences'] = 'Redigér brugerpræferencer'; + $labels['identities'] = 'Identiteter'; $labels['manageidentities'] = 'Styr identiteterne for denne konto'; $labels['newidentity'] = 'Ny identitet'; + $labels['newitem'] = 'Nyt punkt'; $labels['edititem'] = 'Redigér punkt'; + $labels['preferhtml'] = 'Foretræk HTML'; $labels['defaultcharset'] = 'Standard tegnkodning'; $labels['htmlmessage'] = 'HTML-besked'; +$labels['dateformat'] = 'Dato format'; +$labels['timeformat'] = 'Tid format'; $labels['prettydate'] = 'Pæn datovisning'; $labels['setdefault'] = 'Sæt standard'; $labels['autodetect'] = 'Automatisk'; @@ -345,6 +431,15 @@ $labels['afternseconds'] = 'efter $n sekunder'; $labels['reqmdn'] = 'Bed altid om at fÃ¥ besked om læsning'; $labels['reqdsn'] = 'Bed altid om at fÃ¥ en status pÃ¥ levering'; $labels['replysamefolder'] = 'Placer svar til en besked i samme mappe som beskeden der besvares'; +$labels['defaultaddressbook'] = 'Tilføj nye kontakter til den valgte adressebog'; +$labels['autocompletesingle'] = 'UndgÃ¥ alternative emailadresser under autofuldførelse'; +$labels['spellcheckbeforesend'] = 'Tjek stavning inden beskeden sendes'; +$labels['spellcheckoptions'] = 'Stavning muligheder'; +$labels['spellcheckignoresyms'] = 'Ignorer ord med symboler'; +$labels['spellcheckignorenums'] = 'Ignorer ord med tal'; +$labels['spellcheckignorecaps'] = 'Ignorer ord hvor alle bogstaver er versaler'; +$labels['addtodict'] = 'Tilføj til ordbog'; + $labels['folder'] = 'Mappe'; $labels['folders'] = 'Mapper'; $labels['foldername'] = 'Mappenavn'; @@ -361,13 +456,29 @@ $labels['location'] = 'Placering'; $labels['info'] = 'Information'; $labels['getfoldersize'] = 'Klik for at hente mappestørrelse'; $labels['changesubscription'] = 'Klik for at ændre abonnement'; +$labels['foldertype'] = 'Mappe Type'; +$labels['personalfolder'] = 'Privat mappe'; +$labels['otherfolder'] = 'Anden brugers mappe'; +$labels['sharedfolder'] = 'Offentlig mappe'; + $labels['sortby'] = 'Sortér efter'; $labels['sortasc'] = 'Ãldste først'; $labels['sortdesc'] = 'Nyeste først'; +$labels['undo'] = 'Fortryd'; + +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Version'; +$labels['source'] = 'Kilde'; +$labels['license'] = 'Licens'; +$labels['support'] = 'FÃ¥ support'; + +// units $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; $labels['GB'] = 'GB'; + +// character sets $labels['unicode'] = 'Unicode'; $labels['english'] = 'Engelsk'; $labels['westerneuropean'] = 'Vestlig europæisk'; diff --git a/program/localization/da_DK/messages.inc b/program/localization/da_DK/messages.inc index c8ff451..0eb72dd 100644 --- a/program/localization/da_DK/messages.inc +++ b/program/localization/da_DK/messages.inc @@ -12,10 +12,10 @@ | Author : Martin Moeller <martin@liga.dk> | | Jesper R. Meyer <jesper@upthere.dk> | | Søren Aggeboe <soren@aggeboe.dk> | +| John Loft Christiansen <john@nansensvej.dk> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 4462 2011-01-28 16:01:03Z thomasb $ - +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ $messages = array(); @@ -25,6 +25,7 @@ $messages['sessionerror'] = 'Din session er ugyldig eller udløbet'; $messages['imaperror'] = 'Forbindelse til IMAP serveren fejlede'; $messages['servererror'] = 'Server fejl!'; $messages['servererrormsg'] = 'Server fejl: $msg'; +$messages['dberror'] = 'Database fejl!'; $messages['errorreadonly'] = 'Kunne ikke udføre den ønskede handling. Mappen er skrivebeskyttet'; $messages['errornoperm'] = 'Kunne ikke udføre den ønskede handling. Adgang nægtet'; $messages['invalidrequest'] = 'Ugyldig forespørgsel! Ingen data blev gemt.'; @@ -33,6 +34,7 @@ $messages['loggedout'] = 'Du er nu logget af webmail. Farvel sÃ¥ længe!'; $messages['mailboxempty'] = 'Postkassen er tom!'; $messages['loading'] = 'Indlæser...'; $messages['uploading'] = 'Uploader fil...'; +$messages['uploadingmany'] = 'Uploader filer...'; $messages['loadingdata'] = 'Indlæser data...'; $messages['checkingmail'] = 'Tjekker for nye beskeder...'; $messages['sendingmessage'] = 'Sender besked...'; @@ -42,10 +44,12 @@ $messages['messagesaved'] = 'Beskeden er gemt i kladdemappen'; $messages['successfullysaved'] = 'Det lykkedes at gemme'; $messages['addedsuccessfully'] = 'Kontakten blev tilføjet adressebogen'; $messages['contactexists'] = 'Der er allerede en kontakt med denne e-mail adresse'; +$messages['contactnameexists'] = 'En kontakt med samme navn eksisterer allerede.'; $messages['blockedimages'] = 'For at beskytte dit privatliv er billeder fra internetservere blokeret i denne besked.'; $messages['encryptedmessage'] = 'Beskeden er krypteret og kan ikke vises. Beklager!'; $messages['nocontactsfound'] = 'Ingen kontakter blev fundet'; $messages['contactnotfound'] = 'Den søgte kontakt blev ikke fundet'; +$messages['contactsearchonly'] = 'Indtast ord for at finde kontakten'; $messages['sendingfailed'] = 'Beskeden kunne ikke sendes'; $messages['senttooquickly'] = 'Vent venligst $sec sekunder før du sender denne besked'; $messages['errorsavingsent'] = 'Der opstod en fejl da den sendte besked blev gemt'; @@ -55,9 +59,12 @@ $messages['errorcopying'] = 'Beskeden kunne ikke kopieres'; $messages['errordeleting'] = 'Beskeden kunne ikke slettes'; $messages['errormarking'] = 'Beskeden kunne ikke markeres'; $messages['deletecontactconfirm'] = 'Vil du virkelig slette den/de valgte kontakt(er)?'; +$messages['deletegroupconfirm'] = 'Vil du virkelig slette den/de valgte gruppe(r)?'; $messages['deletemessagesconfirm'] = 'Vil du virkelig slette den/de valgte besked(er)?'; $messages['deletefolderconfirm'] = 'Vil du virkelig slette den valgte mappe'; $messages['purgefolderconfirm'] = 'Vil du virkelig slette alle beskeder i denne mappe?'; +$messages['contactdeleting'] = 'Sletter kontakt(er)...'; +$messages['groupdeleting'] = 'Sletter gruppe...'; $messages['folderdeleting'] = 'Sletter mappen...'; $messages['foldermoving'] = 'Flytter mappen...'; $messages['foldersubscribing'] = 'Abonnere pÃ¥ mappen...'; @@ -96,8 +103,11 @@ $messages['sourceisreadonly'] = 'Denne adressekilde er kun til læsning'; $messages['errorsavingcontact'] = 'Kunne ikke gemme kontakt adressen'; $messages['movingmessage'] = 'Flytter besked...'; $messages['copyingmessage'] = 'Kopierer besked...'; +$messages['copyingcontact'] = 'Kopierer kontakt(er)...'; $messages['deletingmessage'] = 'Sletter besked(er)...'; $messages['markingmessage'] = 'Markerer besked(er)...'; +$messages['addingmember'] = 'Tilføjer kontakt(er) til gruppen...'; +$messages['removingmember'] = 'Fjerner kontakt(er) fra gruppen...'; $messages['receiptsent'] = 'Kvittering for læsning er sendt'; $messages['errorsendingreceipt'] = 'Kvitteringen kunne ikke sendes'; $messages['nodeletelastidentity'] = 'Du kan ikke slette denne identitet, da det er den eneste der er tilbage.'; @@ -109,6 +119,7 @@ $messages['contactremovedfromgroup'] = 'Succesfuldt fjernet kontakten fra denne $messages['importwait'] = 'Importerer, vent venligst...'; $messages['importerror'] = 'Fejl i importen! Den uploadede fil er ikke en gyldig vCard fil.'; $messages['importconfirm'] = '<b>Importerede $inserted kontakter, sprang over $skipped allerede eksisterende kontakter</b>:<p><em>$names</em></p>'; +$messages['importconfirmskipped'] = '<b>Skipped $skipped existing entries</b>'; $messages['opnotpermitted'] = 'Handlingen er ikke tilladt!'; $messages['nofromaddress'] = 'Der mangler en email-adresse i den valgte identitet'; $messages['editorwarning'] = 'Al formatering af teksten forsvinder, hvis der skiftes til ren tekst. Vil du fortsætte?'; @@ -118,7 +129,6 @@ $messages['smtpautherror'] = 'SMTP fejl ($code): Autenticering fejlede'; $messages['smtpfromerror'] = 'SMTP fejl ($code): Kunne ikke afsende som "$from" ($msg)'; $messages['smtptoerror'] = 'SMTP fejl ($code): Kunne ikke tilføje modtageren "$to" ($msg)'; $messages['smtprecipientserror'] = 'SMTP fejl: kan ikke fortolke listen af modtagere'; -$messages['smtpdsnerror'] = 'SMTP fejl: Ingen understøttelse af leveringsnotifikation'; $messages['smtperror'] = 'SMTP fejl: $msg'; $messages['emailformaterror'] = 'Ugyldig email-adresse: $email'; $messages['toomanyrecipients'] = 'For mange modtagere. Reducer antallet af modtagere til $max'; @@ -126,18 +136,28 @@ $messages['maxgroupmembersreached'] = 'Antallet af gruppemedlemmer overstiger ma $messages['internalerror'] = 'Der opstod en intern fejl - prøv venligst igen'; $messages['contactdelerror'] = 'Kunne ikke slette kontakt(er)'; $messages['contactdeleted'] = 'Kontakt(er) slettet'; +$messages['contactrestoreerror'] = 'Kunne ikke gendanne slettede kontakt(er).'; +$messages['contactrestored'] = 'Kontakt(er) gendannet.'; $messages['groupdeleted'] = 'Gruppen er slettet'; $messages['grouprenamed'] = 'Gruppen er omdøbt'; $messages['groupcreated'] = 'Gruppen er oprettet'; +$messages['savedsearchdeleted'] = 'Gemt søgning slettet.'; +$messages['savedsearchdeleteerror'] = 'Kunne ikke slette Gemt søgning.'; +$messages['savedsearchcreated'] = 'Gemt søgning oprettet.'; +$messages['savedsearchcreateerror'] = 'Kunne ikke oprette Gemt søgning.'; $messages['messagedeleted'] = 'Besked(er) slettet'; $messages['messagemoved'] = 'Besked(er) flyttet'; $messages['messagecopied'] = 'Besked(er) kopieret'; $messages['messagemarked'] = 'Besked(er) markeret'; $messages['autocompletechars'] = 'Du skal min. indtaste $min for at benytte autoopslag'; +$messages['autocompletemore'] = 'Flere emner fundet. Task flere bogstaver.'; $messages['namecannotbeempty'] = 'Navnet kan ikke været tomt'; $messages['nametoolong'] = 'Navnet er for langt'; $messages['folderupdated'] = 'Mappen er opdateret'; $messages['foldercreated'] = 'Mappen er oprettet'; $messages['invalidimageformat'] = 'Ikke et gyldigt billedformat'; +$messages['mispellingsfound'] = 'Der er fundet stavefejl i beskeden.'; +$messages['parentnotwritable'] = 'Kan ikke oprette/flytte mappe ind i valgt mappe. Ingen adgangsrettigheder.'; +$messages['messagetoobig'] = 'Besked delen er for stor til at behandle.'; ?> diff --git a/program/localization/de_CH/labels.inc b/program/localization/de_CH/labels.inc index c01cb7f..7a27bbe 100644 --- a/program/localization/de_CH/labels.inc +++ b/program/localization/de_CH/labels.inc @@ -13,7 +13,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -285,6 +285,7 @@ $labels['importreplace'] = 'Bestehendes Adressbuch komplett ersetzen'; $labels['importtext'] = 'Sie können Kontakte aus einem bestehenden Adressbuch hochladen.<br/>Es können Adressbücher im <a href="http://de.wikipedia.org/wiki/VCard">vCard-Format</a> importiert werden.'; $labels['done'] = 'Fertig'; $labels['settingsfor'] = 'Einstellungen für'; +$labels['about'] = 'Ãber'; $labels['preferences'] = 'Einstellungen'; $labels['userpreferences'] = 'Benutzereinstellungen'; $labels['editpreferences'] = 'Einstellungen bearbeiten'; @@ -296,6 +297,8 @@ $labels['edititem'] = 'Eintrag bearbeiten'; $labels['preferhtml'] = 'HTML bevorzugen'; $labels['defaultcharset'] = 'Standard-Zeichensatz'; $labels['htmlmessage'] = 'HTML Nachricht'; +$labels['dateformat'] = 'Datumsformat'; +$labels['timeformat'] = 'Zeitformat'; $labels['prettydate'] = 'Kurze Datumsanzeige'; $labels['setdefault'] = 'Als Standard'; $labels['autodetect'] = 'Automatisch'; @@ -392,6 +395,11 @@ $labels['sortby'] = 'Sortieren nach'; $labels['sortasc'] = 'aufsteigend sortieren'; $labels['sortdesc'] = 'absteigend sortieren'; $labels['undo'] = 'Rückgängig'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Version'; +$labels['source'] = 'Quellcode'; +$labels['license'] = 'Lizenz'; +$labels['support'] = 'Support'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/de_CH/messages.inc b/program/localization/de_CH/messages.inc index b112ec9..fe4a07b 100644 --- a/program/localization/de_CH/messages.inc +++ b/program/localization/de_CH/messages.inc @@ -13,7 +13,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5079 2011-08-16 19:57:45Z thomasb $ +@version $Id: messages.inc 5258 2011-09-21 11:17:46Z thomasb $ */ @@ -24,7 +24,7 @@ $messages['sessionerror'] = 'Ihre Session ist ungültig oder abgelaufen'; $messages['imaperror'] = 'Keine Verbindung zum IMAP Server'; $messages['servererror'] = 'Serverfehler!'; $messages['servererrormsg'] = 'Serverfehler: $msg'; -$messages['databaserror'] = 'Datenbankfehler!'; +$messages['dberror'] = 'Datenbankfehler!'; $messages['errorreadonly'] = 'Die Aktion kann nicht ausgeführt werden. Der Ordner ist schreibgeschützt.'; $messages['errornoperm'] = 'Die Aktion kann nicht ausgeführt werden. Zugriff verweigert.'; $messages['invalidrequest'] = 'Ungültige Anfrage! Es wurden keine Daten gespeichert.'; @@ -48,6 +48,7 @@ $messages['blockedimages'] = 'Um Ihre Privatsphäre zur schützen, wurden extern $messages['encryptedmessage'] = 'Dies ist eine verschlüsselte Nachricht und kann leider nicht angezeigt werden.'; $messages['nocontactsfound'] = 'Keine Kontakte gefunden'; $messages['contactnotfound'] = 'Die gewählte Adresse wurde nicht gefunden'; +$messages['contactsearchonly'] = 'Geben Sie einen Suchbegriff ein, um Kontakte zu finden'; $messages['sendingfailed'] = 'Versand der Nachricht fehlgeschlagen'; $messages['senttooquickly'] = 'Bitte warten Sie $sec Sekunde(n) vor dem Senden dieser Nachricht'; $messages['errorsavingsent'] = 'Ein Fehler ist beim Speichern der gesendeten Nachricht aufgetreten'; diff --git a/program/localization/de_DE/labels.inc b/program/localization/de_DE/labels.inc index 1015185..ea7e0a0 100644 --- a/program/localization/de_DE/labels.inc +++ b/program/localization/de_DE/labels.inc @@ -12,9 +12,10 @@ +-----------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | | Author: Marcel Schlesinger <info@marcel-schlesinger.de> | +| Author: Roland Liebl <myroundcube@mail4us.net> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5040 2011-08-10 11:09:16Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -101,18 +102,16 @@ $labels['replytomessage'] = 'Antwort verfassen'; $labels['replytoallmessage'] = 'Antwort an Absender und alle Empfänger verfassen'; $labels['replyall'] = 'Allen antworten'; $labels['replylist'] = 'Liste antworten'; +$labels['forwardinline'] = 'innerhalb der Nachricht'; +$labels['forwardattachment'] = 'als Dateianhang'; $labels['forwardmessage'] = 'Nachricht weiterleiten'; $labels['deletemessage'] = 'Nachricht löschen'; $labels['movemessagetotrash'] = 'Nachricht in den Papierkorb verschieben'; $labels['printmessage'] = 'Nachricht drucken'; $labels['previousmessage'] = 'Vorherige Nachricht anzeigen'; -$labels['previousmessages'] = 'Vorherige Nachrichten anzeigen'; $labels['firstmessage'] = 'Die erste Nachricht anzeigen'; -$labels['firstmessages'] = 'Die ersten Nachrichten anzeigen'; $labels['nextmessage'] = 'Nächste Nachricht anzeigen'; -$labels['nextmessages'] = 'Weitere Nachrichten anzeigen'; $labels['lastmessage'] = 'Die letzte Nachricht anzeigen'; -$labels['lastmessages'] = 'Die letzten Nachrichten anzeigen'; $labels['backtolist'] = 'Zurück zur Liste'; $labels['viewsource'] = 'Quelltext anzeigen'; $labels['markmessages'] = 'Nachrichten markieren'; @@ -120,7 +119,7 @@ $labels['markread'] = 'Als gelesen'; $labels['markunread'] = 'Als ungelesen'; $labels['markflagged'] = 'Stern hinzufügen'; $labels['markunflagged'] = 'Stern entfernen'; -$labels['messageactions'] = 'Weitere Aktionen...'; +$labels['moreactions'] = 'Mehr ...'; $labels['select'] = 'Auswählen'; $labels['all'] = 'Alle'; $labels['none'] = 'Keine'; @@ -174,12 +173,14 @@ $labels['editortype'] = 'Editor Typ'; $labels['returnreceipt'] = 'Empfangsbestätigung (MSN)'; $labels['dsn'] = 'Ãbermittlungsbestätigung (DSN)'; $labels['mailreplyintro'] = 'Am $date, schrieb $sender:'; +$labels['originalmessage'] = 'Originalnachricht'; $labels['editidents'] = 'Absender ändern'; $labels['checkspelling'] = 'Rechtschreibung prüfen'; $labels['resumeediting'] = 'Bearbeitung fortsetzen'; $labels['revertto'] = 'Zurück zu'; $labels['attachments'] = 'Anhänge'; $labels['upload'] = 'Hochladen'; +$labels['uploadprogress'] = '$percent ($current von $total)'; $labels['close'] = 'SchlieÃen'; $labels['messageoptions'] = 'Optionen...'; $labels['low'] = 'Niedrig'; @@ -232,6 +233,24 @@ $labels['female'] = 'weiblich'; $labels['manager'] = 'Vorgesetze(r)'; $labels['assistant'] = 'Assistent'; $labels['spouse'] = 'Partner/in'; +$labels['allfields'] = 'Alle Felder'; +$labels['search'] = 'Suche'; +$labels['advsearch'] = 'Detaillierte Suche'; +$labels['other'] = 'Sonstiges'; +$labels['typehome'] = 'Privat'; +$labels['typework'] = 'Dienstlich'; +$labels['typeother'] = 'Andere'; +$labels['typemobile'] = 'Mobil'; +$labels['typemain'] = 'Hauptnummer'; +$labels['typehomefax'] = 'Fax Privat'; +$labels['typeworkfax'] = 'Fax Dienst'; +$labels['typecar'] = 'Auto'; +$labels['typepager'] = 'Pager'; +$labels['typevideo'] = 'Video'; +$labels['typeassistant'] = 'Assistenz'; +$labels['typehomepage'] = 'Internet'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; $labels['addfield'] = 'Feld hinzufügen...'; $labels['addcontact'] = 'Kontakt hinzufügen'; $labels['editcontact'] = 'Kontakt bearbeiten'; @@ -253,7 +272,8 @@ $labels['print'] = 'Drucken'; $labels['export'] = 'Exportieren'; $labels['exportvcards'] = 'Kontakte im vCard-Format exportieren'; $labels['newcontactgroup'] = 'Neue Kontaktgruppen erstellen'; -$labels['groupactions'] = 'Aktionen für Kontaktgruppen...'; +$labels['grouprename'] = 'Gruppe umbenennen'; +$labels['groupdelete'] = 'Gruppe löschen'; $labels['previouspage'] = 'Seite zurück'; $labels['firstpage'] = 'Erste Seite'; $labels['nextpage'] = 'Nächste Seite'; @@ -261,9 +281,12 @@ $labels['lastpage'] = 'Letzte Seite'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Gruppen'; $labels['personaladrbook'] = 'Persönliches Adressbuch'; +$labels['searchsave'] = 'Suchergebnisse speichern'; +$labels['searchdelete'] = 'Suchergebnisse löschen'; $labels['import'] = 'Importieren'; $labels['importcontacts'] = 'Kontakte importieren'; $labels['importfromfile'] = 'Import aus Datei:'; +$labels['importtarget'] = 'Einen neuen Kontakt hinzufügen:'; $labels['importreplace'] = 'Bestehendes Adressbuch komplett ersetzen'; $labels['importtext'] = 'Sie können Kontakte aus einem bestehenden Adressbuch hochladen. Zur Zeit können Adressbücher im vCard-Format importiert werden.'; $labels['done'] = 'Fertig'; @@ -279,6 +302,8 @@ $labels['edititem'] = 'Eintrag bearbeiten'; $labels['preferhtml'] = 'HTML anzeigen'; $labels['defaultcharset'] = 'Standard Zeichensatz'; $labels['htmlmessage'] = 'HTML-Nachricht'; +$labels['dateformat'] = 'Datumsformatierung'; +$labels['timeformat'] = 'Zeitformatierung'; $labels['prettydate'] = 'Kurze Datumsanzeige'; $labels['setdefault'] = 'Als Standard'; $labels['autodetect'] = 'Automatisch'; @@ -349,6 +374,13 @@ $labels['afternseconds'] = 'nach $n Sekunden'; $labels['reqmdn'] = 'Empfangsbestätigung (MSN) immer anfordern'; $labels['reqdsn'] = 'Ãbermittlungsbestätigung (DSN) immer anfordern'; $labels['replysamefolder'] = 'Antworten im selben Ordner wie Original speichern'; +$labels['defaultaddressbook'] = 'Neue Kontakte zum ausgewählten Adressbuch hinzufügen'; +$labels['spellcheckbeforesend'] = 'Rechtschreibprüfung vor dem Absenden der Nachricht'; +$labels['spellcheckoptions'] = 'Rechtschreibprüfungsoptionen'; +$labels['spellcheckignoresyms'] = 'Wörter mit Symbolen überspringen'; +$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['folder'] = 'Ordner'; $labels['folders'] = 'Ordner'; $labels['foldername'] = 'Ordnername'; @@ -365,9 +397,14 @@ $labels['location'] = 'Speicherort'; $labels['info'] = 'Informationen'; $labels['getfoldersize'] = 'OrdnergröÃe anzeigen'; $labels['changesubscription'] = 'Abonnieren'; +$labels['foldertype'] = 'Ordnertyp'; +$labels['personalfolder'] = 'Privater Ordner'; +$labels['otherfolder'] = 'Ordner eines anderen Benutzers'; +$labels['sharedfolder'] = 'Ãffentlicher Ordner'; $labels['sortby'] = 'Sortieren nach'; $labels['sortasc'] = 'Aufsteigend sortieren'; $labels['sortdesc'] = 'Absteigend sortieren'; +$labels['undo'] = 'Rückgängig machen'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/de_DE/messages.inc b/program/localization/de_DE/messages.inc index 104f60c..584146d 100644 --- a/program/localization/de_DE/messages.inc +++ b/program/localization/de_DE/messages.inc @@ -12,9 +12,10 @@ +-----------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | | Author: Marcel Schlesinger <info@marcel-schlesinger.de> | +| Author: Roland Liebl <myroundcube@mail4us.net> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5079 2011-08-16 19:57:45Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -25,7 +26,7 @@ $messages['sessionerror'] = 'Ihre Session ist ungültig oder abgelaufen'; $messages['imaperror'] = 'Keine Verbindung zum IMAP Server'; $messages['servererror'] = 'Serverfehler!'; $messages['servererrormsg'] = 'Serverfehler: $msg'; -$messages['databaserror'] = 'Datenbankfehler!'; +$messages['dberror'] = 'Datenbankfehler!'; $messages['errorreadonly'] = 'Die Aktion kann nicht ausgeführt werden. Der Ordner ist schreibgeschützt.'; $messages['errornoperm'] = 'Die Aktion kann nicht ausgeführt werden. Zugriff verweigert.'; $messages['invalidrequest'] = 'Ungültige Anfrage! Es wurden keine Daten gespeichert.'; @@ -49,6 +50,7 @@ $messages['blockedimages'] = 'Um Ihre Privatsphäre zur schützen, wurden extern $messages['encryptedmessage'] = 'Dies ist eine verschlüsselte Nachricht und kann leider nicht angezeigt werden.'; $messages['nocontactsfound'] = 'Keine Kontakte gefunden'; $messages['contactnotfound'] = 'Der angeforderte Kontakt wurde nicht gefunden'; +$messages['contactsearchonly'] = 'Geben Sie einen Suchbegriff ein, um Kontakte zu finden'; $messages['sendingfailed'] = 'Versenden der Nachricht fehlgeschlagen'; $messages['senttooquickly'] = 'Bitte warten Sie $sec Sekunde(n) vor dem Senden dieser Nachricht'; $messages['errorsavingsent'] = 'Ein Fehler ist beim Speichern der gesendeten Nachricht aufgetreten'; @@ -77,10 +79,10 @@ $messages['nosubjectwarning'] = 'Die Betreffzeile ist leer. Möchten Sie jetzt e $messages['nobodywarning'] = 'Diese Nachricht ohne Inhalt senden?'; $messages['notsentwarning'] = 'Ihre Nachricht wurde nicht gesendet. Wollen Sie die Nachricht verwerfen?'; $messages['noldapserver'] = 'Bitte wählen Sie einen LDAP-Server aus'; -$messages['nocontactsreturned'] = 'Es wurden keine Kontakte gefunden'; $messages['nosearchname'] = 'Bitte geben Sie einen Namen oder eine E-Mail-Adresse ein'; $messages['notuploadedwarning'] = 'Es wurden noch nicht alle Dateien hochgeladen. Bitte warten oder Upload abbrechen.'; $messages['searchsuccessful'] = '$nr Nachrichten gefunden'; +$messages['contactsearchsuccessful'] = '$nr Kontakte gefunden'; $messages['searchnomatch'] = 'Die Suche lieferte keine Treffer'; $messages['searching'] = 'Suche...'; $messages['checking'] = 'Prüfe...'; @@ -127,7 +129,6 @@ $messages['smtpautherror'] = 'SMTP Fehler ($code): Die Authentisierung ist fehlg $messages['smtpfromerror'] = 'SMTP Fehler ($code): Der Absender "$from" konnte nicht gesetzt werden ($msg)'; $messages['smtptoerror'] = 'SMTP Fehler ($code): Der Empfänger "$to" konnte nicht gesetzt werden ($msg)'; $messages['smtprecipientserror'] = 'SMTP Fehler: Die Empfängerliste konnte nicht verarbeitet werden'; -$messages['smtpdsnerror'] = 'SMTP-Fehler: Ãbermittlungsbestätigungen werden nicht unterstützt'; $messages['smtperror'] = 'SMTP Fehler: $msg'; $messages['emailformaterror'] = 'Ungültige E-Mail-Adresse: $email'; $messages['toomanyrecipients'] = 'Zuviele Empfänger. Reduzieren Sie die Anzahl Empfängeradressen auf $max.'; @@ -140,11 +141,16 @@ $messages['contactrestored'] = 'Kontakte erfolgreich wiederhergestellt.'; $messages['groupdeleted'] = 'Gruppe erfolgreich gelöscht'; $messages['grouprenamed'] = 'Gruppe erlogreich umbenannt'; $messages['groupcreated'] = 'Gruppe erlogreich erstellt'; +$messages['savedsearchdeleted'] = 'Suchergebnisse erfolgreich gelöscht'; +$messages['savedsearchdeleteerror'] = 'Suchergebnisse konnten nicht gelöscht werden'; +$messages['savedsearchcreated'] = 'Suchergebnisse wurden erfolgreich wiederherstellt'; +$messages['savedsearchcreateerror'] = 'Suchergebnisse konnten nicht wiederhergestellt werden'; $messages['messagedeleted'] = 'Nachricht(en) erfolgreich gelöscht'; $messages['messagemoved'] = 'Nachricht(en) erfolgreich verschoben'; $messages['messagecopied'] = 'Nachricht(en) erfolgreich kopiert'; $messages['messagemarked'] = 'Nachricht(en) erfolgreich markiert'; $messages['autocompletechars'] = 'Geben Sie mind. $min Zeichen für die Auto-Vervollständigung ein'; +$messages['autocompletemore'] = 'Mehrere Treffer. Bitte geben Sie mehr Buchstaben ein'; $messages['namecannotbeempty'] = 'Der Name darf nicht leer sein'; $messages['nametoolong'] = 'Der Name ist zu lang'; $messages['folderupdated'] = 'Der Ordner wurde erfolgreich aktualisiert'; diff --git a/program/localization/en_GB/labels.inc b/program/localization/en_GB/labels.inc index 70fd646..9bb7039 100644 --- a/program/localization/en_GB/labels.inc +++ b/program/localization/en_GB/labels.inc @@ -11,9 +11,10 @@ | | +-----------------------------------------------------------------------+ | Author: Weiran Zhang (weiran@weiran.co.uk) | +| Phil Weir | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5184 2011-09-07 06:33:15Z alec $ */ @@ -33,8 +34,8 @@ $labels['sent'] = 'Sent'; $labels['trash'] = 'Deleted Items'; $labels['junk'] = 'Junk'; $labels['subject'] = 'Subject'; -$labels['from'] = 'Sender'; -$labels['to'] = 'Recipient'; +$labels['from'] = 'From'; +$labels['to'] = 'To'; $labels['cc'] = 'Copy'; $labels['bcc'] = 'Bcc'; $labels['replyto'] = 'Reply-To'; @@ -137,7 +138,7 @@ $labels['threaded'] = 'Threaded'; $labels['autoexpand_threads'] = 'Expand message threads'; $labels['do_expand'] = 'all threads'; $labels['expand_only_unread'] = 'only with unread messages'; -$labels['fromto'] = 'Sender/Recipient'; +$labels['fromto'] = 'From/To'; $labels['flag'] = 'Flag'; $labels['attachment'] = 'Attachment'; $labels['nonesort'] = 'None'; diff --git a/program/localization/en_GB/messages.inc b/program/localization/en_GB/messages.inc index 4a0807f..6d344be 100644 --- a/program/localization/en_GB/messages.inc +++ b/program/localization/en_GB/messages.inc @@ -11,9 +11,10 @@ | | +-----------------------------------------------------------------------+ | Author: Weiran Zhang (weiran@weiran.co.uk) | +| Phil Weir | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5173 2011-09-05 18:41:04Z thomasb $ */ diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index e6dd58c..4fbed29 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -13,7 +13,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - @version $Id: labels.inc 5165 2011-09-05 08:49:04Z thomasb $ + @version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -41,9 +41,9 @@ $labels['junk'] = 'Junk'; // message listing $labels['subject'] = 'Subject'; -$labels['from'] = 'Sender'; -$labels['to'] = 'Recipient'; -$labels['cc'] = 'Copy'; +$labels['from'] = 'From'; +$labels['to'] = 'To'; +$labels['cc'] = 'Cc'; $labels['bcc'] = 'Bcc'; $labels['replyto'] = 'Reply-To'; $labels['followupto'] = 'Followup-To'; @@ -140,7 +140,7 @@ $labels['markread'] = 'As read'; $labels['markunread'] = 'As unread'; $labels['markflagged'] = 'As flagged'; $labels['markunflagged'] = 'As unflagged'; -$labels['messageactions'] = 'More actions...'; +$labels['moreactions'] = 'More actions...'; $labels['select'] = 'Select'; $labels['all'] = 'All'; @@ -152,7 +152,6 @@ $labels['unanswered'] = 'Unanswered'; $labels['deleted'] = 'Deleted'; $labels['invert'] = 'Invert'; $labels['filter'] = 'Filter'; - $labels['list'] = 'List'; $labels['threads'] = 'Threads'; $labels['expand-all'] = 'Expand All'; @@ -163,7 +162,7 @@ $labels['threaded'] = 'Threaded'; $labels['autoexpand_threads'] = 'Expand message threads'; $labels['do_expand'] = 'all threads'; $labels['expand_only_unread'] = 'only with unread messages'; -$labels['fromto'] = 'Sender/Recipient'; +$labels['fromto'] = 'From/To'; $labels['flag'] = 'Flag'; $labels['attachment'] = 'Attachment'; $labels['nonesort'] = 'None'; @@ -203,6 +202,7 @@ $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['checkspelling'] = 'Check spelling'; @@ -224,6 +224,7 @@ $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['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Plain text'; @@ -316,7 +317,6 @@ $labels['print'] = 'Print'; $labels['export'] = 'Export'; $labels['exportvcards'] = 'Export contacts in vCard format'; $labels['newcontactgroup'] = 'Create new contact group'; -$labels['groupactions'] = 'Actions for contact groups...'; $labels['grouprename'] = 'Rename group'; $labels['groupdelete'] = 'Delete group'; @@ -329,6 +329,9 @@ $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:'; @@ -339,7 +342,7 @@ $labels['done'] = 'Done'; // settings $labels['settingsfor'] = 'Settings for'; - +$labels['about'] = 'About'; $labels['preferences'] = 'Preferences'; $labels['userpreferences'] = 'User preferences'; $labels['editpreferences'] = 'Edit user preferences'; @@ -354,6 +357,8 @@ $labels['edititem'] = 'Edit item'; $labels['preferhtml'] = 'Display HTML'; $labels['defaultcharset'] = 'Default Character Set'; $labels['htmlmessage'] = 'HTML Message'; +$labels['dateformat'] = 'Date format'; +$labels['timeformat'] = 'Time format'; $labels['prettydate'] = 'Pretty dates'; $labels['setdefault'] = 'Set default'; $labels['autodetect'] = 'Auto'; @@ -402,6 +407,7 @@ $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['section'] = 'Section'; $labels['maintenance'] = 'Maintenance'; @@ -425,7 +431,13 @@ $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['defaultaddressbook'] = 'Add new contacts to the selected addressbook'; +$labels['autocompletesingle'] = 'Skip alternative email addresses in autocompletion'; $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['folder'] = 'Folder'; $labels['folders'] = 'Folders'; @@ -453,6 +465,12 @@ $labels['sortasc'] = 'Sort ascending'; $labels['sortdesc'] = 'Sort descending'; $labels['undo'] = 'Undo'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Version'; +$labels['source'] = 'Source'; +$labels['license'] = 'License'; +$labels['support'] = 'Get support'; + // units $labels['B'] = 'B'; $labels['KB'] = 'KB'; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index 5da8458..10a7a45 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -13,7 +13,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - @version $Id: messages.inc 5022 2011-08-04 09:01:36Z alec $ + @version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -24,7 +24,7 @@ $messages['sessionerror'] = 'Your session is invalid or expired.'; $messages['imaperror'] = 'Connection to IMAP server failed.'; $messages['servererror'] = 'Server Error!'; $messages['servererrormsg'] = 'Server Error: $msg'; -$messages['databaserror'] = 'Database Error!'; +$messages['dberror'] = 'Database Error!'; $messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only.'; $messages['errornoperm'] = 'Unable to perform operation. Permission denied.'; $messages['invalidrequest'] = 'Invalid request! No data was saved.'; @@ -48,6 +48,7 @@ $messages['blockedimages'] = 'To protect your privacy, remote images are blocked $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.'; @@ -61,6 +62,7 @@ $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...'; @@ -76,10 +78,10 @@ $messages['nosubjectwarning'] = 'The "Subject" field is empty. Would you like t $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['nocontactsreturned'] = 'No contacts were found.'; $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...'; @@ -126,7 +128,6 @@ $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['smtpdsnerror'] = 'SMTP Error: No support for Delivery Status Notifications.'; $messages['smtperror'] = 'SMTP Error: $msg'; $messages['emailformaterror'] = 'Invalid e-mail address: $email'; $messages['toomanyrecipients'] = 'Too many recipients. Reduce the number of recipients to $max.'; @@ -139,11 +140,16 @@ $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.'; @@ -151,5 +157,6 @@ $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.'; ?> diff --git a/program/localization/es_ES/labels.inc b/program/localization/es_ES/labels.inc index fa0d824..2e1a49d 100644 --- a/program/localization/es_ES/labels.inc +++ b/program/localization/es_ES/labels.inc @@ -16,7 +16,7 @@ | José M. Ciordia <ciordia@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ @@ -103,6 +103,8 @@ $labels['replytomessage'] = 'Responder mensaje'; $labels['replytoallmessage'] = 'Responder al emisor y a todos los destinatarios'; $labels['replyall'] = 'Responder a todos'; $labels['replylist'] = 'Responder a la lista'; +$labels['forwardinline'] = 'Reenviar directamente'; +$labels['forwardattachment'] = 'Reenviar como adjunto'; $labels['forwardmessage'] = 'Reenviar mensaje'; $labels['deletemessage'] = 'Eliminar mensaje'; $labels['movemessagetotrash'] = 'Mover mensaje a la papelera'; @@ -118,7 +120,7 @@ $labels['markread'] = 'Como leÃdo'; $labels['markunread'] = 'Como no leÃdo'; $labels['markflagged'] = 'Como marcado'; $labels['markunflagged'] = 'Como no marcado'; -$labels['messageactions'] = 'Más acciones...'; +$labels['moreactions'] = 'Más accionesâ¦'; $labels['select'] = 'Elija'; $labels['all'] = 'Todos'; $labels['none'] = 'Ninguno'; @@ -171,12 +173,15 @@ $labels['charset'] = 'Codificación'; $labels['editortype'] = 'Tipo de editor'; $labels['returnreceipt'] = 'Acuse de recibo'; $labels['dsn'] = 'Entrega de notificaciones de estado'; +$labels['mailreplyintro'] = 'El $date, $sender escribió:'; +$labels['originalmessage'] = 'Mensaje original'; $labels['editidents'] = 'Editar identidades'; $labels['checkspelling'] = 'Revisar ortografÃa'; $labels['resumeediting'] = 'Continuar edición'; $labels['revertto'] = 'Revertir a'; $labels['attachments'] = 'Adjuntos'; $labels['upload'] = 'Subir'; +$labels['uploadprogress'] = '$percent ($current de $total)'; $labels['close'] = 'Cerrar'; $labels['messageoptions'] = 'Opciones de mensaje...'; $labels['low'] = 'Bajo'; @@ -229,6 +234,10 @@ $labels['female'] = 'Mujer'; $labels['manager'] = 'Director'; $labels['assistant'] = 'Auxiliar'; $labels['spouse'] = 'Cónyuge'; +$labels['allfields'] = 'Todos los campos'; +$labels['search'] = 'Buscar'; +$labels['advsearch'] = 'Búsqueda avanzada'; +$labels['other'] = 'Otro'; $labels['typehome'] = 'Casa'; $labels['typework'] = 'Trabajo'; $labels['typeother'] = 'Otro'; @@ -240,6 +249,9 @@ $labels['typecar'] = 'Coche'; $labels['typepager'] = 'Busca'; $labels['typevideo'] = 'VÃdeo'; $labels['typeassistant'] = 'Auxiliar'; +$labels['typehomepage'] = 'Inicio'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Perfil'; $labels['addfield'] = 'Añadir campo...'; $labels['addcontact'] = 'Añadir nuevo contacto'; $labels['editcontact'] = 'Editar contacto'; @@ -261,7 +273,8 @@ $labels['print'] = 'Imprimir'; $labels['export'] = 'Exportar'; $labels['exportvcards'] = 'Exportar contactos en formato vCard'; $labels['newcontactgroup'] = 'Crear un nuevo grupo de contactos'; -$labels['groupactions'] = 'Acciones para grupos de contactos...'; +$labels['grouprename'] = 'Renombrar grupo'; +$labels['groupdelete'] = 'Borrar grupo'; $labels['previouspage'] = 'Mostrar grupo anterior'; $labels['firstpage'] = 'Mostrar primer grupo'; $labels['nextpage'] = 'Mostrar grupo siguiente'; @@ -269,9 +282,12 @@ $labels['lastpage'] = 'Mostrar último grupo'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; $labels['personaladrbook'] = 'Direcciones personales'; +$labels['searchsave'] = 'Guardar búsqueda'; +$labels['searchdelete'] = 'Borrar búsqueda'; $labels['import'] = 'Importar'; $labels['importcontacts'] = 'Importar contactos'; $labels['importfromfile'] = 'Importar desde archivo:'; +$labels['importtarget'] = 'Añadir un nuevo contacto a la los contactos:'; $labels['importreplace'] = 'Reemplazar toda la lista de contactos'; $labels['importtext'] = 'Puede importar contactos desde una lista existente.<br/>Actualmente sólo soportamos el formato <a href="http://es.wikipedia.org/wiki/VCard">vCard</a>.'; $labels['done'] = 'Hecho'; @@ -287,6 +303,8 @@ $labels['edititem'] = 'Editar'; $labels['preferhtml'] = 'Prefiero HTML'; $labels['defaultcharset'] = 'Juego de caracteres por defecto'; $labels['htmlmessage'] = 'Mensaje HTML'; +$labels['dateformat'] = 'Formato de fecha'; +$labels['timeformat'] = 'Formato de hora'; $labels['prettydate'] = 'Fecha detallada'; $labels['setdefault'] = 'Seleccionar opción por defecto'; $labels['autodetect'] = 'Automático'; @@ -357,6 +375,13 @@ $labels['afternseconds'] = 'después de $n segundos'; $labels['reqmdn'] = 'Solicitar siempre un acuse de recibo'; $labels['reqdsn'] = 'Solicitar siempre la entrega de notificaciones de estado'; $labels['replysamefolder'] = 'Coloque las respuestas en la bandeja del mensaje que se responde'; +$labels['defaultaddressbook'] = 'Añadir nuevos contactos a la lista de contactos seleccionada'; +$labels['spellcheckbeforesend'] = 'Comprobar ortografÃa antes de enviar un mensaje'; +$labels['spellcheckoptions'] = 'Opciones de ortografÃa'; +$labels['spellcheckignoresyms'] = 'Ignorar palabras con sÃmbolos'; +$labels['spellcheckignorenums'] = 'Ignorar palabras con números'; +$labels['spellcheckignorecaps'] = 'Ignorar palabras con todo mayúsculas'; +$labels['addtodict'] = 'Añadir al diccionario'; $labels['folder'] = 'Bandeja'; $labels['folders'] = 'Bandejas'; $labels['foldername'] = 'Nombre de bandeja'; @@ -380,6 +405,7 @@ $labels['sharedfolder'] = 'Bandeja pública'; $labels['sortby'] = 'Ordenar por'; $labels['sortasc'] = 'Orden ascendente'; $labels['sortdesc'] = 'Orden descendente'; +$labels['undo'] = 'Deshacer'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/es_ES/messages.inc b/program/localization/es_ES/messages.inc index c23f3fa..4ed0e5d 100644 --- a/program/localization/es_ES/messages.inc +++ b/program/localization/es_ES/messages.inc @@ -17,7 +17,7 @@ | José M. Ciordia <ciordia@gmail.com> | +------------------------------------------------------------------------+ -@version $Id: messages.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: messages.inc 5290 2011-09-28 17:09:50Z thomasb $ */ $messages = array(); @@ -27,6 +27,7 @@ $messages['sessionerror'] = 'Su sesión no es válida o ha expirado'; $messages['imaperror'] = 'Error de conexión con el servidor IMAP'; $messages['servererror'] = '¡Error del servidor!'; $messages['servererrormsg'] = 'Error de servidor: $msg'; +$messages['dberror'] = '¡Error de base de datos!'; $messages['errorreadonly'] = 'No se ha podido hacer. La bandeja es sólo de lectura'; $messages['errornoperm'] = 'No se ha podido hacer. Permiso denegado'; $messages['invalidrequest'] = '¡Petición no válida! No se han guardado los datos.'; @@ -35,6 +36,7 @@ $messages['loggedout'] = 'Ha cerrado bien la sesión. ¡Hasta pronto!'; $messages['mailboxempty'] = 'La casilla está vacÃa'; $messages['loading'] = 'Cargando...'; $messages['uploading'] = 'Subiendo fichero...'; +$messages['uploadingmany'] = 'Subiendo archivosâ¦'; $messages['loadingdata'] = 'Cargando datos...'; $messages['checkingmail'] = 'Verificando si hay nuevos mensajes...'; $messages['sendingmessage'] = 'Enviando mensaje...'; @@ -44,6 +46,7 @@ $messages['messagesaved'] = 'Mensaje guardado en borradores'; $messages['successfullysaved'] = 'Guardado correctamente'; $messages['addedsuccessfully'] = 'Contacto añadido correctamente a la libreta de direcciones'; $messages['contactexists'] = 'Ya existe un contacto con esta dirección de correo'; +$messages['contactnameexists'] = 'Ya existe un contacto con el mismo nombre.'; $messages['blockedimages'] = 'Para proteger su privacidad, las imágenes externas han sido bloqueadas en este mensaje'; $messages['encryptedmessage'] = 'Este es un mensaje cifrado y no puede ser mostrado. ¡Lo siento!'; $messages['nocontactsfound'] = 'No hay contactos'; @@ -57,9 +60,11 @@ $messages['errorcopying'] = 'No se ha podido copiar el/los mensaje(s)'; $messages['errordeleting'] = 'No se ha podido eliminar el mensaje'; $messages['errormarking'] = 'No se ha podido marcar el mensaje'; $messages['deletecontactconfirm'] = '¿Realmente quiere eliminar los contactos seleccionados?'; +$messages['deletegroupconfirm'] = '¿De verdad quiere borrar el grupo seleccionado?'; $messages['deletemessagesconfirm'] = '¿Realmente quiere eliminar los mensajes seleccionados?'; $messages['deletefolderconfirm'] = '¿Realmente quiere eliminar esta bandeja?'; $messages['purgefolderconfirm'] = '¿Realmente quiere eliminar todos los mensajes de esta bandeja?'; +$messages['groupdeleting'] = 'Borrando grupoâ¦'; $messages['folderdeleting'] = 'Borrando bandeja...'; $messages['foldermoving'] = 'Moviendo bandeja...'; $messages['foldersubscribing'] = 'Suscribiendo bandeja...'; @@ -74,10 +79,10 @@ $messages['nosubjectwarning'] = 'El campo "Asunto" está vacÃo. ¿Desea complet $messages['nobodywarning'] = '¿Quiere enviar este mensaje sin texto?'; $messages['notsentwarning'] = 'El mensaje no ha sido enviado. ¿Desea descartar su mensaje?'; $messages['noldapserver'] = 'Por favor, seleccione un servidor LDAP para buscar'; -$messages['nocontactsreturned'] = 'No se han encontrado contactos'; $messages['nosearchname'] = 'Por favor, introduzca un nombre o la dirección de e-mail'; $messages['notuploadedwarning'] = 'No se han subido aún todos los adjuntos. Por favor espere o cancele la subida.'; $messages['searchsuccessful'] = 'Se encontraron $nr mensajes'; +$messages['contactsearchsuccessful'] = 'Encontrados $nr contactos.'; $messages['searchnomatch'] = 'No se obtuvieron resultados'; $messages['searching'] = 'Buscando...'; $messages['checking'] = 'Revisando...'; @@ -98,8 +103,11 @@ $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['deletingmessage'] = 'Eliminando mensaje(s)...'; $messages['markingmessage'] = 'Marcando mensaje(s)...'; +$messages['addingmember'] = 'Añadiendo contacto(s) al grupoâ¦'; +$messages['removingmember'] = 'Quitando contacto(s) del grupoâ¦'; $messages['receiptsent'] = 'La notificación de lectura se ha enviado correctamente.'; $messages['errorsendingreceipt'] = 'No se ha podido enviar la notificación de lectura.'; $messages['nodeletelastidentity'] = 'No se puede borrar esta identidad puesto que es la última.'; @@ -129,9 +137,15 @@ $messages['maxgroupmembersreached'] = 'El número de miembros del grupo excede e $messages['internalerror'] = 'Ocurrió un error interno. Por favor, inténtalo de nuevo'; $messages['contactdelerror'] = 'No se ha podido eliminar el contacto(s)'; $messages['contactdeleted'] = 'Contacto(s) eliminado(s) correctamente'; +$messages['contactrestoreerror'] = 'No se han podido restaurar los contactos borrados.'; +$messages['contactrestored'] = 'Los contactos se han restaurado con éxito.'; $messages['groupdeleted'] = 'Grupo eliminado correctamente'; $messages['grouprenamed'] = 'Grupo renombrado correctamente'; $messages['groupcreated'] = 'Grupo creado correctamente'; +$messages['savedsearchdeleted'] = 'La búsqueda guardada se ha borrado con éxito.'; +$messages['savedsearchdeleteerror'] = 'No se ha podido borrar la búsqueda guardada.'; +$messages['savedsearchcreated'] = 'Se ha guardado correctamente la búsqueda.'; +$messages['savedsearchcreateerror'] = 'No se ha podido guardar la búsqueda.'; $messages['messagedeleted'] = 'Mensaje(s) eliminado(s) correctamente'; $messages['messagemoved'] = 'Mensaje(s) movido(s) correctamente'; $messages['messagecopied'] = 'Mensaje(s) copiado(s) correctamente'; @@ -142,5 +156,7 @@ $messages['nametoolong'] = 'El nombre es demasiado largo'; $messages['folderupdated'] = 'Bandeja actualizada correctamente'; $messages['foldercreated'] = 'Bandeja creada correctamente'; $messages['invalidimageformat'] = 'No es un formato de imagen válido'; +$messages['mispellingsfound'] = 'Se han detectado errores ortográficos en el mensaje.'; +$messages['parentnotwritable'] = 'No se puede crear/mover la carpeta a la carpeta superior elegida. No tiene permisos de acceso.'; ?> diff --git a/program/localization/et_EE/messages.inc b/program/localization/et_EE/messages.inc index 70cc69f..40e0082 100644 --- a/program/localization/et_EE/messages.inc +++ b/program/localization/et_EE/messages.inc @@ -15,7 +15,7 @@ | Elan Ruusamäe <glen@delfi.ee> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5139 2011-08-28 09:47:15Z alec $ */ @@ -26,7 +26,7 @@ $messages['sessionerror'] = 'Sinu seanss on aegunud või vigane'; $messages['imaperror'] = 'Ei õnnestunud IMAP serveriga ühendust luua'; $messages['servererror'] = 'Serveri tõrge!'; $messages['servererrormsg'] = 'Serveri tõrge: $msg'; -$messages['databaserror'] = 'Andmebaasi tõrge!'; +$messages['dberror'] = 'Andmebaasi tõrge!'; $messages['errorreadonly'] = 'Operatsioon nurjus. Kaustale on vaid lugemisõigus'; $messages['errornoperm'] = 'Operatsioon nurjus. Ligipääsu õigused puuduvad'; $messages['invalidrequest'] = 'Lubamatu päring! Andmeid ei salvestatud.'; diff --git a/program/localization/fr_FR/labels.inc b/program/localization/fr_FR/labels.inc index b56a6c9..205dcaa 100644 --- a/program/localization/fr_FR/labels.inc +++ b/program/localization/fr_FR/labels.inc @@ -6,7 +6,7 @@ | language/fr_FR/labels.inc | | | | Language file of the Roundcube Webmail client | -| Copyright (C) 2005-2010, The Roundcube Dev Team | +| Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -15,7 +15,7 @@ | Maximilien Cuony <theglu@theglu.org> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -119,7 +119,7 @@ $labels['markread'] = 'Comme lus'; $labels['markunread'] = 'Comme non lus'; $labels['markflagged'] = 'Comme suivi'; $labels['markunflagged'] = 'Comme non-suivi'; -$labels['messageactions'] = 'Actions supplémentaires...'; +$labels['moreactions'] = 'Plus d\'actions...'; $labels['select'] = 'Sélectionner'; $labels['all'] = 'Tous'; $labels['none'] = 'Aucun'; @@ -191,6 +191,7 @@ $labels['highest'] = 'La plus élevée'; $labels['nosubject'] = '(pas de sujet)'; $labels['showimages'] = 'Afficher les images'; $labels['alwaysshow'] = 'Toujours afficher les images de $sender'; +$labels['isdraft'] = 'Ceci est un brouillon.'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'texte brut'; $labels['savesentmessagein'] = 'Enregistrer le message envoyé dans'; @@ -226,7 +227,7 @@ $labels['country'] = 'Pays'; $labels['birthday'] = 'Date de naissance'; $labels['anniversary'] = 'Anniversaire'; $labels['website'] = 'Site Web'; -$labels['instantmessenger'] = 'Messagerie instantannée'; +$labels['instantmessenger'] = 'Messagerie instantanée'; $labels['notes'] = 'Notes'; $labels['male'] = 'Homme'; $labels['female'] = 'Femme'; @@ -234,7 +235,7 @@ $labels['manager'] = 'Manager'; $labels['assistant'] = 'Assistant'; $labels['spouse'] = 'Ãpouse'; $labels['allfields'] = 'Tous les champs'; -$labels['search'] = 'Rechecher'; +$labels['search'] = 'Rechercher'; $labels['advsearch'] = 'Recherche avancée'; $labels['other'] = 'Autre'; $labels['typehome'] = 'Domicile'; @@ -272,7 +273,6 @@ $labels['print'] = 'Imprimer'; $labels['export'] = 'Exporter'; $labels['exportvcards'] = 'Exporter les contacts au format vCard'; $labels['newcontactgroup'] = 'Créer un nouveau groupe de contacts'; -$labels['groupactions'] = 'Actions pour les groupes de contacts'; $labels['grouprename'] = 'Renommer le groupe'; $labels['groupdelete'] = 'Supprimer le groupe'; $labels['previouspage'] = 'Montrer page précédente'; @@ -282,6 +282,8 @@ $labels['lastpage'] = 'Voir la dernière page'; $labels['group'] = 'Groupe'; $labels['groups'] = 'Groupes'; $labels['personaladrbook'] = 'Adresses personnelles'; +$labels['searchsave'] = 'Enregistrer la recherche'; +$labels['searchdelete'] = 'Supprimer la recherche'; $labels['import'] = 'Importer'; $labels['importcontacts'] = 'Importer les contacts'; $labels['importfromfile'] = 'Importer depuis un fichier :'; @@ -290,6 +292,7 @@ $labels['importreplace'] = 'Remplacer le carnet d\'adresse entier'; $labels['importtext'] = 'Vous pouvez envoyer des contacts depuis un carnet d\'adresse existant. Nous supportons actuellement l\'importation d\'adresses au format vCard.'; $labels['done'] = 'Terminé'; $labels['settingsfor'] = 'Paramètres pour'; +$labels['about'] = 'A propos'; $labels['preferences'] = 'Préférences'; $labels['userpreferences'] = 'Préférences utilisateur'; $labels['editpreferences'] = 'Modifier les préférences utilisateur'; @@ -301,6 +304,8 @@ $labels['edititem'] = 'Modifier l\'élément'; $labels['preferhtml'] = 'Afficher en HTML'; $labels['defaultcharset'] = 'Encodage par défaut'; $labels['htmlmessage'] = 'Message en HTML'; +$labels['dateformat'] = 'Format de la date'; +$labels['timeformat'] = 'Format de l\'heure'; $labels['prettydate'] = 'Affichage court des dates'; $labels['setdefault'] = 'Paramètres par défaut'; $labels['autodetect'] = 'Automatique'; @@ -372,7 +377,13 @@ $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['defaultaddressbook'] = 'Ajouter de nouveaux contacts au carnet dâadresses sélectionné'; +$labels['autocompletesingle'] = 'Ne pas tenir compte des adresses emails alternatives dans l\'autoremplissage'; $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'; +$labels['spellcheckignorecaps'] = 'Ignorer les mots entièrement en majuscule'; +$labels['addtodict'] = 'Ajouter au dictionnaire'; $labels['folder'] = 'Dossier'; $labels['folders'] = 'Dossiers'; $labels['foldername'] = 'Nom du dossier'; @@ -397,6 +408,11 @@ $labels['sortby'] = 'Trier par'; $labels['sortasc'] = 'Tri ascendant'; $labels['sortdesc'] = 'Tri descendant'; $labels['undo'] = 'Annuler'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Version'; +$labels['source'] = 'Source'; +$labels['license'] = 'Licence'; +$labels['support'] = 'Support'; $labels['B'] = 'o'; $labels['KB'] = 'ko'; $labels['MB'] = 'Mo'; @@ -420,4 +436,4 @@ $labels['japanese'] = 'Japonais'; $labels['korean'] = 'Coréen'; $labels['chinese'] = 'Chinois'; -?> +?> \ No newline at end of file diff --git a/program/localization/fr_FR/messages.inc b/program/localization/fr_FR/messages.inc index 41f3108..8df142d 100644 --- a/program/localization/fr_FR/messages.inc +++ b/program/localization/fr_FR/messages.inc @@ -6,7 +6,7 @@ | language/fr_FR/messages.inc | | | | Language file of the Roundcube Webmail client | -| Copyright (C) 2005-2010, The Roundcube Dev Team | +| Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -15,7 +15,7 @@ | Maximilien Cuony <theglu@theglu.org> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: messages.inc 5609 2011-12-14 12:58:13Z thomasb $ */ @@ -50,6 +50,7 @@ $messages['blockedimages'] = 'Afin de préserver votre vie privée, les images d $messages['encryptedmessage'] = 'Ceci est un message crypté et il ne peut pas être affiché. Désolé !'; $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 sec. pour envoyer le message'; $messages['errorsavingsent'] = 'Une erreur est survenue pendant la sauvegarde du message envoyé'; @@ -63,6 +64,7 @@ $messages['deletegroupconfirm'] = 'Ãtes-vous sûr de vouloir supprimer le group $messages['deletemessagesconfirm'] = 'Voulez-vous vraiment supprimer le(s) message(s) sélectionné(s) ?'; $messages['deletefolderconfirm'] = 'Voulez-vous vraiment effacer ce dossier ?'; $messages['purgefolderconfirm'] = 'Voulez-vous vraiment effacer tous les messages de ce dossier ?'; +$messages['contactdeleting'] = 'Suppression de contact(s)...'; $messages['groupdeleting'] = 'Suppression du groupe ...'; $messages['folderdeleting'] = 'Suppression du dossier...'; $messages['foldermoving'] = 'Déplacement du dossier...'; @@ -74,14 +76,14 @@ $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['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['nocontactsreturned'] = 'Aucun contact trouvé'; $messages['nosearchname'] = 'Entrez un nom de contact ou un courriel'; $messages['notuploadedwarning'] = 'Toutes les pièces jointes ne sont pas encore envoyées pour le moment. Merci d\'attendre ou d\'annuler l\'envoi.'; $messages['searchsuccessful'] = '$nr messages 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...'; @@ -90,7 +92,7 @@ $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é comptacté'; +$messages['folderexpunged'] = 'Le dossier a bien été compacté'; $messages['deletedsuccessfully'] = 'Supprimé(s) avec succès'; $messages['converting'] = 'Suppression de la mise en forme...'; $messages['messageopenerror'] = 'Impossible de charger le message depuis serveur'; @@ -128,7 +130,6 @@ $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['smtpdsnerror'] = 'Erreur SMTP: Pas de support des notifications d\'état de distribution'; $messages['smtperror'] = 'Erreur SMTP: $msg'; $messages['emailformaterror'] = 'Adresse email incorrecte: $email'; $messages['toomanyrecipients'] = 'Trop de destinataires. Réduisez leur nombre à $max maximum.'; @@ -141,11 +142,16 @@ $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['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['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'; @@ -153,5 +159,6 @@ $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é.'; -?> +?> \ No newline at end of file diff --git a/program/localization/gl_ES/labels.inc b/program/localization/gl_ES/labels.inc index 17f1fba..bdceb7e 100644 --- a/program/localization/gl_ES/labels.inc +++ b/program/localization/gl_ES/labels.inc @@ -5,7 +5,7 @@ | language/gl_ES/labels.inc | | | | Language file of the Roundcube Webmail client | -| Copyright (C) 2005-2010, The Roundcube Dev Team | +| Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -26,14 +26,14 @@ $labels['settings'] = 'Axustes persoais'; $labels['addressbook'] = 'Caderno de enderezos'; $labels['inbox'] = 'Caixa de entrada'; $labels['drafts'] = 'Borradores'; -$labels['sent'] = 'Enviado'; +$labels['sent'] = 'Enviados'; $labels['trash'] = 'Cubo do lixo'; $labels['junk'] = 'Correo lixo'; $labels['subject'] = 'Asunto'; $labels['from'] = 'Remitente'; $labels['to'] = 'Destinatario'; -$labels['cc'] = 'Copia (CC)'; -$labels['bcc'] = 'Copia oculta (BCC)'; +$labels['cc'] = 'Copia (Cc)'; +$labels['bcc'] = 'Copia oculta (Cco)'; $labels['replyto'] = 'Respostar a (Reply-To)'; $labels['followupto'] = 'Respostar a todos (Followup-To)'; $labels['date'] = 'Data'; @@ -42,7 +42,7 @@ $labels['priority'] = 'Prioridade'; $labels['organization'] = 'Organización'; $labels['readstatus'] = 'Estado da lectura'; $labels['mailboxlist'] = 'Cartafoles'; -$labels['messagesfromto'] = 'Mensaxes do $from ao $to de $count'; +$labels['messagesfromto'] = 'Mensaxes da $from á $to de $count'; $labels['threadsfromto'] = 'FÃos do $from ao $to de $count'; $labels['messagenrof'] = 'Mensaxe $nr de $count'; $labels['copy'] = 'Copiar'; @@ -92,31 +92,29 @@ $labels['longnov'] = 'Novembro'; $labels['longdec'] = 'Decembro'; $labels['today'] = 'Hoxe'; $labels['checkmail'] = 'Procurar novas mensaxes'; -$labels['writenewmessage'] = 'Crear unha nova mensaxe'; +$labels['writenewmessage'] = 'Redactar unha mensaxe nova'; $labels['replytomessage'] = 'Respostar a mensaxe'; $labels['replytoallmessage'] = 'Respostar á lista ou ao remitente e a tódolos destinatarios'; $labels['replyall'] = 'Respostar a todos'; $labels['replylist'] = 'Respostar á lista de correo'; +$labels['forwardinline'] = 'Reenviar inserido'; +$labels['forwardattachment'] = 'Reenviar como anexo'; $labels['forwardmessage'] = 'Reenviar a mensaxe'; $labels['deletemessage'] = 'Eliminar a mensaxe'; $labels['movemessagetotrash'] = 'Mover a mensaxe ao cubo do lixo'; $labels['printmessage'] = 'Imprimir esta mensaxe'; $labels['previousmessage'] = 'Amosar a mensaxe anterior'; -$labels['previousmessages'] = 'Amosar o grupo anterior de mensaxes'; $labels['firstmessage'] = 'Amosar a primeira mensaxe'; -$labels['firstmessages'] = 'Amosar o primeiro grupo de mensaxes'; $labels['nextmessage'] = 'Amosar a seguinte mensaxe'; -$labels['nextmessages'] = 'Amosar o seguinte grupo de mensaxes'; $labels['lastmessage'] = 'Amosar a última mensaxe'; -$labels['lastmessages'] = 'Amosar o último grupo de mensaxes'; $labels['backtolist'] = 'Voltar á lista de mensaxes'; -$labels['viewsource'] = 'Ver fonte'; +$labels['viewsource'] = 'Ver código fonte'; $labels['markmessages'] = 'Marcar mensaxes'; $labels['markread'] = 'Como lidas'; $labels['markunread'] = 'Como non lidas'; $labels['markflagged'] = 'Como marcadas'; $labels['markunflagged'] = 'Como non marcadas'; -$labels['messageactions'] = 'Máis accións...'; +$labels['moreactions'] = 'Máis accións...'; $labels['select'] = 'Seleccionar'; $labels['all'] = 'Todas'; $labels['none'] = 'Ningunha'; @@ -126,14 +124,14 @@ $labels['flagged'] = 'Marcadas'; $labels['unanswered'] = 'Non respostadas'; $labels['deleted'] = 'Marcadas como eliminadas'; $labels['invert'] = 'Inverter'; -$labels['filter'] = 'Filtro'; +$labels['filter'] = 'Filtrar'; $labels['list'] = 'Lista'; $labels['threads'] = 'FÃos'; $labels['expand-all'] = 'Expandir todos'; $labels['expand-unread'] = 'Expandir os non lidos'; $labels['collapse-all'] = 'Contraer todos'; -$labels['threaded'] = 'Como fÃos de discusión'; -$labels['autoexpand_threads'] = 'Expandir os fÃos das mensaxes'; +$labels['threaded'] = 'Agrupar conversas'; +$labels['autoexpand_threads'] = 'Expandir os fÃos de mensaxes'; $labels['do_expand'] = 'tódolos fÃos'; $labels['expand_only_unread'] = 'só con mensaxes non lidas'; $labels['fromto'] = 'Remitente/Destinatario'; @@ -169,12 +167,15 @@ $labels['charset'] = 'Codificación'; $labels['editortype'] = 'Tipo de editor'; $labels['returnreceipt'] = 'Notificación da entrega'; $labels['dsn'] = 'Notificación do estado de envÃo (DSN)'; +$labels['mailreplyintro'] = 'O $date, $sender escribiu:'; +$labels['originalmessage'] = 'Mensaxe orixinal'; $labels['editidents'] = 'Modificar identidades'; $labels['checkspelling'] = 'Revisar a ortografÃa'; $labels['resumeediting'] = 'Voltar á edición'; $labels['revertto'] = 'Voltar a'; $labels['attachments'] = 'Ficheiros anexos'; $labels['upload'] = 'Cargar'; +$labels['uploadprogress'] = '$percent ($current de $total)'; $labels['close'] = 'Pechar'; $labels['messageoptions'] = 'Opcións da mensaxe...'; $labels['low'] = 'Baixa'; @@ -183,13 +184,14 @@ $labels['normal'] = 'Normal'; $labels['high'] = 'Alta'; $labels['highest'] = 'A máis alta'; $labels['nosubject'] = '(Sen asunto)'; -$labels['showimages'] = 'Amosar imaxes'; -$labels['alwaysshow'] = 'Amosar sempre as imaxes nas mensaxes remitidas por $sender'; +$labels['showimages'] = 'Amosar as imaxes'; +$labels['alwaysshow'] = 'Amosar sempre as imaxes nas mensaxes de $sender'; +$labels['isdraft'] = 'Esta mensaxe é un borrador'; $labels['htmltoggle'] = 'HTML'; -$labels['plaintoggle'] = 'Texto claro'; +$labels['plaintoggle'] = 'Só texto'; $labels['savesentmessagein'] = 'Gardar a mensaxe enviada en'; $labels['dontsave'] = 'non gardar'; -$labels['maxuploadsize'] = 'O tamaño máximo permitido de ficheiro é de $size'; +$labels['maxuploadsize'] = 'O tamaño máximo permitido por ficheiro é de $size'; $labels['addcc'] = 'Engadir copia (CC)'; $labels['addbcc'] = 'Engadir copia oculta (BCC)'; $labels['addreplyto'] = 'Engadir respostar a (Reply-To)'; @@ -197,29 +199,77 @@ $labels['addfollowupto'] = 'Engadir respostar a todos (Followup-To)'; $labels['mdnrequest'] = 'O remitente desta mensaxe pediu ser notificado cando vostede a lea. Quere notificar ao remitente?'; $labels['receiptread'] = 'Notificación da entrega da mensaxe (lectura)'; $labels['yourmessage'] = 'Esta é unha notificación da entrega da súa mensaxe'; -$labels['receiptnote'] = 'Nota: Esta notificación só confirma que a mensaxe se abriu no computador do destinatario. Non asegura que o destinatario o lera ou entendera o seu contido.'; +$labels['receiptnote'] = 'Nota: Esta notificación só confirma que a mensaxe se abriu no computador do destinatario. Non asegura que o destinatario a lera ou entendera o seu contido.'; $labels['name'] = 'Nome completo'; $labels['firstname'] = 'Nome'; $labels['surname'] = 'Apelidos'; +$labels['middlename'] = 'Segundo nome'; +$labels['nameprefix'] = 'Prefixo'; +$labels['namesuffix'] = 'Sufixo'; +$labels['nickname'] = 'Alcume'; +$labels['jobtitle'] = 'Titulación'; +$labels['department'] = 'Departamento'; +$labels['gender'] = 'Xénero'; +$labels['maidenname'] = 'Nome de solteira'; $labels['email'] = 'Correo Electrónico'; +$labels['phone'] = 'Teléfono'; +$labels['address'] = 'Enderezo'; +$labels['street'] = 'Rúa'; +$labels['locality'] = 'Poboación'; +$labels['zipcode'] = 'Código postal'; +$labels['region'] = 'Provincia'; +$labels['country'] = 'PaÃs'; +$labels['birthday'] = 'Aniversario'; +$labels['anniversary'] = 'Aniversario'; +$labels['website'] = 'Sitio web'; +$labels['instantmessenger'] = 'MensaxerÃa instantánea'; +$labels['notes'] = 'Notes'; +$labels['male'] = 'home'; +$labels['female'] = 'muller'; +$labels['manager'] = 'Xerente'; +$labels['assistant'] = 'Asistente/a'; +$labels['spouse'] = 'Cónxuxe'; +$labels['allfields'] = 'Tódolos campos'; +$labels['search'] = 'Procurar'; +$labels['advsearch'] = 'Procura avanzada'; +$labels['other'] = 'Outro'; +$labels['typehome'] = 'Casa'; +$labels['typework'] = 'Traballo'; +$labels['typeother'] = 'Outro'; +$labels['typemobile'] = 'Móbil'; +$labels['typemain'] = 'Principal'; +$labels['typehomefax'] = 'Fax da casa'; +$labels['typeworkfax'] = 'Fax do traballo'; +$labels['typecar'] = 'Coche'; +$labels['typepager'] = 'Buscapersonas'; +$labels['typevideo'] = 'VÃdeo'; +$labels['typeassistant'] = 'Asistente'; +$labels['typehomepage'] = 'Páxina principal'; +$labels['typeblog'] = 'Blogue'; +$labels['typeprofile'] = 'Perfil'; +$labels['addfield'] = 'Engadir campo'; $labels['addcontact'] = 'Engadir novo contacto'; -$labels['editcontact'] = 'Editar contacto'; +$labels['editcontact'] = 'Modificar este contacto'; $labels['contacts'] = 'Contactos'; $labels['contactproperties'] = 'Propiedades do contacto'; +$labels['personalinfo'] = 'Información persoal'; $labels['edit'] = 'Editar'; $labels['cancel'] = 'Cancelar'; $labels['save'] = 'Gardar'; $labels['delete'] = 'Eliminar'; $labels['rename'] = 'Mudar o nome'; -$labels['newcontact'] = 'Crear novo contacto'; +$labels['addphoto'] = 'Engadir'; +$labels['replacephoto'] = 'SubstituÃr'; +$labels['newcontact'] = 'Novo contacto'; $labels['deletecontact'] = 'Eliminar os contactos seleccionados'; -$labels['composeto'] = 'Redactar mensaxe a'; +$labels['composeto'] = 'Redactar mensaxe para'; $labels['contactsfromto'] = 'Contactos do $from ao $to de $count'; $labels['print'] = 'Imprimir'; $labels['export'] = 'Exportar'; $labels['exportvcards'] = 'Exportar os contactos en formato vCard'; $labels['newcontactgroup'] = 'Crear novo grupo de contactos'; -$labels['groupactions'] = 'Accións cos grupos de contactos...'; +$labels['grouprename'] = 'Mudar o nome do grupo'; +$labels['groupdelete'] = 'Borrar o grupo'; $labels['previouspage'] = 'Amosar o grupo anterior'; $labels['firstpage'] = 'Amosar o primeiro grupo'; $labels['nextpage'] = 'Amosar o seguinte grupo'; @@ -227,13 +277,17 @@ $labels['lastpage'] = 'Amosar o último grupo'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; $labels['personaladrbook'] = 'Enderezos persoais'; +$labels['searchsave'] = 'Gardar procura'; +$labels['searchdelete'] = 'Eliminar procura'; $labels['import'] = 'Importar'; $labels['importcontacts'] = 'Importar contactos'; $labels['importfromfile'] = 'Importar desde ficheiro:'; +$labels['importtarget'] = 'Engadir contactos ao caderno de enderezos:'; $labels['importreplace'] = 'SubstituÃr completamente o caderno de enderezos'; $labels['importtext'] = 'Pode cargar contactos desde un caderno de enderezos xa existente.<br/>Polo de agora pódense importar enderezos usando o formato <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> '; $labels['done'] = 'Rematado'; $labels['settingsfor'] = 'Axustes de'; +$labels['about'] = 'Acerca de'; $labels['preferences'] = 'Preferencias'; $labels['userpreferences'] = 'Preferencias de usuario'; $labels['editpreferences'] = 'Editar preferencias de usuario'; @@ -245,6 +299,8 @@ $labels['edititem'] = 'Editar'; $labels['preferhtml'] = 'Prefiro HTML'; $labels['defaultcharset'] = 'Xogo de caracteres por omisión'; $labels['htmlmessage'] = 'Mensaxe HTML'; +$labels['dateformat'] = 'Formato da data'; +$labels['timeformat'] = 'Formato da hora'; $labels['prettydate'] = 'Data decorada'; $labels['setdefault'] = 'Usar como predeterminada'; $labels['autodetect'] = 'Detectar automáticamente'; @@ -252,11 +308,11 @@ $labels['language'] = 'Linguaxe'; $labels['timezone'] = 'Zona horaria'; $labels['pagesize'] = 'Liñas por páxina'; $labels['signature'] = 'Sinatura'; -$labels['dstactive'] = 'Cambio de hora'; +$labels['dstactive'] = 'Cambio de hora según horario de verán'; $labels['htmleditor'] = 'Redactar mensaxes HTML'; $labels['htmlonreply'] = 'só cando se resposte a unha mensaxe HTML'; $labels['htmlsignature'] = 'Sinatura HTML'; -$labels['previewpane'] = 'Amosar panel de previsualización'; +$labels['previewpane'] = 'Amosar previsualización'; $labels['skin'] = 'Aspecto da interface'; $labels['logoutclear'] = 'Baleirar o cubo do lixo ao saÃr'; $labels['logoutcompact'] = 'Compactar a caixa de entrada ao saÃr'; @@ -272,8 +328,8 @@ $labels['ignore'] = 'ignorar'; $labels['readwhendeleted'] = 'Marcar a mensaxe como lida ao eliminar'; $labels['flagfordeletion'] = 'Marcar a mensaxe para eliminar no canto de eliminar'; $labels['skipdeleted'] = 'Non amosar as mensaxes marcadas como eliminadas'; -$labels['deletealways'] = 'Borrar as mensaxes aÃnda se non se poden gardar na papeleira'; -$labels['showremoteimages'] = 'Amosar imaxes anexas remotas'; +$labels['deletealways'] = 'Eliminar as mensaxes aÃnda que non se poidan gardar no cubo do lixo'; +$labels['showremoteimages'] = 'Amosar as imaxes remotas'; $labels['fromknownsenders'] = 'de remitentes coñecidos'; $labels['always'] = 'sempre'; $labels['showinlineimages'] = 'Amosar as imaxes anexas baixo a mensaxe'; @@ -287,26 +343,26 @@ $labels['messagescomposition'] = 'Composición das mensaxes'; $labels['mimeparamfolding'] = 'Nomes dos ficheiros anexos'; $labels['2231folding'] = 'Conforme ao RFC 2231 (Thunderbird)'; $labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; -$labels['2047folding'] = 'Conforme ao RFC 2047 (other)'; +$labels['2047folding'] = 'Conforme ao RFC 2047 (outros)'; $labels['force7bit'] = 'Usar MIME para codificar caracteres de 8 bits'; $labels['advancedoptions'] = 'Opcións avanzadas'; $labels['focusonnewmessage'] = 'Enfocar o navegador se hai mensaxes novas'; $labels['checkallfolders'] = 'Procurar novas mensaxes en tódolos cartafoles'; -$labels['displaynext'] = 'Amosar a seguinte mensaxe despois de borrar ou mover unha mensaxe'; +$labels['displaynext'] = 'Logo de eliminar ou mover unha mensaxe ir á mensaxe seguinte'; $labels['mainoptions'] = 'Opcións principais'; $labels['section'] = 'Sección'; $labels['maintenance'] = 'Mantemento'; -$labels['newmessage'] = 'Nova mensaxe'; +$labels['newmessage'] = 'Mensaxes novas'; $labels['listoptions'] = 'Opcións de lista'; $labels['signatureoptions'] = 'Opcións da firma'; $labels['whenreplying'] = 'Ao respostar'; $labels['replytopposting'] = 'comezar a nova mensaxe enriba da orixinal'; $labels['replybottomposting'] = 'comezar a nova mensaxe embaixo da orixinal'; -$labels['replyremovesignature'] = 'Eliminar a firma orixinal da mensaxe ao respostar'; +$labels['replyremovesignature'] = 'Eliminar a firma do remitente ao respostar'; $labels['autoaddsignature'] = 'Engadir firma automáticamente'; -$labels['newmessageonly'] = 'só nas novas mensaxes'; +$labels['newmessageonly'] = 'só nas mensaxes novas'; $labels['replyandforwardonly'] = 'só nas respostas e reenvÃos'; -$labels['replysignaturepos'] = 'Ao respostar ou reenviar colocar a firma '; +$labels['replysignaturepos'] = 'Ao respostar ou reenviar colocar a firma '; $labels['belowquote'] = 'embaixo do texto citado'; $labels['abovequote'] = 'enriba do texto citado'; $labels['insertsignature'] = 'Engadir firma'; @@ -315,6 +371,14 @@ $labels['afternseconds'] = 'logo de $n segundos'; $labels['reqmdn'] = 'Solicitar sempre unha notificación da entrega'; $labels['reqdsn'] = 'Solicitar sempre unha notificación do estado de envÃo'; $labels['replysamefolder'] = 'Deixar as respostas no cartafol onde está a mensaxe á que se responde'; +$labels['defaultaddressbook'] = 'Engadir contactos ao caderno de enderezos seleccionado'; +$labels['autocompletesingle'] = 'Ignorar as direccións alternativas no autocompletado'; +$labels['spellcheckbeforesend'] = 'Revisar a ortografÃa antes de enviar unha mensaxe'; +$labels['spellcheckoptions'] = 'Opción da revisión ortográfica'; +$labels['spellcheckignoresyms'] = 'Ignorar as palabras con sÃmbolos'; +$labels['spellcheckignorenums'] = 'Ignorar as palabras con números'; +$labels['spellcheckignorecaps'] = 'Ignorar as palabras escritas en maiúsculas'; +$labels['addtodict'] = 'Engadir ao diccionario'; $labels['folder'] = 'Cartafol'; $labels['folders'] = 'Cartafoles'; $labels['foldername'] = 'Nome do cartafol'; @@ -331,9 +395,19 @@ $labels['location'] = 'Situación'; $labels['info'] = 'Información'; $labels['getfoldersize'] = 'Prema para calcular o tamaño do cartafol'; $labels['changesubscription'] = 'Prema para trocar a subscrición'; +$labels['foldertype'] = 'Tipo do cartafol'; +$labels['personalfolder'] = 'Cartafol privado'; +$labels['otherfolder'] = 'Cartafol de outro usuario'; +$labels['sharedfolder'] = 'Cartafol público'; $labels['sortby'] = 'Ordenar por'; $labels['sortasc'] = 'Orde ascendente'; $labels['sortdesc'] = 'Orde descendente'; +$labels['undo'] = 'Desfacer'; +$labels['plugin'] = 'Complemento'; +$labels['version'] = 'Versión'; +$labels['source'] = 'Fonte'; +$labels['license'] = 'Licencia'; +$labels['support'] = 'Obter axuda'; $labels['B'] = 'B'; $labels['KB'] = 'KiB'; $labels['MB'] = 'MiB'; diff --git a/program/localization/gl_ES/messages.inc b/program/localization/gl_ES/messages.inc index 521a67a..c872c8e 100644 --- a/program/localization/gl_ES/messages.inc +++ b/program/localization/gl_ES/messages.inc @@ -5,7 +5,7 @@ | language/gl_ES/messages.inc | | | | Language file of the Roundcube Webmail client | -| Copyright (C) 2005-2010, The Roundcube Dev Team | +| Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ @@ -15,124 +15,145 @@ */ $messages = array(); -$messages['loginfailed'] = 'Fallou o acceso'; -$messages['cookiesdisabled'] = 'O seu navegador non acepta galletas'; -$messages['sessionerror'] = 'A súa sesión non é válida ou expirou'; -$messages['imaperror'] = 'Fallou a conexión co servidor IMAP'; +$messages['loginfailed'] = 'O contrasinal ou o nome de usuario son incorrectos.'; +$messages['cookiesdisabled'] = 'O seu navegador non acepta galletas.'; +$messages['sessionerror'] = 'A súa sesión non é válida ou expirou.'; +$messages['imaperror'] = 'Fallou a conexión co servidor IMAP.'; $messages['servererror'] = 'Erro do servidor!'; $messages['servererrormsg'] = 'Erro do servidor: $msg'; -$messages['errorreadonly'] = 'Non foi posible realizar a operación. O cartafol é de só lectura'; +$messages['dberror'] = 'Erro na base de datos!'; +$messages['errorreadonly'] = 'Non foi posible realizar a operación. O cartafol é de só lectura.'; $messages['errornoperm'] = 'Non foi posible realizar a operación. Permiso denegado.'; $messages['invalidrequest'] = 'Petición inválida!. Non se gardou ningún dato.'; -$messages['nomessagesfound'] = 'Non se atoparon mensaxes nesta caixa de correo'; +$messages['nomessagesfound'] = 'Non se atoparon mensaxes nesta caixa de correo.'; $messages['loggedout'] = 'Rematou correctamente a súa sesión. Ata logo!'; -$messages['mailboxempty'] = 'A caixa de correo está vacÃa'; +$messages['mailboxempty'] = 'A caixa de correo está vacÃa.'; $messages['loading'] = 'Cargando...'; $messages['uploading'] = 'Cargando ficheiro...'; +$messages['uploadingmany'] = 'Cargando ficheiros...'; $messages['loadingdata'] = 'Cargando datos...'; $messages['checkingmail'] = 'à procura de novas mensaxes...'; $messages['sendingmessage'] = 'Enviando mensaxe...'; -$messages['messagesent'] = 'A mensaxe enviouse correctamente'; +$messages['messagesent'] = 'A mensaxe enviouse correctamente.'; $messages['savingmessage'] = 'Gardando mensaxe...'; $messages['messagesaved'] = 'A mensaxe gardouse en "Borradores"'; -$messages['successfullysaved'] = 'Gardada correctamente'; -$messages['addedsuccessfully'] = 'O contacto engadiuse correctamente ao caderno de enderezos'; -$messages['contactexists'] = 'Xa existe un contacto con este enderezo de correo electrónico'; -$messages['blockedimages'] = 'Estanse a bloquear as imaxes remotas para protexer a súa privacidade'; -$messages['encryptedmessage'] = 'SÃntoo!. Non se pode amosar a mensaxe porque está cifrada'; -$messages['nocontactsfound'] = 'Non se atoparon contactos'; -$messages['contactnotfound'] = 'Non se atopou o contacto solicitado'; -$messages['sendingfailed'] = 'Fallou o envÃo da mensaxe'; -$messages['senttooquickly'] = 'Por favor, espere $sec segundos antes de enviar esta mensaxe'; -$messages['errorsavingsent'] = 'Ocurriu un erro mentres se gardaba a mensaxe enviada'; -$messages['errorsaving'] = 'Ocurriu un erro mentres se gardaba'; -$messages['errormoving'] = 'Non foi posible mover a(s) mensaxe(s)'; -$messages['errorcopying'] = 'Non foi posible copiar a(s) mensaxe(s)'; -$messages['errordeleting'] = 'Non foi posible eliminar a(s) mensaxe(s)'; -$messages['errormarking'] = 'Non foi posible marcar a(s) mensaxe(s)'; +$messages['successfullysaved'] = 'Gardado correctamente.'; +$messages['addedsuccessfully'] = 'O contacto engadiuse correctamente ao caderno de enderezos.'; +$messages['contactexists'] = 'Xa existe un contacto con este enderezo de correo electrónico.'; +$messages['contactnameexists'] = 'Xa existe un contacto con este nome.'; +$messages['blockedimages'] = 'Estanse a bloquear as imaxes remotas para protexer a súa privacidade.'; +$messages['encryptedmessage'] = 'Non se pode amosar a mensaxe porque está cifrada.'; +$messages['nocontactsfound'] = 'Non se atoparon contactos.'; +$messages['contactnotfound'] = 'Non se atopou o contacto solicitado.'; +$messages['contactsearchonly'] = 'Introduza algún termo para atopar contactos'; +$messages['sendingfailed'] = 'Fallou o envÃo da mensaxe.'; +$messages['senttooquickly'] = 'Por favor, espere $sec segundos antes de enviar esta mensaxe.'; +$messages['errorsavingsent'] = 'Ocurriu un erro mentres se gardaba a mensaxe enviada.'; +$messages['errorsaving'] = 'Ocurriu un erro mentres se gardaba.'; +$messages['errormoving'] = 'Non foi posible mover a(s) mensaxe(s).'; +$messages['errorcopying'] = 'Non foi posible copiar a(s) mensaxe(s).'; +$messages['errordeleting'] = 'Non foi posible eliminar a(s) mensaxe(s).'; +$messages['errormarking'] = 'Non foi posible marcar a(s) mensaxe(s).'; $messages['deletecontactconfirm'] = 'Quere eliminar o(s) contacto(s) seleccionado(s)?'; +$messages['deletegroupconfirm'] = 'Quere eliminar o grupo seleccionado?'; $messages['deletemessagesconfirm'] = 'Quere eliminar a(s) mensaxe(s) seleccionadas?'; $messages['deletefolderconfirm'] = 'Quere eliminar este cartafol?'; $messages['purgefolderconfirm'] = 'Quere eliminar tódalas mensaxes neste cartafol?'; +$messages['contactdeleting'] = 'Eliminando o(s) contacto(s)...'; +$messages['groupdeleting'] = 'Eliminando o grupo...'; $messages['folderdeleting'] = 'Eliminando o cartafol...'; $messages['foldermoving'] = 'Movendo o cartafol...'; $messages['foldersubscribing'] = 'Subscribindo o cartafol...'; $messages['folderunsubscribing'] = 'Desubscribindo o cartafol...'; -$messages['formincomplete'] = 'Non se cumprimentou completamente o formulario'; -$messages['noemailwarning'] = 'Por favor, introduza un enderezo de correo electrónico válido'; -$messages['nonamewarning'] = 'Por favor, introduza un nome'; -$messages['nopagesizewarning'] = 'Por favor, introduza un tamaño de páxina'; -$messages['nosenderwarning'] = 'Por favor, introduza o enderezo de correo electrónico do remitente'; -$messages['norecipientwarning'] = 'Por favor, introduza polo menos un destinatario'; -$messages['nosubjectwarning'] = 'O campo "Asunto" está baleiro. Quere introducir un?'; +$messages['formincomplete'] = 'Non se cumprimentou completamente o formulario.'; +$messages['noemailwarning'] = 'Por favor, introduza un enderezo de correo electrónico válido.'; +$messages['nonamewarning'] = 'Por favor, introduza un nome.'; +$messages['nopagesizewarning'] = 'Por favor, introduza un tamaño de páxina.'; +$messages['nosenderwarning'] = 'Por favor, introduza o enderezo de correo electrónico do remitente.'; +$messages['norecipientwarning'] = 'Por favor, introduza polo menos un destinatario.'; +$messages['nosubjectwarning'] = 'O campo "Asunto" está baleiro. Desexa completalo?'; $messages['nobodywarning'] = 'Quere enviar esta mensaxe sen texto?'; $messages['notsentwarning'] = 'A mensaxe non se enviou. Quere descartala?'; -$messages['noldapserver'] = 'Por favor, elixa un servidor LDAP para buscar'; -$messages['nocontactsreturned'] = 'Non se atoparon contactos'; -$messages['nosearchname'] = 'Por favor, introduza un contacto ou un enderezo de correo electrónico'; +$messages['noldapserver'] = 'Por favor, elixa un servidor LDAP para buscar.'; +$messages['nosearchname'] = 'Por favor, introduza un nome ou un enderezo de correo electrónico.'; $messages['notuploadedwarning'] = 'AÃnda non se cargaron tódolos ficheiros. Por favor, agarde ou cancele a carga.'; -$messages['searchsuccessful'] = 'Atopáronse $nr mensaxes'; -$messages['searchnomatch'] = 'A busca non atopou coincidencias'; +$messages['searchsuccessful'] = 'Atopáronse $nr mensaxes.'; +$messages['contactsearchsuccessful'] = 'Atopáronse $nr contactos.'; +$messages['searchnomatch'] = 'A busca non atopou coincidencias.'; $messages['searching'] = 'Buscando...'; $messages['checking'] = 'Comprobando...'; -$messages['nospellerrors'] = 'Non hai erros ortográficos'; -$messages['folderdeleted'] = 'O cartafol eliminouse correctamente'; -$messages['foldersubscribed'] = 'O cartafol suscribiuse correctamente'; -$messages['folderunsubscribed'] = 'O cartafol desuscribiuse correctamente'; -$messages['folderpurged'] = 'O cartafol purgouse correctamente'; -$messages['folderexpunged'] = 'O cartafol baleirouse correctamente'; -$messages['deletedsuccessfully'] = 'Eliminouse correctamente'; +$messages['nospellerrors'] = 'Non hai erros ortográficos.'; +$messages['folderdeleted'] = 'O cartafol eliminouse correctamente.'; +$messages['foldersubscribed'] = 'O cartafol suscribiuse correctamente.'; +$messages['folderunsubscribed'] = 'O cartafol desuscribiuse correctamente.'; +$messages['folderpurged'] = 'O cartafol purgouse correctamente.'; +$messages['folderexpunged'] = 'O cartafol baleirouse correctamente.'; +$messages['deletedsuccessfully'] = 'Eliminouse correctamente.'; $messages['converting'] = 'Eliminando o formato da mensaxe...'; -$messages['messageopenerror'] = 'Non foi posible cargar a mensaxe desde o servidor'; -$messages['fileuploaderror'] = 'Fallou a carga do ficheiro'; -$messages['filesizeerror'] = 'O ficheiro cargado é máis grande que o tamaño máximo de $size'; -$messages['copysuccess'] = 'Copiáronse correctamente $nr enderezos'; -$messages['copyerror'] = 'Non foi posible copiar ningún enderezo'; -$messages['sourceisreadonly'] = 'A orixe é de só lectura'; -$messages['errorsavingcontact'] = 'Non foi posible gardar o contacto'; +$messages['messageopenerror'] = 'Non foi posible cargar a mensaxe desde o servidor.'; +$messages['fileuploaderror'] = 'Fallou a carga do ficheiro.'; +$messages['filesizeerror'] = 'O ficheiro cargado é máis grande que o tamaño máximo de $size.'; +$messages['copysuccess'] = 'Copiáronse correctamente $nr enderezos.'; +$messages['copyerror'] = 'Non foi posible copiar ningún enderezo.'; +$messages['sourceisreadonly'] = 'A orixe é de só lectura.'; +$messages['errorsavingcontact'] = 'Non foi posible gardar o contacto.'; $messages['movingmessage'] = 'Movendo a(s) mensaxe(s)...'; $messages['copyingmessage'] = 'Copiando a(s) mensaxe(s)...'; +$messages['copyingcontact'] = 'Copiando o(s) contacto(s)...'; $messages['deletingmessage'] = 'Eliminando a(s) mensaxe(s)...'; $messages['markingmessage'] = 'Marcando a(s) mensaxe(s)...'; -$messages['receiptsent'] = 'A notificación da entrega enviouse correctamente'; -$messages['errorsendingreceipt'] = 'Non foi posible enviar a notificación da entrega'; -$messages['nodeletelastidentity'] = 'Non pode eliminar esta identidade, é a última'; -$messages['forbiddencharacter'] = 'O nome do cartafol contén un carácter non válido'; -$messages['selectimportfile'] = 'Por favor, escolla un ficheiro para cargar'; -$messages['addresswriterror'] = 'Non se pode escribir no caderno de enderezos que escolleu'; -$messages['contactaddedtogroup'] = 'EngadÃronse correctamente os contactos a este grupo'; -$messages['contactremovedfromgroup'] = 'SuprimÃronse correctamente os contactos de este grupo'; -$messages['importwait'] = 'Estou a importar. Por favor, agarde...'; -$messages['importerror'] = 'Fallou a importación! O ficheiro que cargou non é un vCard correcto.'; +$messages['addingmember'] = 'Engadindo o(s) contacto(s) ao grupo...'; +$messages['removingmember'] = 'Eliminando o(s) contacto(s) do grupo...'; +$messages['receiptsent'] = 'A notificación da entrega enviouse correctamente.'; +$messages['errorsendingreceipt'] = 'Non foi posible enviar a notificación da entrega.'; +$messages['nodeletelastidentity'] = 'Non pode eliminar esta identidade, é a última.'; +$messages['forbiddencharacter'] = 'O nome do cartafol contén un carácter non válido.'; +$messages['selectimportfile'] = 'Por favor, escolla un ficheiro para cargar.'; +$messages['addresswriterror'] = 'Non se pode escribir no caderno de enderezos que escolleu.'; +$messages['contactaddedtogroup'] = 'Engadiuse correctamente o contacto a este grupo.'; +$messages['contactremovedfromgroup'] = 'Suprimiuse correctamente o contacto deste grupo.'; +$messages['importwait'] = 'A importar. Por favor, agarde...'; +$messages['importerror'] = 'Produciuse un erro na importación. O ficheiro que cargou non é un vCard correcto.'; $messages['importconfirm'] = '<b>Importáronse correctamente $inserted contactos. Ignoráronse $skipped contactos que xa existÃan</b>:<p><em>$names</em></p>'; -$messages['opnotpermitted'] = 'Operación non permitida'; -$messages['nofromaddress'] = 'Falta o enderezo de correo electrónico na identidade que escolleu'; +$messages['importconfirmskipped'] = '<b>Ignoráronse $skipped existing entradas</b>'; +$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?'; -$messages['httpreceivedencrypterror'] = 'Produciuse un erro fatal de configuración. Contacte ao administrador inmediatamente. <b>Non foi posible enviar a súa mensaxe.</b>'; -$messages['smtpconnerror'] = 'Erro SMTP ($code): Fallou a conexión co servidor'; -$messages['smtpautherror'] = 'Erro SMTP ($code): Fallou a autenticación'; -$messages['smtpfromerror'] = 'Erro SMTP ($code): Non foi posible establecer o remitente "$from" ($msg)'; -$messages['smtptoerror'] = 'Erro SMTP ($code): Non foi posible engadir o destinatario "$to" ($msg)'; -$messages['smtprecipientserror'] = 'Erro SMTP: Non se pode analizar a lista de destinatarios'; -$messages['smtpdsnerror'] = 'Erro SMTP: Non hai soporte para notificacións do estado de envÃo (DSN)'; +$messages['httpreceivedencrypterror'] = 'Produciuse un erro fatal de configuración. Contacte ao administrador inmediatamente. <b>Non se enviou a súa mensaxe.</b>'; +$messages['smtpconnerror'] = 'Erro SMTP ($code): Fallou a conexión co servidor.'; +$messages['smtpautherror'] = 'Erro SMTP ($code): Fallou a autenticación.'; +$messages['smtpfromerror'] = 'Erro SMTP ($code): Non foi posible establecer o remitente "$from" ($msg).'; +$messages['smtptoerror'] = 'Erro SMTP ($code): Non foi posible engadir o destinatario "$to" ($msg).'; +$messages['smtprecipientserror'] = 'Erro SMTP: Non se pode analizar a lista de destinatarios.'; +$messages['smtpdsnerror'] = 'Erro SMTP: Non hai soporte para notificacións do estado de envÃo (DSN).'; $messages['smtperror'] = 'Erro SMTP: $msg'; -$messages['emailformaterror'] = 'O enderezo de correo electrónico é incorrecto: $email'; +$messages['emailformaterror'] = 'O enderezo de correo electrónico é incorrecto: $email.'; $messages['toomanyrecipients'] = 'Especificou destinatarios de máis. Por favor, redúzaos a un máximo de $max.'; $messages['maxgroupmembersreached'] = 'O número de membros do grupo excede o máximo de $max.'; $messages['internalerror'] = 'Ocurriu un erro interno. Por favor, probe outra vez.'; -$messages['contactdelerror'] = 'Non foi posible borrar o(s) contacto(s)'; -$messages['contactdeleted'] = 'Borráronse correctamente o(s) contacto(s)'; -$messages['groupdeleted'] = 'Borrouse correctamente o grupo'; -$messages['grouprenamed'] = 'Mudouse correctamente o nome do grupo'; -$messages['groupcreated'] = 'Creouse correctamente o grupo'; -$messages['messagedeleted'] = 'Borráronse correctamente a(s) mensaxe(s)'; -$messages['messagemoved'] = 'Movéronse correctamente a(s) mensaxe(s)'; -$messages['messagecopied'] = 'Copiáronse correctamente a(s) mensaxe(s)'; -$messages['messagemarked'] = 'Marcáronse correctamente a(s) mensaxe(s)'; -$messages['autocompletechars'] = 'Introduza polo menos $min caracteres para autocompletar'; -$messages['namecannotbeempty'] = 'O nome non pode estar baleiro'; -$messages['nametoolong'] = 'O nome é longo de máis'; -$messages['folderupdated'] = 'O cartafol actualizouse correctamente'; -$messages['foldercreated'] = 'O cartafol creouse correctamente'; +$messages['contactdelerror'] = 'Non foi posible eliminar o(s) contacto(s).'; +$messages['contactdeleted'] = 'Borráronse correctamente o(s) contacto(s).'; +$messages['contactrestoreerror'] = 'Non foi posible restaurar o(s) contacto(s) borrado(s).'; +$messages['contactrestored'] = 'Restauráronse correctamente o(s) contacto(s).'; +$messages['groupdeleted'] = 'Borrouse correctamente o grupo.'; +$messages['grouprenamed'] = 'Mudouse correctamente o nome do grupo.'; +$messages['groupcreated'] = 'Creouse correctamente o grupo.'; +$messages['savedsearchdeleted'] = 'Borrouse correctamente a procura gardada. '; +$messages['savedsearchdeleteerror'] = 'Non foi posible borrar a procura gardada.'; +$messages['savedsearchcreated'] = 'Creouse correctamente a procura gardada.'; +$messages['savedsearchcreateerror'] = 'Non foi posible crear a procura gardada.'; +$messages['messagedeleted'] = 'Borráronse correctamente a(s) mensaxe(s).'; +$messages['messagemoved'] = 'Movéronse correctamente a(s) mensaxe(s).'; +$messages['messagecopied'] = 'Copiáronse correctamente a(s) mensaxe(s).'; +$messages['messagemarked'] = 'Marcáronse correctamente a(s) mensaxe(s).'; +$messages['autocompletechars'] = 'Introduza polo menos $min caracteres para autocompletar.'; +$messages['autocompletemore'] = 'Atopáronse máis entradas concidintes. Por favor, introduza máis caracteres.'; +$messages['namecannotbeempty'] = 'O nome non pode estar baleiro.'; +$messages['nametoolong'] = 'O nome é longo de máis.'; +$messages['folderupdated'] = 'O cartafol actualizouse correctamente.'; +$messages['foldercreated'] = 'O cartafol creouse correctamente.'; +$messages['invalidimageformat'] = 'O formato da imaxe non é válido.'; +$messages['mispellingsfound'] = 'Atopáronse erros ortográficos na mensaxe.'; +$messages['parentnotwritable'] = 'Non foi posible crear/mover o cartafol no cartafol padre escollido porque non ten permisos.'; ?> diff --git a/program/localization/he_IL/labels.inc b/program/localization/he_IL/labels.inc index 1058979..1dd15f4 100644 --- a/program/localization/he_IL/labels.inc +++ b/program/localization/he_IL/labels.inc @@ -11,7 +11,7 @@ +-----------------------------------------------------------------------+ | Author: Moshe Leibovitch <moish@mln.co.il> | | Updates: Noor Dawod <noor@comrax.com> | -| Updates: Moshe Leibovitch <moish@mln.co.il> 05092011 | +| Updates: Moshe Leibovitch <moish@mln.co.il> 28112011 | +-----------------------------------------------------------------------+ */ @@ -115,7 +115,7 @@ $labels['markread'] = '×× ×§×¨××'; $labels['markunread'] = '××× × ×§×¨××'; $labels['markflagged'] = '××ס×××'; $labels['markunflagged'] = '××× ×ס×××'; -$labels['messageactions'] = 'פע×××ת × ×ספ×ת'; +$labels['moreactions'] = 'פע×××ת × ×ספ×ת...'; $labels['select'] = '×××ר×'; $labels['all'] = '×××'; $labels['none'] = '××××'; @@ -187,6 +187,7 @@ $labels['highest'] = '×××× ×××תר'; $labels['nosubject'] = '(××× × ×ש×)'; $labels['showimages'] = '×צ×ת ת××× ×ת'; $labels['alwaysshow'] = '$sender ת××× ××צ×× ×ª××× ×ת ××ת '; +$labels['isdraft'] = '×× ××××× ×©× ××××¢×'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = '××× ×¢×צ××'; $labels['savesentmessagein'] = '×××× ×ש××ר ×××××¢×?'; @@ -268,7 +269,6 @@ $labels['print'] = '××פס×'; $labels['export'] = '××צ××'; $labels['exportvcards'] = '××צ×× ×× ×©× ×§×©×¨ ×פ×ר×× vCard '; $labels['newcontactgroup'] = '×צ×רת ×§×××¦× ×××©× ×©× ×× ×©× ×§×©×¨'; -$labels['groupactions'] = 'פע×××ת ×¢× ×§××צת ×× ×©× ×קשר...'; $labels['grouprename'] = 'ש×× ×× ×©× ×§××צ×'; $labels['groupdelete'] = '×××קת ×§××צ×'; $labels['previouspage'] = '×צ×ת ××§×××¦× ××§×××ת'; @@ -278,6 +278,8 @@ $labels['lastpage'] = '×צ×ת ××§×××¦× ×××ר×× ×'; $labels['group'] = '×§××צ×'; $labels['groups'] = '×§××צ×ת'; $labels['personaladrbook'] = '×ת×××ת פר×××ת'; +$labels['searchsave'] = 'ש××רת ×××פ×ש'; +$labels['searchdelete'] = '×××קת ×××פ×ש'; $labels['import'] = '×××××'; $labels['importcontacts'] = '××××× ×× ×©× ×§×©×¨'; $labels['importfromfile'] = '××××× ××§×××¥'; @@ -286,6 +288,7 @@ $labels['importreplace'] = '×××פת ×× ×¤× ×§×¡ ××ת×××ת'; $labels['importtext'] = '<a href="http://en.wikipedia.org/wiki/VCard">vCard</a> × ××ª× ××××× ×× ×©× ×§×©×¨ ××¤× ×§×¡ ×ת×××ת ×§×××. ×× × ×ª××××× ×פ×ר××'; $labels['done'] = '××צע'; $labels['settingsfor'] = '×××ר×ת ×¢××ר'; +$labels['about'] = '××××ת'; $labels['preferences'] = '××¢×פ×ת'; $labels['userpreferences'] = '××¢×פ×ת ×שת×ש'; $labels['editpreferences'] = 'ער××× ×©× ××¢×פ×ת ×שת×ש'; @@ -297,6 +300,8 @@ $labels['edititem'] = 'ער××ת רש×××'; $labels['preferhtml'] = '×צ×ת HTML'; $labels['defaultcharset'] = '×ר×רת ×××× ×©× ×ª××××'; $labels['htmlmessage'] = 'ת××× HTML'; +$labels['dateformat'] = 'פ×ר×× ×ת×ר××'; +$labels['timeformat'] = 'פ×ר×× ×שע×'; $labels['prettydate'] = 'ת×ר×××× ××¢×צ×××'; $labels['setdefault'] = '×§×××¢× ××ר×רת ××××'; $labels['autodetect'] = '×××××××'; @@ -368,7 +373,13 @@ $labels['reqmdn'] = 'ת××× ×ש ××ר×ש ××ש×ר ×§×××'; $labels['reqdsn'] = 'ת××× ××קש ××××¢× ×¢× ××¦× ××ס×ר×'; $labels['replysamefolder'] = '×××¢× × ×ש×ר ×ת××§×× ×©× ×××××¢× ×××§×ר×ת'; $labels['defaultaddressbook'] = '××ספת ×× ×©× ×§×©×¨ ×ספר ××ת×××ת ×©× ××ר'; +$labels['autocompletesingle'] = '×××× ×¢× ×ת××ת ×××ר ××××פ×ת ×עת ש×××ש ××ש××× ×××××××ת ×©× ××§×××'; $labels['spellcheckbeforesend'] = '×××קת ×××ת ××¤× × ××ש×××'; +$labels['spellcheckoptions'] = '×פשר××ת ×××קת ×××ת'; +$labels['spellcheckignoresyms'] = '×תע×××ת ×××××× ××××××ת ס××××'; +$labels['spellcheckignorenums'] = '×תע×××ת ×××××× ××××××ת ×ספר××'; +$labels['spellcheckignorecaps'] = '×תע×××ת ×××××× ×¢× ××תצ××ת ר×ש××ת'; +$labels['addtodict'] = '×××¡×¤× ××××××'; $labels['folder'] = 'ת××§'; $labels['folders'] = 'ת××§××'; $labels['foldername'] = '×©× ×ª××§'; @@ -393,6 +404,11 @@ $labels['sortby'] = '×××× ×פ×'; $labels['sortasc'] = '×××× ×ס×ר ×¢×××'; $labels['sortdesc'] = '×××× ×ס×ר ××ר×'; $labels['undo'] = '××××× ×©×× ××'; +$labels['plugin'] = 'ת×סף ת××× ×'; +$labels['version'] = '××רס×'; +$labels['source'] = '××§×ר'; +$labels['license'] = 'רש×××'; +$labels['support'] = '×§××ת ת××××'; $labels['B'] = '××××'; $labels['KB'] = '×§"×'; $labels['MB'] = '×"×'; diff --git a/program/localization/he_IL/messages.inc b/program/localization/he_IL/messages.inc index affa0d9..51de7c7 100644 --- a/program/localization/he_IL/messages.inc +++ b/program/localization/he_IL/messages.inc @@ -11,7 +11,7 @@ +-----------------------------------------------------------------------+ | Author: Moshe Leibovitch <moish@mln.co.il> | | Updates: Noor Dawod <noor@comrax.com> | -| Updates: Moshe Leibovitch <moish@mln.co.il> 08082011 | +| Updates: Moshe Leibovitch <moish@mln.co.il> 28112011 | +-----------------------------------------------------------------------+ */ @@ -47,6 +47,7 @@ $messages['blockedimages'] = 'ת××× ×ת ×שרת ××ר × ×ס×× ××× × $messages['encryptedmessage'] = '×× ×××עת ×××¦×¤× ×ª ××× × ××ª× ××צ×××'; $messages['nocontactsfound'] = '×× × ×צ×× ×× ×©× ×§×©×¨'; $messages['contactnotfound'] = '××ש ×קשר ××××קש ×× × ×צ×'; +$messages['contactsearchonly'] = '×ש ×××§×ש ×פת××ת ××פ×ש ××× ××צ×× ×× ×©× ×§×©×¨'; $messages['sendingfailed'] = 'ש×××ת ×××××¢× × ×ש××'; $messages['senttooquickly'] = '× × ×××ת×× $sec ×©× ××ת ××¤× × ×ס×רת ××××¢× ××'; $messages['errorsavingsent'] = '× ×ר×× ×©×××× ××××× ×©××רת ×××××¢× ×ת××§ ××××¢×ת ××צ××ת'; @@ -60,6 +61,7 @@ $messages['deletegroupconfirm'] = '××× ××× ×רצ×× × ×××××§ ×ת × $messages['deletemessagesconfirm'] = '××× ×××××§ ×ת ×××××¢×ת ××ס××× ×ת?'; $messages['deletefolderconfirm'] = '××× ×××××§ ת××§ ××?'; $messages['purgefolderconfirm'] = '××× ×××××§ ×ת ×× ×××××¢×ת ×ת××§ ××?'; +$messages['contactdeleting'] = '×× ×©× ×§×©×¨ × ×××§××...'; $messages['groupdeleting'] = '×××קת ×§××צ×...'; $messages['folderdeleting'] = '×ת××§×× × ××קת...'; $messages['foldermoving'] = '××¢×רת ת××§××...'; @@ -75,10 +77,10 @@ $messages['nosubjectwarning'] = 'ש×רת ×× ××©× ×¨××§×. ××× ×רצ×× $messages['nobodywarning'] = '××× ×ש××× ××××¢× ××× ×ª×××?'; $messages['notsentwarning'] = '×××××¢× ×× × ×©×××. ××× ××××?'; $messages['noldapserver'] = '× × ××××ר שרת ×ת×××ת ×××פ×ש'; -$messages['nocontactsreturned'] = '×× × ×צ×× ×× ×©× ×§×©×¨'; $messages['nosearchname'] = '× × ×××ס××£ ××ש קשר ×× ×ת××ת ×××\"×'; $messages['notuploadedwarning'] = '×¢×××× ×× ×××¢×× ×× ××§×צ××. × × ××××ת ×× ×××× ×פע×××.'; $messages['searchsuccessful'] = '× ×צ×× $nr ××××¢×ת'; +$messages['contactsearchsuccessful'] = '× ×צ×× $nr ×× ×©× ×§×©×¨'; $messages['searchnomatch'] = 'ת×צ×ת ×××פ×ש ר××§×'; $messages['searching'] = '××פ×ש...'; $messages['checking'] = '××××§×...'; @@ -125,7 +127,6 @@ $messages['smtpautherror'] = 'SMTP ($code): ××××××ת × ×ש××'; $messages['smtpfromerror'] = ' ($msg) SMTP ($code): "$from" ×× × ×¨×©×× ×ת××ת ×ש×××'; $messages['smtptoerror'] = ' ($msg) SMTP ($code): "$to" ×× × ×¨×©×× ×ת××ת ×××§××'; $messages['smtprecipientserror'] = 'SMTP : ×× × ××ª× ××¤×¢× × ×¨×©××ת × ××¢× ××'; -$messages['smtpdsnerror'] = 'ש×××ת SMTP: ××× ×ª×××× ×××××¢× ×¢× ××¦× ×ס×ר×'; $messages['smtperror'] = 'SMTP: $msg'; $messages['emailformaterror'] = '$email ×ת××ת ×××"× ×©××××'; $messages['toomanyrecipients'] = '××תר ××× × ××¢× ××. ×ש ×××§××× ××¡×¤×¨× × - $max'; @@ -138,11 +139,16 @@ $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['autocompletemore'] = '× ×צ×× ×¨×©×××ת × ×ספ×ת. × × ×××§×ש ת×××× × ×ספ××.'; $messages['namecannotbeempty'] = '××©× ××× × ×××× ××××ת ר××§'; $messages['nametoolong'] = '××©× ×ר×× ×××'; $messages['folderupdated'] = '×ת××§ ×¢×××× ××צ×××'; @@ -150,5 +156,6 @@ $messages['foldercreated'] = '×ת××§ × ×צר ××צ×××'; $messages['invalidimageformat'] = 'פ×ר×× ×ª××× × ×× ×××§×'; $messages['mispellingsfound'] = '×ת××× ×©××××ת ×ת×× ×××××¢×'; $messages['parentnotwritable'] = '×× × ××ª× ××צ×ר/×××¢××ר ת××§×× ×ת×× ×ª××§×ת ××× ×©× ××ר×. ××× ×רש×× ×××ש×.'; +$messages['messagetoobig'] = '×××××¢× ××××× ××¢×ר ×××××ת ××¢×××× ×©× ×ת××× ×'; ?> diff --git a/program/localization/hr_HR/messages.inc b/program/localization/hr_HR/messages.inc index ad0974e..725a7eb 100644 --- a/program/localization/hr_HR/messages.inc +++ b/program/localization/hr_HR/messages.inc @@ -14,7 +14,7 @@ | Tanja DobriÄiÄ <tanja.dobricic@everymail.info> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5139 2011-08-28 09:47:15Z alec $ */ @@ -25,7 +25,7 @@ $messages['sessionerror'] = 'Morate se ponovno ulogirati'; $messages['imaperror'] = 'NeuspjeÅ¡na veza na IMAP server'; $messages['servererror'] = 'GreÅ¡ka poslužitelja'; $messages['servererrormsg'] = 'GreÅ¡ka na serveru: $msg'; -$messages['databaserror'] = 'GreÅ¡ka baze podataka!'; +$messages['dberror'] = 'GreÅ¡ka baze podataka!'; $messages['errorreadonly'] = 'NemoguÄa izvedba operacije. Mapa je samo za Äitanje.'; $messages['errornoperm'] = 'NemoguÄa izvedba operacije. Dozvola odbijena.'; $messages['invalidrequest'] = 'Nepravilan zahtijev! Podaci nisu spremljeni.'; diff --git a/program/localization/hu_HU/labels.inc b/program/localization/hu_HU/labels.inc index 4673717..3982a64 100644 --- a/program/localization/hu_HU/labels.inc +++ b/program/localization/hu_HU/labels.inc @@ -13,9 +13,10 @@ | Author: Zark Bonfire <ikkhares at gmail dot com> | | Peter Szabo <pete at teamlupus dot hu> | | Barnabas Bona <bsi at hosember dot hu> | +| Gabor Veliczky <hosting at jugiter dot net> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -27,7 +28,7 @@ $labels['server'] = 'Szerver'; $labels['login'] = 'Belépés'; $labels['logout'] = 'Kijelentkezés'; $labels['mail'] = 'E-mail'; -$labels['settings'] = 'Egyéni beállÃtások'; +$labels['settings'] = 'BeállÃtások'; $labels['addressbook'] = 'CÃmjegyzék'; $labels['inbox'] = 'Ãrkezett levelek'; $labels['drafts'] = 'Piszkozatok'; @@ -119,7 +120,7 @@ $labels['markread'] = 'Olvasottként'; $labels['markunread'] = 'Olvasatlanként'; $labels['markflagged'] = 'Jelöltként'; $labels['markunflagged'] = 'Jelöletlenként'; -$labels['messageactions'] = 'További lehetÅségek...'; +$labels['moreactions'] = 'További műveletek...'; $labels['select'] = 'Kijelölés'; $labels['all'] = 'Ãsszes'; $labels['none'] = 'Nincs'; @@ -172,12 +173,15 @@ $labels['charset'] = 'Karakterkészlet'; $labels['editortype'] = 'SzerkesztÅ tÃpusa'; $labels['returnreceipt'] = 'Olvasási visszaigazolás'; $labels['dsn'] = 'KézbesÃtési visszaigazolás'; +$labels['mailreplyintro'] = '$date idÅpontban $sender ezt Ãrta:'; +$labels['originalmessage'] = 'Eredeti üzenet'; $labels['editidents'] = 'AzonosÃtók szerkesztése'; $labels['checkspelling'] = 'HelyesÃrás-ellenÅrzés'; $labels['resumeediting'] = 'HelyesÃrás-ellenÅrzés vége'; $labels['revertto'] = 'VisszaállÃtás erre'; $labels['attachments'] = 'Csatolmányok'; $labels['upload'] = 'Feltöltés'; +$labels['uploadprogress'] = '$percent ($current / $total)'; $labels['close'] = 'Bezárás'; $labels['messageoptions'] = 'ÃzenetbeállÃtások...'; $labels['low'] = 'Alacsony'; @@ -187,7 +191,8 @@ $labels['high'] = 'Magas'; $labels['highest'] = 'Legmagasabb'; $labels['nosubject'] = '(nincs tárgy)'; $labels['showimages'] = 'Képek megjelenÃtése'; -$labels['alwaysshow'] = 'Képek megjelenÃtése mindig ha a feladó $sender'; +$labels['alwaysshow'] = 'Képek megjelenÃtése mindig, ha a feladó $sender'; +$labels['isdraft'] = 'TRANSLATE!'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Egyszerű szöveg'; $labels['savesentmessagein'] = 'Elküldött üzenet mentése ide'; @@ -238,14 +243,16 @@ $labels['typehome'] = 'Otthon'; $labels['typework'] = 'Munkahely'; $labels['typeother'] = 'Egyéb'; $labels['typemobile'] = 'Mobil'; -$labels['typemain'] = 'FÅvonal'; +$labels['typemain'] = 'Vezetékes'; $labels['typehomefax'] = 'Otthoni fax'; $labels['typeworkfax'] = 'Munkahelyi fax'; $labels['typecar'] = 'Gépkocsi'; $labels['typepager'] = 'SzemélyhÃvó'; $labels['typevideo'] = 'Videó'; $labels['typeassistant'] = 'Asszisztens'; -$labels['typehomepage'] = 'Weboldal'; +$labels['typehomepage'] = 'Weboldal'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; $labels['addfield'] = 'Ãj mezÅ hozzáadása...'; $labels['addcontact'] = 'Ãj kapcsolat hozzáadása'; $labels['editcontact'] = 'Kapcsolat szerkesztése'; @@ -267,16 +274,17 @@ $labels['print'] = 'Nyomtatás'; $labels['export'] = 'Exportálás'; $labels['exportvcards'] = 'Kapcsolatok exportálása vCard formátumban'; $labels['newcontactgroup'] = 'Ãj csoport'; -$labels['groupactions'] = 'Műveletek csoportokkal...'; -$labels['grouprename'] = 'Csoport átnevezése'; -$labels['groupdelete'] = 'Csoport törlése'; -$labels['previouspage'] = 'ElÅzÅ lap'; -$labels['firstpage'] = 'ElsÅ lap'; -$labels['nextpage'] = 'KövetkezÅ lap'; -$labels['lastpage'] = 'Utolsó lap'; +$labels['grouprename'] = 'Csoport átnevezése'; +$labels['groupdelete'] = 'Csoport törlése'; +$labels['previouspage'] = 'ElÅzÅ oldal'; +$labels['firstpage'] = 'ElsÅ oldal'; +$labels['nextpage'] = 'KövetkezÅ oldal'; +$labels['lastpage'] = 'Utolsó oldal'; $labels['group'] = 'Csoport'; $labels['groups'] = 'Csoportok'; $labels['personaladrbook'] = 'Személyes cÃmjegyzék'; +$labels['searchsave'] = 'Keresés mentése'; +$labels['searchdelete'] = 'Keresés törlése'; $labels['import'] = 'Importálás'; $labels['importcontacts'] = 'Kapcsolatok importálása'; $labels['importfromfile'] = 'Importálás fájlból:'; @@ -296,6 +304,8 @@ $labels['edititem'] = 'Elem szerkesztése'; $labels['preferhtml'] = 'HTML megjelenÃtés'; $labels['defaultcharset'] = 'Alapértelmezett karakterkódolás'; $labels['htmlmessage'] = 'HTML üzenet'; +$labels['dateformat'] = 'Dátumformátum'; +$labels['timeformat'] = 'IdÅformátum'; $labels['prettydate'] = 'Rövid dátumok'; $labels['setdefault'] = 'BeállÃtás alapértelmezettnek'; $labels['autodetect'] = 'Automatikus'; @@ -321,7 +331,7 @@ $labels['autosendknown'] = 'visszaigazolás küldése csak a kapcsolataimnak, eg $labels['autosendknownignore'] = 'visszaigazolás küldése csak a kapcsolataimnak, egyéb esetben hagyja figyelmen kÃvül'; $labels['ignore'] = 'hagyja figyelmen kÃvül'; $labels['readwhendeleted'] = 'Ãzenet olvasottként jelölése törléskor'; -$labels['flagfordeletion'] = 'Ãzenet törlendÅnek jelölése törlés helyett '; +$labels['flagfordeletion'] = 'Ãzenet törlendÅnek jelölése törlés helyett'; $labels['skipdeleted'] = 'Törölt üzenetek ne legyenek megjelenÃtve'; $labels['deletealways'] = 'Ãzenet törlése, ha nem sikerül áthelyezni a törölt elemek mappába'; $labels['showremoteimages'] = 'Távoli beágyazott képek mutatása'; @@ -367,7 +377,13 @@ $labels['reqmdn'] = 'Olvasási visszaigazolás megkövetelése'; $labels['reqdsn'] = 'KézbesÃtési visszaigazolás megkövetelése'; $labels['replysamefolder'] = 'Válaszok azonos mappába helyezése'; $labels['defaultaddressbook'] = 'Ãj kapcsolatok hozzáadása a kiválasztott cÃmjegyzékhez'; +$labels['autocompletesingle'] = 'TRANSLATE!'; $labels['spellcheckbeforesend'] = 'HelyesÃrás-ellenÅrzés az üzenet elküldése elÅtt'; +$labels['spellcheckoptions'] = 'HelyesÃrás-ellenÅrzés opciók'; +$labels['spellcheckignoresyms'] = 'Speciális karaktereket tartalmazó szavak kihagyása'; +$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['folder'] = 'Mappa'; $labels['folders'] = 'Mappák'; $labels['foldername'] = 'Mappa neve'; @@ -386,11 +402,12 @@ $labels['getfoldersize'] = 'Mappa mérete'; $labels['changesubscription'] = 'Feliratkozás megváltoztatása'; $labels['foldertype'] = 'Mappa tÃpusa'; $labels['personalfolder'] = 'Privát mappa'; -$labels['otherfolder'] = 'Más felhasználó mappája'; +$labels['otherfolder'] = 'Más felhasználó(k) mappája'; $labels['sharedfolder'] = 'Megosztott mappa'; $labels['sortby'] = 'Rendezés'; $labels['sortasc'] = 'növekvÅ'; $labels['sortdesc'] = 'csökkenÅ'; +$labels['undo'] = 'Visszavonás'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/hu_HU/messages.inc b/program/localization/hu_HU/messages.inc index 1c070ce..321486e 100644 --- a/program/localization/hu_HU/messages.inc +++ b/program/localization/hu_HU/messages.inc @@ -13,9 +13,10 @@ | Author: Zark Bonfire <ikkhares at gmail dot com> | | Peter Szabo <pete at teamlupus dot hu> | | Barnabas Bona <bsi at hosember dot hu> | +| Gabor Veliczky <hosting at jugiter dot net> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -23,12 +24,12 @@ $messages = array(); $messages['loginfailed'] = 'Sikertelen belépés'; $messages['cookiesdisabled'] = 'A böngészÅ nem támogatja a sütik használatát'; $messages['sessionerror'] = 'Ãrvénytelen vagy lejárt munkamenet'; -$messages['imaperror'] = 'Nem sikerült a kapcsolódás az IMAP szerverhez'; +$messages['imaperror'] = 'Nem sikerült csatlakozni az IMAP szerverhez'; $messages['servererror'] = 'Szerverhiba!'; $messages['servererrormsg'] = 'Szerverhiba: $msg'; -$messages['databaserror'] = 'Adatbázishiba!'; -$messages['errorreadonly'] = 'A műveletet nem sikerült végrehajtani. A mappa Ãrásvédett'; -$messages['errornoperm'] = 'A műveletet nem sikerült végrehajtani. Hozzáférés megtagadva'; +$messages['dberror'] = 'Adatbázishiba!'; +$messages['errorreadonly'] = 'A műveletet nem sikerült végrehajtani. A mappa Ãrásvédett.'; +$messages['errornoperm'] = 'A műveletet nem sikerült végrehajtani. Hozzáférés megtagadva.'; $messages['invalidrequest'] = 'Ãrvénytelen kérés! Az adatok nem lettek elmentve.'; $messages['nomessagesfound'] = 'A fiók nem tartalmaz leveleket'; $messages['loggedout'] = 'Sikeres kijelentkezés. Viszontlátásra!'; @@ -44,11 +45,13 @@ $messages['savingmessage'] = 'Az üzenet mentése...'; $messages['messagesaved'] = 'Az üzenet elmentve a Piszkozatokhoz'; $messages['successfullysaved'] = 'A mentés sikerült'; $messages['addedsuccessfully'] = 'A kapcsolat hozzáadása a cÃmjegyzékhez megtörtént'; -$messages['contactexists'] = 'A kapcsolat már létezik ezzel az e-mail cÃmmel'; -$messages['blockedimages'] = 'Biztonsági okokból a távoli képek letöltése tiltott.'; -$messages['encryptedmessage'] = 'Az üzenet titkosÃtott, ezért nem megjelenÃthetÅ.'; +$messages['contactexists'] = 'Ezzel az e-mail cÃmmel már létezik kapcsolat'; +$messages['contactnameexists'] = 'Ezzel a névvel már létezik kapcsolat'; +$messages['blockedimages'] = 'Biztonsági okokból a távoli képek letöltése tiltott'; +$messages['encryptedmessage'] = 'Az üzenet titkosÃtott, ezért nem megjelenÃthetÅ'; $messages['nocontactsfound'] = 'Nem találhatóak kapcsolatok'; $messages['contactnotfound'] = 'A kiválasztott kapcsolat nem található'; +$messages['contactsearchonly'] = 'Adjon meg keresÅkifejezéseket a kapcsolatok közti kereséshez'; $messages['sendingfailed'] = 'Az üzenet elküldése nem sikerült'; $messages['senttooquickly'] = 'Kérem várjon még $sec másodpercet az üzenet elküldése elÅtt'; $messages['errorsavingsent'] = 'Hiba történt az elküldött üzenet mentése közben'; @@ -58,9 +61,12 @@ $messages['errorcopying'] = 'Az üzenet(ek)et nem sikerült másolni'; $messages['errordeleting'] = 'Az üzenet(ek)et nem sikerült törölni'; $messages['errormarking'] = 'Az üzenet(ek)et nem sikerült megjelölni'; $messages['deletecontactconfirm'] = 'Biztos, hogy törölni szeretné a kijelölt kapcsolato(ka)t?'; +$messages['deletegroupconfirm'] = 'Biztos, hogy törölni szeretné a kijelölt csoportot?'; $messages['deletemessagesconfirm'] = 'Biztos, hogy törölni szeretné a kijelölt üzenete(ke)t?'; $messages['deletefolderconfirm'] = 'Biztos, hogy törölni szeretné ezt a mappát?'; $messages['purgefolderconfirm'] = 'Biztos benne, hogy az összes üzenet törölhetÅ?'; +$messages['contactdeleting'] = 'Kapcsolat(ok) törlése...'; +$messages['groupdeleting'] = 'Csoport törlése...'; $messages['folderdeleting'] = 'Mappa törlése...'; $messages['foldermoving'] = 'Mappa mozgatása...'; $messages['foldersubscribing'] = 'Feliratkozás a mappára...'; @@ -75,17 +81,17 @@ $messages['nosubjectwarning'] = 'A Tárgy mezŠüres. Szeretné most kitölteni $messages['nobodywarning'] = 'Elküldi az üzenetet üresen?'; $messages['notsentwarning'] = 'Az üzenet még nem lett elküldve. Eldobja az üzenetet?'; $messages['noldapserver'] = 'Adjon meg egy LDAP szervert a kereséshez'; -$messages['nocontactsreturned'] = 'Nem található kapcsolat'; $messages['nosearchname'] = 'Adja meg a kapcsolat nevét vagy e-mail cÃmét'; $messages['notuploadedwarning'] = 'Még nem került feltöltésre minden csatolmány. Kérem várjon vagy állÃtsa le a feltöltést!'; $messages['searchsuccessful'] = '$nr üzenet található'; +$messages['contactsearchsuccessful'] = '$nr találat'; $messages['searchnomatch'] = 'Nincs találat'; $messages['searching'] = 'Keresés...'; $messages['checking'] = 'EllenÅrzés...'; $messages['nospellerrors'] = 'Nem található helyesÃrási hiba'; $messages['folderdeleted'] = 'A mappa sikeresen törölve'; -$messages['foldersubscribed'] = 'A feliratkozás a mappára sikeres'; -$messages['folderunsubscribed'] = 'A leiratkozás a mappáról sikeres'; +$messages['foldersubscribed'] = 'Sikerült a mappára feliratkozni'; +$messages['folderunsubscribed'] = 'Sikerült a mappáról leiratkozni'; $messages['folderpurged'] = 'Mappa sikeresen törölve'; $messages['folderexpunged'] = 'Mappa sikeresen kiürÃtve'; $messages['deletedsuccessfully'] = 'Törölve'; @@ -99,11 +105,14 @@ $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['deletingmessage'] = 'Ãzenet(ek) törlése....'; $messages['markingmessage'] = 'Ãzenet(ek) megjelölése...'; +$messages['addingmember'] = 'Kapcsolat(ok) hozzáadása a csoporthoz...'; +$messages['removingmember'] = 'Kapcsolat(ok) törlése a csoportból...'; $messages['receiptsent'] = 'Az olvasási visszaigazolás el lett küldve'; $messages['errorsendingreceipt'] = 'Az olvasási visszaigazolást nem sikerült elküldeni'; -$messages['nodeletelastidentity'] = 'Nem törölheti ezt az azonosÃtót, ez az egyetlen'; +$messages['nodeletelastidentity'] = 'Az azonosÃtó nem törölhetÅ, lennie kell legalább egy azonosÃtónak!'; $messages['forbiddencharacter'] = 'A mappa neve tiltott karaktert tartalmaz'; $messages['selectimportfile'] = 'Kérjük válassza ki a feltölteni kÃvánt fájlt'; $messages['addresswriterror'] = 'A kiválasztott cÃmjegyzék nem Ãrható'; @@ -114,7 +123,7 @@ $messages['importerror'] = 'Az importálás sikertelen! A feltöltött állomán $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['opnotpermitted'] = 'A művelet nem megengedett!'; -$messages['nofromaddress'] = 'Hiányzó e-mail cÃm a kiválasztott feladónál'; +$messages['nofromaddress'] = 'A kiválasztott feladónál hiányzik az e-mail cÃm!'; $messages['editorwarning'] = 'Az egyszerű szöveges formátumra való váltás az összes formázás elvesztésével jár. Biztosan folytatja?'; $messages['httpreceivedencrypterror'] = 'Végzetes konfigurációs hiba történt, azonnal lépjen kapcsolatba az üzemeltetÅvel. <b>Az üzenet nem küldhetÅ el.</b>'; $messages['smtpconnerror'] = 'SMTP hiba ($code): Sikertelen kapcsolódás a szerverhez'; @@ -122,27 +131,34 @@ $messages['smtpautherror'] = 'SMTP hiba ($code): Sikertelen bejelentkezés'; $messages['smtpfromerror'] = 'SMTP hiba ($code): Nem sikerült a feladó beállÃtása: "$from" ($msg)'; $messages['smtptoerror'] = 'SMTP hiba ($code): Nem sikerült a következÅ cÃmzett hozzáadása: "$to" ($msg)'; $messages['smtprecipientserror'] = 'SMTP hiba ($code): A cÃmzettlista feldolgozása sikertelen'; -$messages['smtpdsnerror'] = 'SMTP hiba: A kézbesÃtési visszaigazolásokat a szerver nem támogatja'; $messages['smtperror'] = 'SMTP hiba ($code): $msg'; $messages['emailformaterror'] = 'Helytelen formátumú e-mail cÃm: $email'; -$messages['toomanyrecipients'] = 'Túl sok a cÃmzett. Csökkentse a cÃmzettek számát $max cÃmre.'; -$messages['maxgroupmembersreached'] = 'A csoport létszáma meghaladja a maximum $max értéket'; +$messages['toomanyrecipients'] = 'Túl sok a cÃmzett. Csökkentse a cÃmzettek számát maximum $max cÃmre!'; +$messages['maxgroupmembersreached'] = 'A csoport létszáma meghaladja a maximum $max fÅt'; $messages['internalerror'] = 'BelsÅ hiba történt, kérjük próbálja újra!'; $messages['contactdelerror'] = 'Hiba a kapcsolat(ok) törlésekor'; $messages['contactdeleted'] = 'Kapcsolat(ok) sikeresen törölve'; +$messages['contactrestoreerror'] = 'Nem sikerült a törölt kapcsolat(ok) helyreállÃtása'; +$messages['contactrestored'] = 'Kapcsolat(ok) sikeresen helyreállÃtva'; $messages['groupdeleted'] = 'Csoport sikeresen törölve'; $messages['grouprenamed'] = 'Csoport sikeresen átnevezve'; $messages['groupcreated'] = 'Csoport sikeresen létrehozva'; +$messages['savedsearchdeleted'] = 'Mentett keresés sikeresen törölve'; +$messages['savedsearchdeleteerror'] = 'Nem sikerült törölni a mentett keresést'; +$messages['savedsearchcreated'] = 'Keresés sikeresen mentve'; +$messages['savedsearchcreateerror'] = 'Nem sikerült létrehozni mentett keresést'; $messages['messagedeleted'] = 'Ãzenet(ek) sikeresen törölve'; $messages['messagemoved'] = 'Ãzenet(ek) sikeresen átmozgatva'; $messages['messagecopied'] = 'Ãzenet(ek) sikeresen másolva'; $messages['messagemarked'] = 'Ãzenet(ek) sikeresen megjelölve'; $messages['autocompletechars'] = 'Az automatikus kiegészÃtéshez legalább $min karakter szükséges'; +$messages['autocompletemore'] = 'Több egyezés található. Kérem adjon meg további karaktereket!'; $messages['namecannotbeempty'] = 'A név nem lehet üres'; $messages['nametoolong'] = 'A név túl hosszú'; $messages['folderupdated'] = 'Mappa sikeresen frissÃtve'; $messages['foldercreated'] = 'Mappa sikeresen létrehozva'; $messages['invalidimageformat'] = 'Ãrvénytelen képformátum'; $messages['mispellingsfound'] = 'Az üzenetben helyesÃrási hibák találhatók'; +$messages['parentnotwritable'] = 'Nem sikerült a mappa létrehozása/mozgatása a kijelölt mappába. Nincs jogosultsága a művelethez!'; ?> diff --git a/program/localization/id_ID/messages.inc b/program/localization/id_ID/messages.inc index c16a1ca..bf1f252 100644 --- a/program/localization/id_ID/messages.inc +++ b/program/localization/id_ID/messages.inc @@ -13,7 +13,7 @@ | Author: Putu Arya Sabda Wijaya <ptaryasw@isi-dps.ac.id> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 4748 2011-05-11 13:17:43Z yllar $ +@version $Id: messages.inc 5139 2011-08-28 09:47:15Z alec $ */ @@ -24,7 +24,7 @@ $messages['sessionerror'] = 'Session Anda invalid atau kadaluwarsa'; $messages['imaperror'] = 'Koneksi ke IMAP server gagal'; $messages['servererror'] = 'Server Error!'; $messages['servererrormsg'] = 'Server Error: $msg'; -$messages['databaserror'] = 'Basis data Error!'; +$messages['dberror'] = 'Basis data Error!'; $messages['errorreadonly'] = 'Tidak bisa melakukan operasi. Folder hanya bisa dibaca'; $messages['errornoperm'] = 'Tidak bisa melakukan operasi. Ijin ditolak'; $messages['invalidrequest'] = 'Permintaan tidak valid! Tidak ada data yang tersimpan.'; diff --git a/program/localization/it_IT/labels.inc b/program/localization/it_IT/labels.inc index 74da7e5..52950a3 100644 --- a/program/localization/it_IT/labels.inc +++ b/program/localization/it_IT/labels.inc @@ -14,7 +14,7 @@ | Yusef Maali <contact@yusefmaali.net> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -118,7 +118,7 @@ $labels['markread'] = 'Letti'; $labels['markunread'] = 'Non letti'; $labels['markflagged'] = 'Contrassegnato'; $labels['markunflagged'] = 'Non contrassegnato'; -$labels['messageactions'] = 'Altre azioni...'; +$labels['moreactions'] = 'Altre operazioni...'; $labels['select'] = 'Seleziona'; $labels['all'] = 'Tutti'; $labels['none'] = 'Nessuno'; @@ -150,7 +150,7 @@ $labels['listcolumns'] = 'Elenco Colonne'; $labels['listsorting'] = 'Ordina per'; $labels['listorder'] = 'Ordinamento'; $labels['listmode'] = 'Modalità di visualizzazione'; -$labels['folderactions'] = 'Azione cartella'; +$labels['folderactions'] = 'Operazioni cartella'; $labels['compact'] = 'Compatta'; $labels['empty'] = 'Svuota'; $labels['quota'] = 'Spazio utilizzato'; @@ -172,6 +172,7 @@ $labels['editortype'] = 'Tipo editor'; $labels['returnreceipt'] = 'Ricevuta di ritorno'; $labels['dsn'] = 'Notifica di consegna'; $labels['mailreplyintro'] = 'Il $date $sender ha scritto:'; +$labels['originalmessage'] = 'Messaggio originale'; $labels['editidents'] = 'Modifica indentità '; $labels['checkspelling'] = 'Controlla ortografia'; $labels['resumeediting'] = 'Torna al messaggio'; @@ -189,6 +190,7 @@ $labels['highest'] = 'Molto alta'; $labels['nosubject'] = '(nessun oggetto)'; $labels['showimages'] = 'Visualizza immagini'; $labels['alwaysshow'] = 'Mostra sempre immagini da $sender'; +$labels['isdraft'] = 'Questa è una bozza.'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Testo semplice'; $labels['savesentmessagein'] = 'Salva i messaggi inviati in'; @@ -247,6 +249,8 @@ $labels['typepager'] = 'Teledrin'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Assistente'; $labels['typehomepage'] = 'Home page'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profilo'; $labels['addfield'] = 'Aggiungi campo...'; $labels['addcontact'] = 'Aggiungi contatto alla rubrica'; $labels['editcontact'] = 'Modifica contatto'; @@ -268,7 +272,6 @@ $labels['print'] = 'Stampa'; $labels['export'] = 'Esporta'; $labels['exportvcards'] = 'Esporta i contatti in formato vCard'; $labels['newcontactgroup'] = 'Crea un nuovo gruppo'; -$labels['groupactions'] = 'Azioni per i gruppi'; $labels['grouprename'] = 'Rinomina il gruppo'; $labels['groupdelete'] = 'Cancella il gruppo'; $labels['previouspage'] = 'Pagina precedente'; @@ -278,6 +281,8 @@ $labels['lastpage'] = 'Ultima pagina'; $labels['group'] = 'Gruppo'; $labels['groups'] = 'Gruppi'; $labels['personaladrbook'] = 'Rubrica Personale'; +$labels['searchsave'] = 'Salva ricerca'; +$labels['searchdelete'] = 'Elimina ricerca'; $labels['import'] = 'Importa'; $labels['importcontacts'] = 'Importa contatti'; $labels['importfromfile'] = 'Importa da file:'; @@ -286,6 +291,7 @@ $labels['importreplace'] = 'Sostituisci l\'intera rubrica'; $labels['importtext'] = 'Puoi caricare i contatti da una rubrica esistente. Al momento è supportata l\'importazione dei contatti dal formato vCard.'; $labels['done'] = 'Fatto'; $labels['settingsfor'] = 'Impostazioni per '; +$labels['about'] = 'Informazioni'; $labels['preferences'] = 'Preferenze'; $labels['userpreferences'] = 'Preferenze utente'; $labels['editpreferences'] = 'Modifica le preferenze per l\'utente'; @@ -297,6 +303,8 @@ $labels['edititem'] = 'Modifica elemento'; $labels['preferhtml'] = 'Mostra HTML'; $labels['defaultcharset'] = 'Set di caratteri predefinito'; $labels['htmlmessage'] = 'Messaggio HTML'; +$labels['dateformat'] = 'Formato data'; +$labels['timeformat'] = 'Formato orario'; $labels['prettydate'] = 'Date più leggibili'; $labels['setdefault'] = 'Imposta predefinita'; $labels['autodetect'] = 'Auto'; @@ -368,7 +376,13 @@ $labels['reqmdn'] = 'Richiedi sempre la ricevuta di ritorno'; $labels['reqdsn'] = 'Richiedi sempre la notifica di consegna'; $labels['replysamefolder'] = 'Salva risposta nella cartella del messaggio a cui si risponde'; $labels['defaultaddressbook'] = 'Aggiungi nuovi contatti alla rubrica selezionata'; +$labels['autocompletesingle'] = 'Non considerare gli indirizzi secondari nell\'autocompletamento'; $labels['spellcheckbeforesend'] = 'Esegui il controllo ortografico prima di inviare un messaggio'; +$labels['spellcheckoptions'] = 'Opzioni controllo ortografico'; +$labels['spellcheckignoresyms'] = 'Ignora le parole contenenti simboli'; +$labels['spellcheckignorenums'] = 'Ignora le parole contenenti numeri'; +$labels['spellcheckignorecaps'] = 'Ignora le parole con tutte le lettere maiuscole'; +$labels['addtodict'] = 'Aggiungi al dizionario'; $labels['folder'] = 'Cartella'; $labels['folders'] = 'Cartelle'; $labels['foldername'] = 'Nome cartella'; @@ -393,6 +407,11 @@ $labels['sortby'] = 'Ordina per'; $labels['sortasc'] = 'Ordinamento crescente'; $labels['sortdesc'] = 'Ordinamento decrescente'; $labels['undo'] = 'Annulla'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Versione'; +$labels['source'] = 'Sorgente'; +$labels['license'] = 'Licenza'; +$labels['support'] = 'Ottieni supporto'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/it_IT/messages.inc b/program/localization/it_IT/messages.inc index 8e2c118..bafcbb0 100644 --- a/program/localization/it_IT/messages.inc +++ b/program/localization/it_IT/messages.inc @@ -14,7 +14,7 @@ | Yusef Maali <contact@yusefmaali.net> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -25,7 +25,7 @@ $messages['sessionerror'] = 'Sessione non valida o scaduta'; $messages['imaperror'] = 'Impossibile connettersi al server IMAP'; $messages['servererror'] = 'Errore del server!'; $messages['servererrormsg'] = 'Errore del server: $msg'; -$messages['databaserror'] = 'Errore del database!'; +$messages['dberror'] = 'Errore del database!'; $messages['errorreadonly'] = 'Impossibile eseguire l\'operazione. Cartella in sola lettura'; $messages['errornoperm'] = 'Impossibile eseguire l\'operazione. Permesso negato'; $messages['invalidrequest'] = 'Richiesta non valida! Nessun dato salvato.'; @@ -49,6 +49,7 @@ $messages['blockedimages'] = 'Per proteggere la tua privacy, le immagini remote $messages['encryptedmessage'] = 'Questo messaggio é cifrato e non può essere visualizzato. Spiacenti!'; $messages['nocontactsfound'] = 'Nessun contatto trovato'; $messages['contactnotfound'] = 'Il contatto richiesto non è stato trovato'; +$messages['contactsearchonly'] = 'Inserisci dei termini per cercare i contatti'; $messages['sendingfailed'] = 'Impossibile inviare il messaggio'; $messages['senttooquickly'] = 'Per favore, attendi $sec secondi prima di inviare questo messaggio'; $messages['errorsavingsent'] = 'C\'è stato un errore nel salvare il messaggio inviato'; @@ -62,6 +63,7 @@ $messages['deletegroupconfirm'] = 'Sei sicuro di voler eliminare i gruppi selezi $messages['deletemessagesconfirm'] = 'Sei sicuro di voler eliminare i messaggi selezionati?'; $messages['deletefolderconfirm'] = 'Sei sicuro di voler eliminare la cartella selezionata?'; $messages['purgefolderconfirm'] = 'Sei sicuro di voler eliminare tutti i messaggi in questa cartella?'; +$messages['contactdeleting'] = 'Eliminazione contatti...'; $messages['groupdeleting'] = 'Eliminazione gruppo...'; $messages['folderdeleting'] = 'Eliminazione cartella...'; $messages['foldermoving'] = 'Spostamento cartella...'; @@ -77,10 +79,10 @@ $messages['nosubjectwarning'] = 'L\'oggetto è vuoto. Vuoi inserirlo adesso?'; $messages['nobodywarning'] = 'Inviare il messaggio senza testo?'; $messages['notsentwarning'] = 'Il messaggio non è stato inviato. Vuoi annullare questo messaggio?'; $messages['noldapserver'] = 'Per favore, scegli un server LDAP in cui ricercare'; -$messages['nocontactsreturned'] = 'Nessun contatto trovato'; $messages['nosearchname'] = 'Per favore, immetti un nome o un indirizzo e-mail'; $messages['notuploadedwarning'] = 'Non tutti gli allegati sono stati ancora caricati. Prego attendere, oppure cancellare il caricamento.'; $messages['searchsuccessful'] = '$nr messaggi trovati'; +$messages['contactsearchsuccessful'] = '$nr contatti trovati'; $messages['searchnomatch'] = 'La ricerca non ha dato nessun risultato'; $messages['searching'] = 'Ricerca...'; $messages['checking'] = 'Controllo...'; @@ -127,7 +129,6 @@ $messages['smtpautherror'] = 'Errore SMTP ($code): Autenticazione fallita'; $messages['smtpfromerror'] = 'Errore SMTP ($code): Fallita l\'impostazione del mittente "$from" ($msg)'; $messages['smtptoerror'] = 'Errore SMTP ($code): Fallito l\'inserimento del destinatario "$to" ($msg)'; $messages['smtprecipientserror'] = 'Errore SMTP: Impossibile processare la lista dei destinatari'; -$messages['smtpdsnerror'] = 'Errore SMTP: Ricevuta di consegna non supportata'; $messages['smtperror'] = 'Errore SMTP: $msg'; $messages['emailformaterror'] = 'Indirizzo e-mail non corretto: $email'; $messages['toomanyrecipients'] = 'Numero eccessivo di destinatari, ridurlo a $max'; @@ -140,11 +141,16 @@ $messages['contactrestored'] = 'Contatto/i ripristinato/i'; $messages['groupdeleted'] = 'Gruppo correttamente eliminato'; $messages['grouprenamed'] = 'Gruppo correttamente rinominato'; $messages['groupcreated'] = 'Gruppo creato correttamente'; +$messages['savedsearchdeleted'] = 'Le ricerca salvata è stata eliminata con successo.'; +$messages['savedsearchdeleteerror'] = 'Impossibile eliminare la ricerca salvata.'; +$messages['savedsearchcreated'] = 'Ricerca salvata creata con successo.'; +$messages['savedsearchcreateerror'] = 'Impossibile creare la ricerca salvata.'; $messages['messagedeleted'] = 'Messaggi/o cancellato correttamente'; $messages['messagemoved'] = 'Messaggi/o spostato correttamente'; $messages['messagecopied'] = 'Messaggi/o copiato correttamente'; $messages['messagemarked'] = 'Messaggi/o marcato correttamente'; $messages['autocompletechars'] = 'Inserisci almeno $min caratteri per l\'autocompletamento'; +$messages['autocompletemore'] = 'Più risultati ottenuti. Inserisci per favore più caratteri.'; $messages['namecannotbeempty'] = 'Il nome non può essere vuoto'; $messages['nametoolong'] = 'Nome troppo lungo'; $messages['folderupdated'] = 'Cartella aggiornata correttamente'; @@ -152,5 +158,6 @@ $messages['foldercreated'] = 'Cartella creata correttamente'; $messages['invalidimageformat'] = 'Formato immagine non valido'; $messages['mispellingsfound'] = 'Sono stati riscontrati errori ortografici nel messaggio'; $messages['parentnotwritable'] = 'Impossibile creare o muovere la cartella: accesso negato'; +$messages['messagetoobig'] = 'La parte del messaggio è troppo grande per essere processata.'; ?> diff --git a/program/localization/ja_JP/labels.inc b/program/localization/ja_JP/labels.inc index 5a3f3ec..f9e8548 100644 --- a/program/localization/ja_JP/labels.inc +++ b/program/localization/ja_JP/labels.inc @@ -14,9 +14,9 @@ | Takashi Takamatsu <taka717@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ -EN-Revision: 5210 +EN-Revision: 5490 */ @@ -154,7 +154,6 @@ $labels['unanswered'] = 'æªè¿ä¿¡'; $labels['deleted'] = 'å餿¸ã¿'; $labels['invert'] = 'å転'; $labels['filter'] = 'ãã£ã«ã¿ã¼'; - $labels['list'] = 'ä¸è¦§'; $labels['threads'] = 'ã¹ã¬ãã'; $labels['expand-all'] = 'ãã¹ã¦å±é'; @@ -227,6 +226,7 @@ $labels['highest'] = 'æé«'; $labels['nosubject'] = '(ä»¶åãªã)'; $labels['showimages'] = 'ç»åã®è¡¨ç¤º'; $labels['alwaysshow'] = '$sender ããå±ããç»åã¯å¸¸ã«è¡¨ç¤º'; +$labels['isdraft'] = 'ããã¯ä¸æ¸ãã®ã¡ãã»ã¼ã¸ã§ãã'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'ããã¹ã'; @@ -344,7 +344,7 @@ $labels['done'] = 'å®äº'; // settings $labels['settingsfor'] = '次ã®è¨å®:'; - +$labels['about'] = 'Roundcube Webmail ã«ã¤ãã¦'; $labels['preferences'] = 'è¨å®'; $labels['userpreferences'] = 'ã¦ã¼ã¶ã¼è¨å®'; $labels['editpreferences'] = 'ã¦ã¼ã¶ã¼è¨å®ã®å¤æ´'; @@ -432,6 +432,7 @@ $labels['reqmdn'] = '常ã«éå°ç¢ºèªéç¥ãè¦æ±ãã'; $labels['reqdsn'] = '常ã«é éç¶æ³ã®éç¥ãè¦æ±ãã'; $labels['replysamefolder'] = 'è¿ä¿¡ãããã¡ã¼ã«ãè¿ä¿¡å ã¡ã¼ã«ã¨åããã©ã«ãã«ä¿å'; $labels['defaultaddressbook'] = '次ã®ã¢ãã¬ã¹å¸³ã«æ°è¦é£çµ¡å ã追å ãã'; +$labels['autocompletesingle'] = 'èªåè£å®ã§ä»£æ¿ã¡ã¼ã«ã¢ãã¬ã¹ãé£ã°ã'; $labels['spellcheckbeforesend'] = 'ã¡ã¼ã«ã®éä¿¡åã«ã¹ãã« ãã§ãã¯'; $labels['spellcheckoptions'] = 'ã¹ãã«ãã§ãã¯ã®ãªãã·ã§ã³'; $labels['spellcheckignoresyms'] = 'è¨å·ã®åèªãç¡è¦ãã'; @@ -465,6 +466,12 @@ $labels['sortasc'] = 'æé ã§ä¸¦ã³æ¿ã'; $labels['sortdesc'] = 'éé ã§ä¸¦ã³æ¿ã'; $labels['undo'] = 'åãæ¶ã'; +$labels['plugin'] = 'ãã©ã°ã¤ã³'; +$labels['version'] = 'ãã¼ã¸ã§ã³'; +$labels['source'] = 'ã½ã¼ã¹'; +$labels['license'] = 'ã©ã¤ã»ã³ã¹'; +$labels['support'] = 'ãã«ããåãã'; + // units $labels['B'] = 'ãã¤ã'; $labels['KB'] = 'KB'; diff --git a/program/localization/ja_JP/messages.inc b/program/localization/ja_JP/messages.inc index fefd7a5..e728b03 100644 --- a/program/localization/ja_JP/messages.inc +++ b/program/localization/ja_JP/messages.inc @@ -14,9 +14,9 @@ | Takashi Takamatsu <taka717@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ -// EN-Revision: 5276 +// EN-Revision: 5490 */ @@ -136,7 +136,6 @@ $messages['smtpautherror'] = 'SMTP Error ($code): èªè¨¼ã«å¤±æãã¾ããã $messages['smtpfromerror'] = 'SMTP Error ($code): å·®åºäºº "$from" ãè¨å®ã§ãã¾ãã ($msg)'; $messages['smtptoerror'] = 'SMTP Error ($code): å®å "$to" ã追å ã§ãã¾ãã ($msg)'; $messages['smtprecipientserror'] = 'SMTP Error: å®å ã®ä¸è¦§ãè§£æã§ãã¾ããã'; -$messages['smtpdsnerror'] = 'SMTP ã¨ã©ã¼: é éç¶æ³éç¥ããµãã¼ããã¦ãã¾ããã'; $messages['smtperror'] = 'SMTP ã¨ã©ã¼: $msg'; $messages['emailformaterror'] = 'ã¡ã¼ã«ã¢ãã¬ã¹ãæ£ããããã¾ãã: $email'; $messages['toomanyrecipients'] = 'å®å ãå¤ããã¾ãã$max 件以å ã«ãã¦ãã ããã'; @@ -166,5 +165,6 @@ $messages['foldercreated'] = 'ãã©ã«ãã¼ã使ãã¾ããã'; $messages['invalidimageformat'] = 'ç»åã®å½¢å¼ãæ£ããããã¾ããã'; $messages['mispellingsfound'] = 'ã¡ãã»ã¼ã¸ã«ã¹ãã« ã¨ã©ã¼ãè¦ã¤ãã¾ããã'; $messages['parentnotwritable'] = '鏿ãã親ãã©ã«ãã¼ã¸ã®ä½æãç§»åã«å¤±æãã¾ãããã¢ã¯ã»ã¹æ¨©éãããã¾ããã'; +$messages['messagetoobig'] = 'ãã®å¦çãããã«ã¯ã¡ãã»ã¼ã¸é¨åã大ãããã¾ãã'; ?> diff --git a/program/localization/ka_GE/labels.inc b/program/localization/ka_GE/labels.inc index 2a9701c..fd38114 100755 --- a/program/localization/ka_GE/labels.inc +++ b/program/localization/ka_GE/labels.inc @@ -9,7 +9,7 @@ | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ -| Author: Zaza Zviadadze | +| Author: Zaza Zviadadze, George Machitidze | +-----------------------------------------------------------------------+ @version $Id: labels.inc 842 2009-10-03 19:00:00 zaza$ @@ -23,38 +23,35 @@ $labels['password'] = 'ááá ááá'; $labels['server'] = 'á¡áá ááá á'; $labels['login'] = 'á¨áá¡ááá'; $labels['logout'] = 'ááááá¡ááá'; -$labels['mail'] = 'ááâá¤áá¡á¢á'; +$labels['mail'] = 'ááá¤áá¡á¢á'; $labels['settings'] = 'ááá áááá¢á ááá'; $labels['addressbook'] = 'ááá¡áááá áááá'; $labels['inbox'] = 'ááá¦ááá£áá'; $labels['drafts'] = 'áá áááááá'; -$labels['sent'] = 'áááááááááááá'; -$labels['trash'] = 'á¬áá¨áááááá'; +$labels['sent'] = 'áááááááááá'; +$labels['trash'] = 'á¬áá¨áááá'; $labels['junk'] = 'á¡áááá'; $labels['subject'] = 'á¡áááá£á á'; $labels['from'] = 'ááááááááá'; -$labels['to'] = 'áááá¦ááá'; -$labels['cc'] = 'ááááá'; +$labels['to'] = 'ááá¡'; +$labels['cc'] = 'áá¡áá'; $labels['bcc'] = 'á¤áá á£áá'; -$labels['replyto'] = 'áááá á£áááá'; +$labels['replyto'] = 'ááá¡á£á®á'; $labels['date'] = 'ááá áá¦á'; $labels['size'] = 'áááá'; $labels['priority'] = 'áá ááá áá¢áá¢á'; $labels['organization'] = 'áá áááááááªáá'; -$labels['reply-to'] = 'áááá á£áááá'; $labels['mailboxlist'] = 'á¡áá¥áá¦ááááááá'; -$labels['messagesfromto'] = 'á¨áá¢á§ááááááá $from $to ááá $count'; $labels['messagenrof'] = 'á¨áá¢á§ááááááá $nr ááá $count'; +$labels['copy'] = 'áá¡áá'; +$labels['move'] = 'ááááá¢ááá'; $labels['moveto'] = 'ááááá¢ááá...'; $labels['download'] = 'áááááá¬áá á'; $labels['filename'] = 'á¤ááááá¡ á¡áá®ááá'; $labels['filesize'] = 'á¤ááááá¡ áááá'; -$labels['preferhtml'] = 'á áááá ᪠HTML'; -$labels['htmlmessage'] = 'HTML á¨áá¢á§ááááááá'; -$labels['prettydate'] = 'ááá áá ááá áá¦ááá'; $labels['addtoaddressbook'] = 'ááá¡áááá áááá¨á ááááá¢ááá'; -$labels['sun'] = 'áá'; -$labels['mon'] = 'áá '; +$labels['sun'] = 'ááá'; +$labels['mon'] = 'áá á¨'; $labels['tue'] = 'á¡áá'; $labels['wed'] = 'ááá®'; $labels['thu'] = 'á®á£á'; @@ -101,13 +98,9 @@ $labels['deletemessage'] = 'á¬áá¨áá'; $labels['movemessagetotrash'] = 'á¨áá¢á§áááááááá¡ á¬áá¨áááááá¨á ááááá¢ááá'; $labels['printmessage'] = 'á¨áá¢á§áááááááá¡ ááááááááá'; $labels['previousmessage'] = 'á¬ááá á¨áá¢á§áááááááá¡ ááá®áá'; -$labels['previousmessages'] = 'á¬ááá á¨áá¢á§áááááááááá¡ ááá®áá'; $labels['firstmessage'] = 'ááá áááá á¨áá¢á§áááááááá¡ ááá®áá'; -$labels['firstmessages'] = 'áá áááá á¨áá¢á§ááááááááá'; $labels['nextmessage'] = 'á¨áááááá á¨áá¢á§áááááááá¡ ááá®áá'; -$labels['nextmessages'] = 'á¨áááááá á¨áá¢á§áááááááááá¡ ááá®áá'; $labels['lastmessage'] = 'áááá á¨áá¢á§áááááááá¡ ááá®áá'; -$labels['lastmessages'] = 'áááá á¨áá¢á§áááááááááá¡ ááá®áá'; $labels['backtolist'] = 'á£ááá á©áááááááááá¨á'; $labels['viewsource'] = 'á¨áááááá¡á'; $labels['markmessages'] = 'ááááá¨ááá á¨áá¢á§ááááááááá'; @@ -115,19 +108,30 @@ $labels['markread'] = 'á áááá ᪠á¬ááááá®á£áá'; $labels['markunread'] = 'á áááá ᪠á¬áá£áááá®ááá'; $labels['markflagged'] = 'á áááá ᪠ááááá¨áá£áá'; $labels['markunflagged'] = 'á áááá ᪠ááá£ááá¨áááá'; -$labels['messageactions'] = 'ááá¢á á¤á£áá¥áªáááá'; +$labels['moreactions'] = 'ááá¢á ááá¥áááááá...'; $labels['select'] = 'ááááá¨ááá'; $labels['all'] = 'á§áááá'; $labels['none'] = 'áá áªáá áá'; +$labels['currpage'] = 'áááááááá á áááá áá'; $labels['unread'] = 'á¬áá£áááá®ááá'; $labels['flagged'] = 'ááááá¨áá£áá'; $labels['unanswered'] = 'á£ááá¡á£á®á'; $labels['deleted'] = 'á¬áá¨áááá'; $labels['invert'] = 'á¨ááá á£áááá£áá'; $labels['filter'] = 'á¤ááá¢á á'; +$labels['list'] = 'á¡áá'; +$labels['expand-all'] = 'á§ááááá¡ ááá¨áá'; +$labels['expand-unread'] = 'á¬áá£áááá®áááá¡ ááá¨áá'; +$labels['collapse-all'] = 'á§ááááá¡ áááááªáá'; +$labels['fromto'] = 'ááá¡ááá/ááá¡'; +$labels['flag'] = 'áá áá¨á'; +$labels['attachment'] = 'áááááá ááá£áá á¤áááá'; +$labels['sentdate'] = 'ááááááááá¡ ááá áá¦á'; +$labels['asc'] = 'áá ááááááá'; +$labels['desc'] = 'áááááááááá'; +$labels['listorder'] = 'áááááááá'; $labels['compact'] = 'á¨ááá£áá¨áá'; $labels['empty'] = 'áááªáá áááááá'; -$labels['purge'] = 'ááá¡á£á¤áááááá'; $labels['quota'] = 'á¨ááá¦á£ááá'; $labels['unknown'] = 'á£áªáááá'; $labels['unlimited'] = 'á¨áá£áá¦á£áááá'; @@ -174,13 +178,49 @@ $labels['receiptnote'] = 'áááááá á¢ááá: áá¡ ááá¨áá $labels['name'] = 'á¡á á£áá á¡áá®ááá'; $labels['firstname'] = 'á¡áá®ááá'; $labels['surname'] = 'áááá á'; +$labels['department'] = 'ááááá á¢ááááá¢á'; +$labels['gender'] = 'á¡á¥áá¡á'; $labels['email'] = 'ááâá¤áá¡á¢á'; +$labels['phone'] = 'á¢áááá¤ááá'; +$labels['address'] = 'ááá¡áááá áá'; +$labels['street'] = 'á¥á£á©á'; +$labels['locality'] = 'á¥áááá¥á'; +$labels['zipcode'] = 'ZIP áááá'; +$labels['region'] = 'á¨á¢áá¢á/áá áááááªáá'; +$labels['country'] = 'á¥ááá§ááá'; +$labels['birthday'] = 'ááááááááá¡ áá¦á'; +$labels['website'] = 'ááááááá áá'; +$labels['male'] = 'áááá ááááá'; +$labels['female'] = 'ááááá áááá'; +$labels['manager'] = 'ááááá¯áá á'; +$labels['allfields'] = 'á§áááá áááá'; +$labels['search'] = 'á«áááá'; +$labels['advsearch'] = 'ááá¤áá ááááá£áá á«áááá'; +$labels['other'] = 'á¡á®áá'; +$labels['typehome'] = 'á¡áá®áá'; +$labels['typework'] = 'á¡ááá¡áá®á£á á'; +$labels['typeother'] = 'á¡á®áá'; +$labels['typemobile'] = 'áááááá£á á'; +$labels['typemain'] = 'á«áá ááááá'; +$labels['typehomefax'] = 'á¡áá®ááá¡ á¤áá¥á¡á'; +$labels['typeworkfax'] = 'á¡ááá¡áá®á£á áá¡ á¤áá¥á¡á'; +$labels['typecar'] = 'áááá¥ááá'; +$labels['typepager'] = 'áááá¯áá á'; +$labels['typevideo'] = 'ááááá'; +$labels['typeblog'] = 'ááááá'; +$labels['typeprofile'] = 'áá áá¤ááá'; +$labels['addfield'] = 'ááááá¡ ááááá¢ááá...'; $labels['addcontact'] = 'áááá¢áá¥á¢ááá¨á ááááá¢ááá'; $labels['editcontact'] = 'áááá¢áá¥á¢áá¡ á áááá¥á¢áá ááá'; +$labels['contacts'] = 'áááá¢áá¥á¢ááá'; +$labels['personalinfo'] = 'ááá ááá ááá¤áá áááªáá'; $labels['edit'] = 'á áááá¥á¢áá ááá'; $labels['cancel'] = 'ááá£á¥áááá'; $labels['save'] = 'á¨áááá®áá'; $labels['delete'] = 'á¬áá¨áá'; +$labels['rename'] = 'ááááá á¥áááá'; +$labels['addphoto'] = 'ááááá¢ááá'; +$labels['replacephoto'] = 'áááááªááá'; $labels['newcontact'] = 'áááá¢áá¥á¢áá¡ á¨áá¥ááá'; $labels['deletecontact'] = 'ááááá¨áááá áááá¢áá¥á¢áá¡ á¬áá¨áá'; $labels['composeto'] = 'á¤áá¡á¢áá¡ áááááááá á¨áá á©áá£á ááá áá¡áá¢ááááá'; @@ -188,12 +228,18 @@ $labels['contactsfromto'] = 'áááá¢áá¥á¢ááá $from ááá $to $labels['print'] = 'áááááááá'; $labels['export'] = 'áá¥á¡ááá á¢á'; $labels['exportvcards'] = 'áááá¢áá¥á¢áááá¡ áá¥á¡ááá á¢á vCard á¤áá ááá¢á¨á'; +$labels['newcontactgroup'] = 'áá®ááá á¡ááááá¢áá¥á¢á á¯áá£á¤áá¡ á¨áá¥ááá'; +$labels['grouprename'] = 'á¯áá£á¤áá¡ á¡áá®áááá¡ á¨ááªááá'; +$labels['groupdelete'] = 'á¯áá£á¤áá¡ á¬áá¨áá'; $labels['previouspage'] = 'á¬áááá¡ á©áááááá'; $labels['firstpage'] = 'ááá ááááá¡ á©áááááá'; $labels['nextpage'] = 'á¨ááááááá¡ á©áááááá'; $labels['lastpage'] = 'ááááá¡ á©áááááá'; +$labels['group'] = 'á¯áá£á¤á'; $labels['groups'] = 'á¯áá£á¤ááá'; $labels['personaladrbook'] = 'ááá á¡ááááá£á á ááá¡áááá áááá'; +$labels['searchsave'] = 'á«ááááá¡ á¨áááá®áá'; +$labels['searchdelete'] = 'á«ááááá¡ á¬áá¨áá'; $labels['import'] = 'á¨áááá¢ááá'; $labels['importcontacts'] = 'áááá¢áá¥á¢áááá¡ á¨áááá¢ááá'; $labels['importfromfile'] = 'á¨áááá¢ááá á¤ááááááá:'; @@ -209,6 +255,12 @@ $labels['manageidentities'] = 'áá áá¤áááááá¡ ááá ááá $labels['newidentity'] = 'áá®ááá áá áá¤ááá'; $labels['newitem'] = 'áá®ááá'; $labels['edititem'] = 'á áááá¥á¢áá ááá'; +$labels['preferhtml'] = 'á áááá ᪠HTML'; +$labels['defaultcharset'] = 'áááá£ááá¡á®áááá á¡áááááááá áááá ááá'; +$labels['htmlmessage'] = 'HTML á¨áá¢á§ááááááá'; +$labels['dateformat'] = 'ááá áá¦áá¡ á¤áá ááá¢á'; +$labels['timeformat'] = 'áá ááá¡ á¤áá ááá¢á'; +$labels['prettydate'] = 'ááá áá ááá áá¦ááá'; $labels['setdefault'] = 'á áááá ᪠ááááááá'; $labels['autodetect'] = 'ááá¢áááá¢á£á á'; $labels['language'] = 'ááá'; @@ -240,12 +292,14 @@ $labels['autosavedraft'] = 'ááá¢áááá¢á£á á á¨áááá®áá $labels['everynminutes'] = 'á§áááá $n á¬á£áá¨á'; $labels['keepalive'] = 'á¨ááááá¬áá áá®áá á¨áá¢á§ááááááááá'; $labels['never'] = 'áá áá¡áá áá¡'; +$labels['immediately'] = 'ááá£á§ááááááá'; $labels['messagesdisplaying'] = 'áááááá©ááá á¨áá¢á§ááááááááá'; $labels['messagescomposition'] = 'á¨áá¢á§áááááááááá¡ á¨áá¥ááá'; $labels['mimeparamfolding'] = 'ááá£ááá¡ á¡áá®ááááá'; $labels['2231folding'] = 'Full RFC 2231 (Thunderbird)'; $labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; $labels['2047folding'] = 'Full RFC 2047 (other)'; +$labels['force7bit'] = 'MIME ááááá áááá¡ ááááá§ááááá 8 ááá¢áááá á¡áááááááááá¡áááá¡'; $labels['advancedoptions'] = 'ááááá¢ááááá ááá áááá¢á ááá'; $labels['focusonnewmessage'] = 'á¤ááá£á¡áá ááá áá®áá á¨áá¢á§áááááááááá'; $labels['checkallfolders'] = 'á¨ááááá¬áá á§áááá á¡áá¥áá¦áááá áá®áá á¨áá¢á§ááááááááá'; @@ -267,6 +321,8 @@ $labels['replysignaturepos'] = 'áá®áááá ááá¡á£á®áá¡ áá $labels['belowquote'] = 'áªáá¢áá¢áá¡ á¨ááááá'; $labels['abovequote'] = 'áªáá¢áá¢áááá'; $labels['insertsignature'] = 'á®áááááªáá áá¡ á©áá¡áá'; +$labels['afternseconds'] = '$n á¬áááá¡ á¨ááááá'; +$labels['addtodict'] = 'ááá¥á¡ááááá¨á ááááá¢ááá'; $labels['folder'] = 'á¡áá¥áá¦áááá'; $labels['folders'] = 'á¡áá¥áá¦ááááááá'; $labels['foldername'] = 'á¡áá¥áá¦ááááá¡ ááá¡áá®ááááá'; @@ -276,12 +332,34 @@ $labels['create'] = 'á¨áá¥ááá'; $labels['createfolder'] = 'á¡áá¥áá¦ááááá¡ á¨áá¥ááá'; $labels['managefolders'] = 'á¡áá¥áá¦áááááááá¡ ááá ááá'; $labels['specialfolders'] = 'á¡áááªáááá£á á á¡áá¥áá¦áááá'; +$labels['location'] = 'áááááá áááá'; +$labels['info'] = 'ááá¤áá áááªáá'; +$labels['foldertype'] = 'ááá¡á¢áá¡ á¢ááá'; +$labels['personalfolder'] = 'ááá á«á ááá¡á¢á'; +$labels['sharedfolder'] = 'á¡áá¯áá á ááá¡á¢á'; $labels['sortby'] = 'áááááááá'; $labels['sortasc'] = 'áááááááá áá ááááááá'; $labels['sortdesc'] = 'áááááááá áááááááááá'; -$labels['B'] = 'á'; -$labels['KB'] = 'áá'; -$labels['MB'] = 'áá'; -$labels['GB'] = 'áá'; +$labels['undo'] = 'áááá á£áááá'; +$labels['B'] = 'áá¢'; +$labels['KB'] = 'ááá¢'; +$labels['MB'] = 'ááá¢'; +$labels['GB'] = 'ááá¢'; +$labels['unicode'] = 'á£áááááá'; +$labels['english'] = 'ááá¡áááá¡á£á á'; +$labels['westerneuropean'] = 'ááá¡áááá£á ááá ááá£áá'; +$labels['easterneuropean'] = 'áá¦ááá¡áááááááá ááá£áá'; +$labels['baltic'] = 'áááá¢áá£á á'; +$labels['cyrillic'] = 'ááá ááááªá'; +$labels['arabic'] = 'áá ááá£áá'; +$labels['greek'] = 'ááá á«áá£áá'; +$labels['hebrew'] = 'ááá áá£áá'; +$labels['turkish'] = 'áá£á á¥á£áá'; +$labels['thai'] = 'á¢áá'; +$labels['celtic'] = 'áááá¢á£á á'; +$labels['vietnamese'] = 'áááá¢áááá£á á'; +$labels['japanese'] = 'áááááá£á á'; +$labels['korean'] = 'ááá áá£áá'; +$labels['chinese'] = 'á©ááá£á á'; ?> diff --git a/program/localization/ka_GE/messages.inc b/program/localization/ka_GE/messages.inc index 4865847..55d3333 100755 --- a/program/localization/ka_GE/messages.inc +++ b/program/localization/ka_GE/messages.inc @@ -9,7 +9,7 @@ | Licensed under the GNU GPL | | | +-----------------------------------------------------------------------+ -| Author: Zaza Zviadadze | +| Author: Zaza Zviadadze, George Machitidze | +-----------------------------------------------------------------------+ @version $Id: messages.inc 842 2009-10-03 19:30:00 zaza$ @@ -22,12 +22,16 @@ $messages['cookiesdisabled'] = 'áá¥áááá áá áá£ááá á á $messages['sessionerror'] = 'áá¥áááá á¡áá¡áá áá áá¡ ááªááá á áá ááááááá¡á£áá'; $messages['imaperror'] = 'IMAP á¡áá ááá ááá áááááá¨áá ááá á¨áá£á«ááááááá'; $messages['servererror'] = 'á¨ááªáááá á¡áá ááá áá!'; +$messages['servererrormsg'] = 'á¡áá ááá áá¡ á¨ááªáááá: $msg'; +$messages['dberror'] = 'áááááªáááá ááááá¡ á¨ááªáááá!'; +$messages['errornoperm'] = 'ááá¥ááááááá¡ á¨áá¡á á£áááá á¨áá£á«ááááááá. á¬ááááá ááá á«ááá£ááá.'; $messages['invalidrequest'] = 'áá áá¡á¬áá á áááá®áááá! áááááªáááááá¡ á¨áááá®áá áá ááá®áá á®áá.'; $messages['nomessagesfound'] = 'áá áá áá¡ áá®ááá á¨áá¢á§ááááááá'; $messages['loggedout'] = 'á¬áá ááá¢áááá áááá®á£á á áá¥áááá á¡áá¡áá'; $messages['mailboxempty'] = 'á¡áá¤áá¡á¢á á§á£áá áªáá ááááá'; $messages['loading'] = 'áá¢ááá áááá...'; $messages['uploading'] = 'á¤áááá áá¢ááá áááá...'; +$messages['uploadingmany'] = 'á¤ááááááá¡ áá¢ááá ááá...'; $messages['loadingdata'] = 'áááááªáááááá¡ á©áá¢ááá ááá...'; $messages['checkingmail'] = 'áá®ááá á¨áá¢á§áááááááá¡ ááá®áá'; $messages['sendingmessage'] = 'á¨áá¢á§áááááááá¡ áááááááá'; @@ -52,6 +56,7 @@ $messages['deletecontactconfirm'] = 'ááááááááá áá¡á£á á $messages['deletemessagesconfirm'] = 'ááááááááá áá¡á£á á ááááá¨áá£áá á¨áá¢á§áááááááááá¡ á¬áá¨áá?'; $messages['deletefolderconfirm'] = 'ááááááááá áá¡á£á á áá á¡áá¥áá¦ááááá¡ á¬áá¨áá?'; $messages['purgefolderconfirm'] = 'ááááááááá áá¡á£á á á§áááá á¨áá¢á§áááááááá¡ á¬áá¨áá áá¦ááá¨áá£á á¡áá¥áá¦ááááá¨á?'; +$messages['groupdeleting'] = 'á¯áá£á¤áá¡ á¬áá¨áá...'; $messages['folderdeleting'] = 'á¡áá¥áá¦ááááá¡ á¬áá¨áá...'; $messages['foldermoving'] = 'á¡áá¥áá¦ááááá¡ ááááá¢ááá...'; $messages['formincomplete'] = 'á§áááá áááá áá áá áá¡ á¨ááá¡ááá£áá'; @@ -64,10 +69,10 @@ $messages['nosubjectwarning'] = 'áá¡á£á á áᣠáá á á¨áá¢á§ $messages['nobodywarning'] = 'áá¡á£á á áᣠáá á á¨áá¢á§áááááááá¡ áááááááá á£á¢áá¥á¡á¢áá?'; $messages['notsentwarning'] = 'á¨áá¢á§ááááááá ááá áá¥áá áááááááááá. áá¡á£á á áᣠáá á ááááááááá¡ ááá£á¥áááá?'; $messages['noldapserver'] = 'ááá£ááááá LDAP á¡áá ááá á á«ááááá¡áááá¡'; -$messages['nocontactsreturned'] = 'áááá¢áá¥á¢ááá ááá ááá«áááá'; $messages['nosearchname'] = 'ááá£ááááá á¡áá®ááá áá ááâá¤áá¡á¢áá¡ ááá¡áááá áá'; $messages['notuploadedwarning'] = 'á¯áá áá áá¢ááá áá£áá á§áááá áááááá ááá£áá á¤áááá. áááááááá áá áááá£á¥ááá áá¢ááá ááá.'; $messages['searchsuccessful'] = '$nr á¨áá¢á§áááááá áááá«áááá'; +$messages['contactsearchsuccessful'] = 'áááááááá $nr áááá¢áá¥á¢á'; $messages['searchnomatch'] = 'á¨áá¢á§ááááááá ááá áááá«áááá'; $messages['searching'] = 'á«áááá...'; $messages['checking'] = 'á¨áááá¬áááá...'; @@ -103,5 +108,17 @@ $messages['smtptoerror'] = 'SMTP Error ($code): ááá áááááá¢á $messages['smtprecipientserror'] = 'SMTP Error: áááá¦áááá á©ááááááááááá¡ áááá£á¨ááááá ááá ááá®áá á®áá'; $messages['smtperror'] = 'SMTP Error: $msg'; $messages['emailformaterror'] = 'áá-á¤áá¡á¢áá¡ ááá¡áááá áá áá áá¡á¬áá áá $email'; +$messages['contactdeleted'] = 'áááá¢áá¥á¢(áá)á á¬áá ááá¢áááá á¬ááá¨ááá.'; +$messages['contactrestored'] = 'áááá áá¥á¢(áá)á á¬áá ááá¢áááá áá¦ááá,'; +$messages['groupdeleted'] = 'á¯áá£á¤á á¬áá ááá¢áááá á¬ááá¨ááá.'; +$messages['groupcreated'] = 'á¯áá£á¤á á¬áá ááá¢áááá á¨ááá¥ááá.'; +$messages['messagedeleted'] = 'á¨áá¢á§ááááááááá á¬áá ááá¢áááá á¬ááá¨ááá.'; +$messages['messagemoved'] = 'á¨áá¢á§ááááááááá ááááá¢áááááá á¬áá ááá¢áááá.'; +$messages['messagemarked'] = 'á¨áá¢á§ááááááááá á¬áá ááá¢áááá áááááá¨áá.'; +$messages['namecannotbeempty'] = 'á¡áá®ááá áá á¨ááá«áááá áá§áá¡ áªáá áááá.'; +$messages['nametoolong'] = 'á¡áá®ááá á«ááááá áááááá.'; +$messages['folderupdated'] = 'ááá¡á¢á á¬áá ááá¢áááá ááááá®ááá.'; +$messages['foldercreated'] = 'ááá¡á¢á á¬áá ááá¢áááá á¨ááá¥ááá.'; +$messages['invalidimageformat'] = 'ááááá¡áá®á£ááááá¡ á¤áá ááá¢á áá áá¡á¬áá áá.'; ?> diff --git a/program/localization/lt_LT/labels.inc b/program/localization/lt_LT/labels.inc index 623fd1e..9f9af61 100644 --- a/program/localization/lt_LT/labels.inc +++ b/program/localization/lt_LT/labels.inc @@ -14,7 +14,7 @@ | Rimas Kudelis <rq@akl.lt> | +-----------------------------------------------------------------------+' -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -118,7 +118,7 @@ $labels['markread'] = 'Kaip skaitytus'; $labels['markunread'] = 'Kaip neskaitytus'; $labels['markflagged'] = 'PažymÄti gairele'; $labels['markunflagged'] = 'PaÅ¡alinti gairelÄ'; -$labels['messageactions'] = 'Daugiau veiksmųâ¦'; +$labels['moreactions'] = 'Kiti veiksmaiâ¦'; $labels['select'] = 'PažymÄti'; $labels['all'] = 'visus'; $labels['none'] = 'nieko'; @@ -151,7 +151,7 @@ $labels['listsorting'] = 'Stulpelis rikiavimui'; $labels['listorder'] = 'Rikiavimo tvarka'; $labels['listmode'] = 'SÄ raÅ¡o rodymo veiksena'; $labels['folderactions'] = 'Veiksmai su aplankaisâ¦'; -$labels['compact'] = 'Suspausti'; +$labels['compact'] = 'Suglaudinti'; $labels['empty'] = 'IÅ¡tuÅ¡tinti'; $labels['quota'] = 'Disko naudojimas'; $labels['unknown'] = 'nežinomas'; @@ -172,6 +172,7 @@ $labels['editortype'] = 'LaiÅ¡ko tipas'; $labels['returnreceipt'] = 'PraÅ¡yti pristatymo pažymos'; $labels['dsn'] = 'LaiÅ¡ko pristatymo pažyma'; $labels['mailreplyintro'] = '$date, $sender raÅ¡Ä:'; +$labels['originalmessage'] = 'Originalus laiÅ¡kas'; $labels['editidents'] = 'Tvarkyti tapatybes'; $labels['checkspelling'] = 'Tikrinti raÅ¡ybÄ '; $labels['resumeediting'] = 'TÄsti redagavimÄ '; @@ -189,6 +190,7 @@ $labels['highest'] = 'AukÅ¡Äiausias'; $labels['nosubject'] = '(tema nenurodyta)'; $labels['showimages'] = 'Rodyti paveikslÄlius'; $labels['alwaysshow'] = 'Visada rodyti paveikslÄlius $sender laiÅ¡kuose'; +$labels['isdraft'] = 'Tai â laiÅ¡ko juodraÅ¡tis.'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Grynasis tekstas'; $labels['savesentmessagein'] = 'IÅ¡siųstus laiÅ¡kus įraÅ¡yti į'; @@ -247,6 +249,8 @@ $labels['typepager'] = 'PraneÅ¡imų gaviklis'; $labels['typevideo'] = 'Vaizdo'; $labels['typeassistant'] = 'PadÄjÄjo(-os)'; $labels['typehomepage'] = 'Tinklalapis'; +$labels['typeblog'] = 'TinklaraÅ¡tis'; +$labels['typeprofile'] = 'Profilis'; $labels['addfield'] = 'PridÄti laukÄ â¦'; $labels['addcontact'] = 'PridÄti adresatÄ '; $labels['editcontact'] = 'Taisyti adresatÄ '; @@ -268,7 +272,6 @@ $labels['print'] = 'Spausdinti'; $labels['export'] = 'Eksportuoti'; $labels['exportvcards'] = 'Eksportuoti adresatus âvCardâ formatu'; $labels['newcontactgroup'] = 'Kurti adresatų grupÄ'; -$labels['groupactions'] = 'Adresatų grupÄms taikomi veiksmaiâ¦'; $labels['grouprename'] = 'Pervardinti grupÄ'; $labels['groupdelete'] = 'PaÅ¡alinti grupÄ'; $labels['previouspage'] = 'Rodyti ankstesnį puslapį'; @@ -278,6 +281,8 @@ $labels['lastpage'] = 'Rodyti paskutinį puslapį'; $labels['group'] = 'GrupÄ'; $labels['groups'] = 'GrupÄs'; $labels['personaladrbook'] = 'Asmeniniai adresai'; +$labels['searchsave'] = 'Ä®raÅ¡yti kaip radinių aplankÄ '; +$labels['searchdelete'] = 'PaÅ¡alinti radinių aplankÄ '; $labels['import'] = 'Importuoti'; $labels['importcontacts'] = 'Importuoti adresatus'; $labels['importfromfile'] = 'Importuoti iÅ¡ failo:'; @@ -286,6 +291,7 @@ $labels['importreplace'] = 'PerraÅ¡yti visÄ adresų knygÄ '; $labels['importtext'] = 'JÅ«s galite įkelti adresatus iÅ¡ egzistuojanÄios adresų knygos.<br/>Å iuo metu galima importuoti adresus iÅ¡ <a href="http://en.wikipedia.org/wiki/VCard">vCard</a> tipo failų.'; $labels['done'] = 'Baigta'; $labels['settingsfor'] = 'Nustatymai'; +$labels['about'] = 'Apie'; $labels['preferences'] = 'Nustatymai'; $labels['userpreferences'] = 'Naudotojo nustatymai'; $labels['editpreferences'] = 'Redaguoti naudotojo nustatymus'; @@ -297,6 +303,8 @@ $labels['edititem'] = 'Redaguoti elementÄ '; $labels['preferhtml'] = 'Rodyti HTML'; $labels['defaultcharset'] = 'Numatytoji koduotÄ'; $labels['htmlmessage'] = 'HTML laiÅ¡kas'; +$labels['dateformat'] = 'Datos formatas'; +$labels['timeformat'] = 'Laiko formatas'; $labels['prettydate'] = 'Dailios datos'; $labels['setdefault'] = 'Laikyti numatytÄ ja'; $labels['autodetect'] = 'Aptikti automatiÅ¡kai'; @@ -311,7 +319,7 @@ $labels['htmlsignature'] = 'HTML paraÅ¡as'; $labels['previewpane'] = 'Rodyti laiÅ¡ko peržiÅ«ros polangį'; $labels['skin'] = 'Grafinis apvalkalas'; $labels['logoutclear'] = 'IÅ¡valyti Å iukÅ¡linÄ atsijungiant'; -$labels['logoutcompact'] = 'Suspausti Gautų laiÅ¡kų aplankÄ atsijungiant'; +$labels['logoutcompact'] = 'Suglaudinti gautųjų laiÅ¡kų aplankÄ atsijungiant'; $labels['uisettings'] = 'Naudotojo sÄ saja'; $labels['serversettings'] = 'Serverio nustatymai'; $labels['mailboxview'] = 'PaÅ¡to dÄžutÄs rodymas'; @@ -368,7 +376,13 @@ $labels['reqmdn'] = 'Visuomet praÅ¡yti patvirtinimo, jog laiÅ¡kas perskaitytas'; $labels['reqdsn'] = 'Visuomet praÅ¡yti laiÅ¡ko pristatymo pažymos'; $labels['replysamefolder'] = 'Atsakymus talpinti į tÄ patį aplankÄ , kuriame yra pirminis laiÅ¡kas'; $labels['defaultaddressbook'] = 'PridÄti naujus adresatus į pasirinktÄ jÄ adresų knygÄ '; +$labels['autocompletesingle'] = 'Užbaigiant adresus, praleisti antrinius'; $labels['spellcheckbeforesend'] = 'Tikrinti raÅ¡ybÄ prieÅ¡ iÅ¡siunÄiant laiÅ¡kÄ '; +$labels['spellcheckoptions'] = 'RaÅ¡ybos tikrinimo nuostatos'; +$labels['spellcheckignoresyms'] = 'Nepaisyti žodžių su spec. simboliais'; +$labels['spellcheckignorenums'] = 'Nepaisyti žodžių su skaitmenimis'; +$labels['spellcheckignorecaps'] = 'Nepaisyti žodžių vien iÅ¡ didžiųjų raidžių'; +$labels['addtodict'] = 'Ä®traukti į žodynÄ '; $labels['folder'] = 'Aplankas'; $labels['folders'] = 'Aplankai'; $labels['foldername'] = 'Aplanko vardas'; @@ -393,6 +407,11 @@ $labels['sortby'] = 'Rikiuoti pagal'; $labels['sortasc'] = 'Rikiuoti didÄjanÄiai'; $labels['sortdesc'] = 'Rikiuoti mažÄjanÄiai'; $labels['undo'] = 'AtÅ¡aukti'; +$labels['plugin'] = 'Papildinys'; +$labels['version'] = 'Versija'; +$labels['source'] = 'Å altinis'; +$labels['license'] = 'Licencija'; +$labels['support'] = 'Gauti pagalbos'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/lt_LT/messages.inc b/program/localization/lt_LT/messages.inc index 151277e..4cff2b0 100644 --- a/program/localization/lt_LT/messages.inc +++ b/program/localization/lt_LT/messages.inc @@ -14,7 +14,7 @@ | Rimas Kudelis <rq@akl.lt> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -25,7 +25,7 @@ $messages['sessionerror'] = 'JÅ«sų sesija negaliojanti.'; $messages['imaperror'] = 'Nepavyko prisijungti prie IMAP serverio.'; $messages['servererror'] = 'Serverio klaida!'; $messages['servererrormsg'] = 'Serverio klaida: $msg'; -$messages['databaserror'] = 'Duomenų bazÄs klaida!'; +$messages['dberror'] = 'Duomenų bazÄs klaida!'; $messages['errorreadonly'] = 'Nepavyko atlikti veiksmo â aplankas prieinamas tik skaitymui.'; $messages['errornoperm'] = 'Nepavyko atlikti veiksmo â nepakanka teisių.'; $messages['invalidrequest'] = 'Netinkama užklausa! Duomenys neiÅ¡saugoti.'; @@ -49,6 +49,7 @@ $messages['blockedimages'] = 'Siekiant apsaugoti JÅ«sų privatumÄ , paveikslÄli $messages['encryptedmessage'] = 'Apgailestaujame, taÄiau Å¡is laiÅ¡kas užšifruotas ir negali bÅ«ti parodytas.'; $messages['nocontactsfound'] = 'Adresatų nerasta.'; $messages['contactnotfound'] = 'IeÅ¡kotas adresatas nerastas.'; +$messages['contactsearchonly'] = 'Ä®veskite reikÅ¡minius žodžius adresatų paieÅ¡kai'; $messages['sendingfailed'] = 'LaiÅ¡ko iÅ¡siųsti nepavyko.'; $messages['senttooquickly'] = 'Turite luktelÄti $sec sek., kad galÄtumÄte iÅ¡siųsti laiÅ¡kÄ .'; $messages['errorsavingsent'] = 'Ä®raÅ¡ant iÅ¡siųstÄ laiÅ¡kÄ Ä¯vyko klaida.'; @@ -62,6 +63,7 @@ $messages['deletegroupconfirm'] = 'Ar tikrai paÅ¡alinti pažymÄtÄ grupÄ?'; $messages['deletemessagesconfirm'] = 'Ar tikrai paÅ¡alinti pažymÄtÄ (-us) laiÅ¡kÄ (-us)?'; $messages['deletefolderconfirm'] = 'Ar tikrai paÅ¡alinti šį aplankÄ ?'; $messages['purgefolderconfirm'] = 'Ar tikrai paÅ¡alinti visus Å¡iame aplanke esanÄius laiÅ¡kus?'; +$messages['contactdeleting'] = 'Adresatas(-ai) Å¡alinamas(-i)â¦'; $messages['groupdeleting'] = 'GrupÄ Å¡alinamaâ¦'; $messages['folderdeleting'] = 'Aplankas Å¡alinamasâ¦'; $messages['foldermoving'] = 'Aplankas perkeliamasâ¦'; @@ -77,10 +79,10 @@ $messages['nosubjectwarning'] = 'Temos laukelis tuÅ¡Äias. Ar norite temÄ Ä¯ves $messages['nobodywarning'] = 'IÅ¡siųsti šį laiÅ¡kÄ be teksto?'; $messages['notsentwarning'] = 'LaiÅ¡kas neiÅ¡siųstas. Ar jÅ«s tikrai norite jo atsikratyti?'; $messages['noldapserver'] = 'PraÅ¡ome pasirinkti LDAP serverį paieÅ¡kai.'; -$messages['nocontactsreturned'] = 'Jokių adresatų nerasta.'; $messages['nosearchname'] = 'PraÅ¡om įvesti vardÄ arba el. paÅ¡to adresÄ .'; $messages['notuploadedwarning'] = 'Ä®kelti dar ne visi priedai. PraÅ¡om palaukti arba atÅ¡aukti jų įkÄlimÄ .'; $messages['searchsuccessful'] = 'Rasta laiÅ¡kų: $nr.'; +$messages['contactsearchsuccessful'] = 'Rasta adresatų: $nr.'; $messages['searchnomatch'] = 'PaieÅ¡kÄ atitinkanÄių rezultatų nÄra.'; $messages['searching'] = 'IeÅ¡komaâ¦'; $messages['checking'] = 'Tikrinamaâ¦'; @@ -127,7 +129,6 @@ $messages['smtpautherror'] = 'SMTP klaida ($code): nepavyko autentikuotis.'; $messages['smtpfromerror'] = 'SMTP klaida ($code): nepavyko nurodyti siuntÄjo â$fromâ ($msg).'; $messages['smtptoerror'] = 'SMTP klaida ($code): nepavyko pridÄti gavÄjo â$toâ ($msg).'; $messages['smtprecipientserror'] = 'SMTP klaida: nepavyko apdoroti gavÄjų sÄ raÅ¡o.'; -$messages['smtpdsnerror'] = 'SMTP klaida: laiÅ¡kų pristatymo pažymos nepalaikomos.'; $messages['smtperror'] = 'SMTP klaida: $msg'; $messages['emailformaterror'] = 'Netinkamas el. paÅ¡to adresas: $email'; $messages['toomanyrecipients'] = 'Per daug gavÄjų. Sumažinkite jų bent iki $max.'; @@ -140,11 +141,16 @@ $messages['contactrestored'] = 'Adresatas(-ai) sÄkmingai atkurtas(-i).'; $messages['groupdeleted'] = 'GrupÄ sÄkmingai paÅ¡alinta.'; $messages['grouprenamed'] = 'GrupÄ sÄkmingai pervardinta.'; $messages['groupcreated'] = 'GrupÄ sÄkmingai sukurta.'; +$messages['savedsearchdeleted'] = 'Radinių aplankas sÄkmingai paÅ¡alintas.'; +$messages['savedsearchdeleteerror'] = 'Radinių aplanko paÅ¡alinti nepavyko.'; +$messages['savedsearchcreated'] = 'Radinių aplankas sÄkmingai sukurtas.'; +$messages['savedsearchcreateerror'] = 'Radinių aplanko sukurti nepavyko.'; $messages['messagedeleted'] = 'LaiÅ¡kas(-ai) sÄkmingai paÅ¡alintas(-i).'; $messages['messagemoved'] = 'LaiÅ¡kas(-ai) sÄkmingai perkeltas(-i).'; $messages['messagecopied'] = 'LaiÅ¡kas(-ai) sÄkmingai nukopijuotas(-i).'; $messages['messagemarked'] = 'LaiÅ¡kas(-ai) sÄkmingai pažymÄtas(-i).'; $messages['autocompletechars'] = 'Automatiniam užbaigimui bÅ«tini bent $min simboliai.'; +$messages['autocompletemore'] = 'Rasta daugiau atitikmenų. Ä®veskite dar porÄ simbolių.'; $messages['namecannotbeempty'] = 'Vardas negali bÅ«ti tuÅ¡Äias.'; $messages['nametoolong'] = 'Vardas yra per ilgas.'; $messages['folderupdated'] = 'Aplanko savybÄs sÄkmingai atnaujintos.'; @@ -152,5 +158,6 @@ $messages['foldercreated'] = 'Aplankas sÄkmingai sukurtas.'; $messages['invalidimageformat'] = 'Paveikslo formatas netinkamas.'; $messages['mispellingsfound'] = 'LaiÅ¡ke rasta raÅ¡ybos klaidų.'; $messages['parentnotwritable'] = 'Nepavyko sukurti arba perkelti aplanko į parinktÄ tÄvinį aplankÄ . TrÅ«ksta prieigos teisių.'; +$messages['messagetoobig'] = 'LaiÅ¡ko dalis yra per didelÄ, kad galÄtų bÅ«ti apdorota.'; ?> diff --git a/program/localization/lv_LV/labels.inc b/program/localization/lv_LV/labels.inc index 46bcf80..d0df666 100644 --- a/program/localization/lv_LV/labels.inc +++ b/program/localization/lv_LV/labels.inc @@ -16,7 +16,7 @@ | Kaspars Tenters <kaspars.tenters@va.lv> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5173 2011-09-05 18:41:04Z thomasb $ */ diff --git a/program/localization/lv_LV/messages.inc b/program/localization/lv_LV/messages.inc index 8c6ab5a..698baca 100644 --- a/program/localization/lv_LV/messages.inc +++ b/program/localization/lv_LV/messages.inc @@ -16,7 +16,7 @@ | Kaspars Tenters <kaspars.tenters@va.lv> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5173 2011-09-05 18:41:04Z thomasb $ */ diff --git a/program/localization/nl_NL/labels.inc b/program/localization/nl_NL/labels.inc index 1c616a1..0186f47 100644 --- a/program/localization/nl_NL/labels.inc +++ b/program/localization/nl_NL/labels.inc @@ -17,7 +17,7 @@ | Justin van Beusekom <j.v.beusekom@beus-it.nl> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4549 2011-02-15 14:33:45Z robin $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -104,18 +104,16 @@ $labels['replytomessage'] = 'Beantwoord het bericht'; $labels['replytoallmessage'] = 'Beantwoord lijst of afzender en alle ontvangers'; $labels['replyall'] = 'Beantwoord alle ontvangers'; $labels['replylist'] = 'Beantwoord lijst'; +$labels['forwardinline'] = 'Doorsturen in bericht'; +$labels['forwardattachment'] = 'Doorsturen als bijlage'; $labels['forwardmessage'] = 'Bericht doorsturen'; $labels['deletemessage'] = 'Verwijder het bericht'; $labels['movemessagetotrash'] = 'Verplaats het bericht naar de prullenbak'; $labels['printmessage'] = 'Dit bericht afdrukken'; $labels['previousmessage'] = 'Toon het vorige bericht'; -$labels['previousmessages'] = 'Toon vorige lijst met berichten'; $labels['firstmessage'] = 'Toon het eerste bericht'; -$labels['firstmessages'] = 'Toon eerste lijst met berichten'; $labels['nextmessage'] = 'Toon het volgende bericht'; -$labels['nextmessages'] = 'Toon volgende lijst met berichten'; $labels['lastmessage'] = 'Toon het laatste bericht'; -$labels['lastmessages'] = 'Toon laatste lijst met berichten'; $labels['backtolist'] = 'Terug naar berichtenoverzicht'; $labels['viewsource'] = 'Toon bron'; $labels['markmessages'] = 'Markeer berichten'; @@ -123,7 +121,7 @@ $labels['markread'] = 'Gelezen'; $labels['markunread'] = 'Ongelezen'; $labels['markflagged'] = 'Selecteren'; $labels['markunflagged'] = 'Niet selecteren'; -$labels['messageactions'] = 'Meer acties...'; +$labels['moreactions'] = 'Meer acties'; $labels['select'] = 'Selecteer'; $labels['all'] = 'Allemaal'; $labels['none'] = 'Geen'; @@ -176,12 +174,15 @@ $labels['charset'] = 'Karakterset'; $labels['editortype'] = 'Opmaak'; $labels['returnreceipt'] = 'Ontvangstbevestiging'; $labels['dsn'] = 'Afleverings status notificatie (DSN)'; +$labels['mailreplyintro'] = '$sender schreef op $date:'; +$labels['originalmessage'] = 'Originele bericht'; $labels['editidents'] = 'Bewerk identiteiten'; $labels['checkspelling'] = 'Controleer spelling'; $labels['resumeediting'] = 'Doorgaan met opstellen'; $labels['revertto'] = 'Wijzig terug in'; $labels['attachments'] = 'Bijlages'; $labels['upload'] = 'Toevoegen'; +$labels['uploadprogress'] = '$percent ($current van $total)'; $labels['close'] = 'Sluit'; $labels['messageoptions'] = 'Acties voor bericht...'; $labels['low'] = 'Laag'; @@ -192,6 +193,7 @@ $labels['highest'] = 'Hoogste'; $labels['nosubject'] = '(geen onderwerp)'; $labels['showimages'] = 'Toon afbeeldingen'; $labels['alwaysshow'] = 'Afbeeldingen van $sender altijd tonen'; +$labels['isdraft'] = 'Dit is een concept.'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Gewone tekst'; $labels['savesentmessagein'] = 'Bewaar verzonden bericht in'; @@ -234,6 +236,10 @@ $labels['female'] = 'Vrouw'; $labels['manager'] = 'Manager'; $labels['assistant'] = 'Assistent'; $labels['spouse'] = 'Echtgenoot'; +$labels['allfields'] = 'Alle velden'; +$labels['search'] = 'Zoeken'; +$labels['advsearch'] = 'Geavanceerd zoeken'; +$labels['other'] = 'Anders'; $labels['typehome'] = 'Thuis'; $labels['typework'] = 'Werk'; $labels['typeother'] = 'Anders'; @@ -245,6 +251,9 @@ $labels['typecar'] = 'Auto'; $labels['typepager'] = 'Pieper'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Assistent'; +$labels['typehomepage'] = 'Website'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profiel'; $labels['addfield'] = 'Veld toevoegen...'; $labels['addcontact'] = 'Nieuwe contactpersoon toevoegen'; $labels['editcontact'] = 'Contactpersoon wijzigen'; @@ -266,7 +275,8 @@ $labels['print'] = 'Afdrukken'; $labels['export'] = 'Exporteren'; $labels['exportvcards'] = 'Exporteer contactpersonen in vCard formaat'; $labels['newcontactgroup'] = 'Maak een nieuwe contactgroep'; -$labels['groupactions'] = 'Acties voor contactgroepen...'; +$labels['grouprename'] = 'Groep hernoemen'; +$labels['groupdelete'] = 'Groep verwijderen'; $labels['previouspage'] = 'Vorige pagina'; $labels['firstpage'] = 'Eerste pagina'; $labels['nextpage'] = 'Volgende pagina'; @@ -274,9 +284,12 @@ $labels['lastpage'] = 'Laatste pagina'; $labels['group'] = 'Groep'; $labels['groups'] = 'Groepen'; $labels['personaladrbook'] = 'Persoonlijk Adresboek'; +$labels['searchsave'] = 'Zoekopdracht opslaan'; +$labels['searchdelete'] = 'Zoekopdracht verwijderen'; $labels['import'] = 'Importeer'; $labels['importcontacts'] = 'Contactpersonen importeren'; $labels['importfromfile'] = 'Importeer van bestand:'; +$labels['importtarget'] = 'Voeg nieuwe contactpersonen toe aan adresboek:'; $labels['importreplace'] = 'Vervang het complete adresboek'; $labels['importtext'] = 'U kunt hier contactpersonen importeren vanuit een bestaand adresboek.<br />Op dit moment ondersteunen wij het <a href="http://nl.wikipedia.org/wiki/VCard">vCard</a> bestandsformaat.'; $labels['done'] = 'Klaar'; @@ -292,6 +305,8 @@ $labels['edititem'] = 'Wijzig item'; $labels['preferhtml'] = 'Toon HTML'; $labels['defaultcharset'] = 'Standaard karakterset'; $labels['htmlmessage'] = 'HTML-Bericht'; +$labels['dateformat'] = 'Datum formaat'; +$labels['timeformat'] = 'Tijd formaat'; $labels['prettydate'] = 'Gebruiksvriendelijke data'; $labels['setdefault'] = 'Stel in als standaard'; $labels['autodetect'] = 'Automatisch'; @@ -362,6 +377,14 @@ $labels['afternseconds'] = 'Na $n seconden'; $labels['reqmdn'] = 'Vraag altijd een ontvangstbevestiging'; $labels['reqdsn'] = 'Vraag altijd een afleverings status notificatie (DSN)'; $labels['replysamefolder'] = 'Plaats antwoorden in de folder van het beantwoorde bericht'; +$labels['defaultaddressbook'] = 'Voeg nieuw contactpersoon toe aan geselecteerd adresboek'; +$labels['autocompletesingle'] = 'Sla alternatieve E-mail adressen over bij automatisch aanvullen'; +$labels['spellcheckbeforesend'] = 'Controleer slepping voordat het bericht wordt verzonden'; +$labels['spellcheckoptions'] = 'Instellingen spellingscontrole'; +$labels['spellcheckignoresyms'] = 'Negeer woorden met symbolen'; +$labels['spellcheckignorenums'] = 'Negeer woorden met cijfers'; +$labels['spellcheckignorecaps'] = 'Negeer woorden welke volledig uit hoofdletters bestaan'; +$labels['addtodict'] = 'Voeg toe aan woordenboek'; $labels['folder'] = 'Map'; $labels['folders'] = 'Mappen'; $labels['foldername'] = 'Mapnaam'; @@ -378,9 +401,14 @@ $labels['location'] = 'Locatie'; $labels['info'] = 'Informatie'; $labels['getfoldersize'] = 'Klik hier voor de map grootte'; $labels['changesubscription'] = 'Klik voor het wijzigen van de inschrijving'; +$labels['foldertype'] = 'Mapgrootte'; +$labels['personalfolder'] = 'Privé map'; +$labels['otherfolder'] = 'Map van andere gebruiker'; +$labels['sharedfolder'] = 'Publieke map'; $labels['sortby'] = 'Sorteer op'; $labels['sortasc'] = 'Sorteer oplopend'; $labels['sortdesc'] = 'Sorteer aflopend'; +$labels['undo'] = 'Ongedaan maken'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/nl_NL/messages.inc b/program/localization/nl_NL/messages.inc index 8c50383..37ece88 100644 --- a/program/localization/nl_NL/messages.inc +++ b/program/localization/nl_NL/messages.inc @@ -16,136 +16,149 @@ | Justin van Beusekom <j.v.beusekom@beus-it.nl> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ $messages = array(); -$messages['loginfailed'] = 'Inloggen mislukt'; -$messages['cookiesdisabled'] = 'Uw browser accepteert geen cookies'; -$messages['sessionerror'] = 'Uw sessie is verlopen of ongeldig'; -$messages['imaperror'] = 'Connectie met IMAP server mislukt'; +$messages['loginfailed'] = 'Inloggen mislukt.'; +$messages['cookiesdisabled'] = 'Uw browser accepteert geen cookies.'; +$messages['sessionerror'] = 'Uw sessie is verlopen of ongeldig.'; +$messages['imaperror'] = 'Connectie met IMAP server mislukt.'; $messages['servererror'] = 'Server Fout!'; $messages['servererrormsg'] = 'Server Fout: $msg'; -$messages['databaserror'] = 'Database Fout!'; -$messages['errorreadonly'] = 'Niet in staat om de bewerking uit te voeren. Map is alleen-lezen'; -$messages['errornoperm'] = 'Niet in staat om de bewerking uit te voeren. Toestemming geweigerd'; +$messages['dberror'] = 'Database Fout!'; +$messages['errorreadonly'] = 'Niet in staat om de bewerking uit te voeren. Map is alleen-lezen.'; +$messages['errornoperm'] = 'Niet in staat om de bewerking uit te voeren. Toestemming geweigerd.'; $messages['invalidrequest'] = 'Ongeldige aanvraag! Er zijn geen gegevens opgeslagen.'; -$messages['nomessagesfound'] = 'Geen berichten gevonden in deze mailbox'; +$messages['nomessagesfound'] = 'Geen berichten gevonden in deze mailbox.'; $messages['loggedout'] = 'Succesvol uitgelogd. Tot ziens!'; -$messages['mailboxempty'] = 'Mailbox is leeg'; +$messages['mailboxempty'] = 'Mailbox is leeg.'; $messages['loading'] = 'Laden...'; -$messages['uploading'] = 'Bezig met uploaden...'; +$messages['uploading'] = 'Bestand wordt geüpload...'; +$messages['uploadingmany'] = 'Bestanden worden geüpload...'; $messages['loadingdata'] = 'Laden van data...'; $messages['checkingmail'] = 'Controleren op nieuwe berichten...'; $messages['sendingmessage'] = 'Bezig met bericht versturen...'; -$messages['messagesent'] = 'Bericht succesvol verstuurd'; +$messages['messagesent'] = 'Bericht succesvol verstuurd.'; $messages['savingmessage'] = 'Bezig met bericht opslaan...'; -$messages['messagesaved'] = 'Bericht bewaard als concept'; -$messages['successfullysaved'] = 'Succesvol opgeslagen'; -$messages['addedsuccessfully'] = 'Contact is succesvol toegevoegd aan het adresboek'; -$messages['contactexists'] = 'Er bestaat al een contactpersoon met dit e-mailadres'; +$messages['messagesaved'] = 'Bericht bewaard als concept.'; +$messages['successfullysaved'] = 'Succesvol opgeslagen.'; +$messages['addedsuccessfully'] = 'Contact is succesvol toegevoegd aan het adresboek.'; +$messages['contactexists'] = 'Er bestaat al een contactpersoon met dit e-mailadres.'; +$messages['contactnameexists'] = 'Er bestaat al een contactpersoon met deze naam.'; $messages['blockedimages'] = 'Uit privacyoverwegingen zijn niet bijgevoegde afbeeldingen geblokkeerd in dit bericht.'; $messages['encryptedmessage'] = 'Dit is een gecodeerd bericht en kan niet weergegeven worden. Excuses!'; -$messages['nocontactsfound'] = 'Geen contactpersonen gevonden'; -$messages['contactnotfound'] = 'Contactpersoon niet gevonden'; -$messages['sendingfailed'] = 'Verzenden van bericht is mislukt'; +$messages['nocontactsfound'] = 'Geen contactpersonen gevonden.'; +$messages['contactnotfound'] = 'Contactpersoon niet gevonden.'; +$messages['contactsearchonly'] = 'Voer enkele zoektermen in om contactpersonen te zoeken.'; +$messages['sendingfailed'] = 'Verzenden van bericht is mislukt.'; $messages['senttooquickly'] = 'Je moet $sec seconden wachten om het bericht te versturen.'; -$messages['errorsavingsent'] = 'Er is een fout opgetreden tijdens het opslaan van het verzonden bericht'; -$messages['errorsaving'] = 'Er is een fout opgetreden tijdens het opslaan'; -$messages['errormoving'] = 'Kan het bericht niet verplaatsen'; -$messages['errorcopying'] = 'Kan de bericht(en) niet kopiëren'; -$messages['errordeleting'] = 'Kan het bericht niet verwijderen'; -$messages['errormarking'] = 'Kon bericht niet markeren'; +$messages['errorsavingsent'] = 'Er is een fout opgetreden tijdens het opslaan van het verzonden bericht.'; +$messages['errorsaving'] = 'Er is een fout opgetreden tijdens het opslaan.'; +$messages['errormoving'] = 'Kan het bericht niet verplaatsen.'; +$messages['errorcopying'] = 'Kan de bericht(en) niet kopiëren.'; +$messages['errordeleting'] = 'Kan het bericht niet verwijderen.'; +$messages['errormarking'] = 'Kon bericht niet markeren.'; $messages['deletecontactconfirm'] = 'Weet u zeker dat u de geselecteerde contactperso(o)n/en wilt verwijderen?'; +$messages['deletegroupconfirm'] = 'Weet u zeker dat u de geselecteerde groep wilt verwijderen?'; $messages['deletemessagesconfirm'] = 'Weet u zeker dat u de geselecteerde bericht(en) wilt verwijderen?'; $messages['deletefolderconfirm'] = 'Weet u zeker dat u deze map wilt verwijderen?'; $messages['purgefolderconfirm'] = 'Weet u zeker dat u alle berichten in deze map wilt verwijderen?'; -$messages['folderdeleting'] = 'Map verwijderen...'; -$messages['foldermoving'] = 'Map verplaatsen...'; -$messages['foldersubscribing'] = 'Abonneren map...'; -$messages['folderunsubscribing'] = 'Afmelding map ...'; -$messages['formincomplete'] = 'Het formulier was niet volledig ingevuld'; -$messages['noemailwarning'] = 'Geef een geldig e-mailadres op'; -$messages['nonamewarning'] = 'Vul een naam in'; -$messages['nopagesizewarning'] = 'Geef een paginagrootte op'; -$messages['nosenderwarning'] = 'Geef een e-mailadres van de afzender op'; -$messages['norecipientwarning'] = 'Geef tenminste één ontvanger op'; +$messages['contactdeleting'] = 'Bezig met verwijderen één of meer contactpersonen...'; +$messages['groupdeleting'] = 'Groep wordt verwijderd...'; +$messages['folderdeleting'] = 'Map wordt verwijderd...'; +$messages['foldermoving'] = 'Map wordt verplaatst...'; +$messages['foldersubscribing'] = 'Bezig met abonneren op map...'; +$messages['folderunsubscribing'] = 'Abonnement op map wordt opgezegd...'; +$messages['formincomplete'] = 'Het formulier was niet volledig ingevuld.'; +$messages['noemailwarning'] = 'Geef een geldig e-mailadres op.'; +$messages['nonamewarning'] = 'Vul een naam in.'; +$messages['nopagesizewarning'] = 'Geef een paginagrootte op.'; +$messages['nosenderwarning'] = 'Geef een e-mailadres van de afzender op.'; +$messages['norecipientwarning'] = 'Geef tenminste één ontvanger op.'; $messages['nosubjectwarning'] = 'Het \'Onderwerp\' veld is leeg. Wilt u nu alsnog een onderwerp opgeven?'; $messages['nobodywarning'] = 'Dit bericht zonder inhoud versturen?'; $messages['notsentwarning'] = 'Bericht is niet verstuurd. Weet u zeker dat u het niet wilt bewaren?'; -$messages['noldapserver'] = 'Geef een LDAP adresboek server op om te doorzoeken'; -$messages['nocontactsreturned'] = 'Er zijn geen contactpersonen gevonden'; -$messages['nosearchname'] = 'Geef de naam of e-mail op van de contactpersoon'; +$messages['noldapserver'] = 'Geef een LDAP adresboek server op om te doorzoeken.'; +$messages['nosearchname'] = 'Geef de naam of e-mail op van de contactpersoon.'; $messages['notuploadedwarning'] = 'Nog niet alle bijlagen zijn geüpload. Wacht even of annuleer de upload.'; -$messages['searchsuccessful'] = '$nr berichten gevonden'; -$messages['searchnomatch'] = 'Zoekopdracht heeft geen resultaten opgeleverd'; +$messages['searchsuccessful'] = '$nr berichten gevonden.'; +$messages['contactsearchsuccessful'] = '$nr contactpersonen gevonden.'; +$messages['searchnomatch'] = 'Zoekopdracht heeft geen resultaten opgeleverd.'; $messages['searching'] = 'Zoeken...'; $messages['checking'] = 'Controleren...'; -$messages['nospellerrors'] = 'Geen spelfouten gevonden'; -$messages['folderdeleted'] = 'Map successvol verwijderd'; -$messages['foldersubscribed'] = 'Folder succesvol geabonneerd'; -$messages['folderunsubscribed'] = 'Folder succesvol uitgeschreven'; -$messages['folderpurged'] = 'Folder met succes geleegd'; -$messages['folderexpunged'] = 'Folder succesvol geleegd'; -$messages['deletedsuccessfully'] = 'Successvol verwijderd'; +$messages['nospellerrors'] = 'Geen spelfouten gevonden.'; +$messages['folderdeleted'] = 'Map successvol verwijderd.'; +$messages['foldersubscribed'] = 'Folder succesvol geabonneerd.'; +$messages['folderunsubscribed'] = 'Folder succesvol uitgeschreven.'; +$messages['folderpurged'] = 'Folder met succes geleegd.'; +$messages['folderexpunged'] = 'Folder succesvol geleegd.'; +$messages['deletedsuccessfully'] = 'Successvol verwijderd.'; $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 adressen succesvol gekopieerd'; -$messages['copyerror'] = 'Kan geen adressen kopiëren'; -$messages['sourceisreadonly'] = 'Het adres is alleen-lezen'; -$messages['errorsavingcontact'] = 'Kan het ontvanger-adres niet opslaan'; +$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 adressen succesvol gekopieerd.'; +$messages['copyerror'] = 'Kan geen adressen kopiëren.'; +$messages['sourceisreadonly'] = 'Het adres is alleen-lezen.'; +$messages['errorsavingcontact'] = 'Kan het ontvanger-adres niet opslaan.'; $messages['movingmessage'] = 'Bericht verplaatsen...'; $messages['copyingmessage'] = 'Kopiëren bericht...'; +$messages['copyingcontact'] = 'Kopiëren contactpersonen...'; $messages['deletingmessage'] = 'Verwijderen bericht(en)...'; $messages['markingmessage'] = 'Markeren bericht(en)...'; -$messages['receiptsent'] = 'Ontvangstbevestiging is verstuurd'; -$messages['errorsendingreceipt'] = 'Kan de ontvangstbevestiging niet versturen'; -$messages['nodeletelastidentity'] = 'U kunt uw enige identiteit niet verwijderen'; -$messages['forbiddencharacter'] = 'De naam van de map bevat een karakter dat niet is toegestaan'; -$messages['selectimportfile'] = 'Selecteer een bestand om de uploaden'; -$messages['addresswriterror'] = 'Het geselecteerde adresboek is alleen lezen'; -$messages['contactaddedtogroup'] = 'Contact(en) met succes toegevoegd aan de groep'; -$messages['contactremovedfromgroup'] = 'Contact(en) met succes verwijderd aan de groep'; +$messages['addingmember'] = 'Contactpersonen worden toegevoegd aan de groep...'; +$messages['removingmember'] = 'Contactpersonen worden verwijderd uit de groep...'; +$messages['receiptsent'] = 'Ontvangstbevestiging is verstuurd.'; +$messages['errorsendingreceipt'] = 'Kan de ontvangstbevestiging niet versturen.'; +$messages['nodeletelastidentity'] = 'U kunt uw enige identiteit niet verwijderen.'; +$messages['forbiddencharacter'] = 'De naam van de map bevat een karakter dat niet is toegestaan.'; +$messages['selectimportfile'] = 'Selecteer een bestand om de uploaden.'; +$messages['addresswriterror'] = 'Het geselecteerde adresboek is alleen lezen.'; +$messages['contactaddedtogroup'] = 'Contact(en) met succes toegevoegd aan de groep.'; +$messages['contactremovedfromgroup'] = 'Contact(en) met succes verwijderd aan de groep.'; $messages['importwait'] = 'Importeren, even geduld...'; $messages['importerror'] = 'Importeren mislukt! Het verstuurde bestand is geen geldig vCard bestand.'; $messages['importconfirm'] = '<b>Er zijn $inserted contactpersonen succesvol geïmporteerd, en $skipped bestaande overgeslagen</b>:<p><em>$names</em></p>'; $messages['importconfirmskipped'] = '<b>$skipped bestaande contactpersonen overgeslagen</b>'; $messages['opnotpermitted'] = 'Deze verrichting is niet toegestaan!'; -$messages['nofromaddress'] = 'Het e-mailadres mist in de geselecteerde identiteit'; +$messages['nofromaddress'] = 'Het e-mailadres mist in de geselecteerde identiteit.'; $messages['editorwarning'] = 'Door het overschakelen naar de platte tekst editor gaat alle opmaak verloren. Weet je zeker dat je verder wil gaan?'; $messages['httpreceivedencrypterror'] = 'Er is een fatale fout opgetreden. Neem direct contact op met uw systeembeheerder. <b>Uw bericht kon niet worden verzonden.</b>'; -$messages['smtpconnerror'] = 'SMTP Fout ($code): Verbinding met server mislukt'; -$messages['smtpautherror'] = 'SMTP Fout ($code): Autenticatie mislukt'; -$messages['smtpfromerror'] = 'SMTP Fout ($code): Kon afzender "$from" niet instellen ($msg)'; -$messages['smtptoerror'] = 'SMTP Fout ($code): Kon ontvanger "$to" niet toevoegen ($msg)'; -$messages['smtprecipientserror'] = 'SMTP Fout: Kon lijst van ontvangers niet verwerken'; -$messages['smtpdsnerror'] = 'SMTP Fout: Delivery Status Notifications worden niet ondersteund'; +$messages['smtpconnerror'] = 'SMTP Fout ($code): Verbinding met server mislukt.'; +$messages['smtpautherror'] = 'SMTP Fout ($code): Autenticatie mislukt.'; +$messages['smtpfromerror'] = 'SMTP Fout ($code): Kon afzender "$from" niet instellen ($msg).'; +$messages['smtptoerror'] = 'SMTP Fout ($code): Kon ontvanger "$to" niet toevoegen ($msg).'; +$messages['smtprecipientserror'] = 'SMTP Fout: Kon lijst van ontvangers niet verwerken.'; $messages['smtperror'] = 'SMTP Fout: $msg'; $messages['emailformaterror'] = 'Ongeldig e-mailadres: $email'; -$messages['toomanyrecipients'] = 'Te veel geadresseerden. Verminder de hoeveelheid geadresseerden tot $max'; -$messages['maxgroupmembersreached'] = 'Het aantal leden van de groep groter is dan de maximale van $max'; -$messages['internalerror'] = 'Er is een interne fout opgetreden. Probeer het nogmaals'; -$messages['contactdelerror'] = 'Kon contact(en) niet verwijderen'; -$messages['contactdeleted'] = 'Contact(en) succesvol verwijderd'; +$messages['toomanyrecipients'] = 'Te veel geadresseerden. Verminder de hoeveelheid geadresseerden tot $max.'; +$messages['maxgroupmembersreached'] = 'Het aantal leden van de groep groter is dan de maximale van $max.'; +$messages['internalerror'] = 'Er is een interne fout opgetreden. Probeer het nogmaals.'; +$messages['contactdelerror'] = 'Kon contact(en) niet verwijderen.'; +$messages['contactdeleted'] = 'Contact(en) succesvol verwijderd.'; $messages['contactrestoreerror'] = 'Verwijderde contactpersonen konden niet hersteld worden'; -$messages['contactrestored'] = 'Contactpersonen succesvol hersteld'; -$messages['groupdeleted'] = 'Groep succesvol verwijderd'; -$messages['grouprenamed'] = 'Groep succesvol hernoemd'; -$messages['groupcreated'] = 'Groep succesvol aangemaakt'; -$messages['messagedeleted'] = 'Bericht(en) succesvol verwijderd'; -$messages['messagemoved'] = 'Bericht(en) succesvol verplaatst'; -$messages['messagecopied'] = 'Bericht(en) succesvol gekopieerd'; -$messages['messagemarked'] = 'Bericht(en) succesvol gemarkeerd'; -$messages['autocompletechars'] = 'Voer ten minste $min karakters in voor automatisch aanvullen'; +$messages['contactrestored'] = 'Contactpersonen succesvol hersteld.'; +$messages['groupdeleted'] = 'Groep succesvol verwijderd.'; +$messages['grouprenamed'] = 'Groep succesvol hernoemd.'; +$messages['groupcreated'] = 'Groep succesvol aangemaakt.'; +$messages['savedsearchdeleted'] = 'Opgeslagen zoekopdracht successvol verwijderd.'; +$messages['savedsearchdeleteerror'] = 'Opgeslagen zoekopdracht kon niet worden verwijderd.'; +$messages['savedsearchcreated'] = 'Zoekopdracht successvol opgeslagen.'; +$messages['savedsearchcreateerror'] = 'Zoekopdracht kon niet worden opgeslagen.'; +$messages['messagedeleted'] = 'Bericht(en) succesvol verwijderd.'; +$messages['messagemoved'] = 'Bericht(en) succesvol verplaatst.'; +$messages['messagecopied'] = 'Bericht(en) succesvol gekopieerd.'; +$messages['messagemarked'] = 'Bericht(en) succesvol gemarkeerd.'; +$messages['autocompletechars'] = 'Voer ten minste $min karakters in voor automatisch aanvullen.'; +$messages['autocompletemore'] = 'Meerdere resultaten gevonden. Verfijn uw zoekopdracht.'; $messages['namecannotbeempty'] = 'Naam kan niet leeg zijn'; $messages['nametoolong'] = 'Naam is te lang'; $messages['folderupdated'] = 'Map succesvol bijgewerkt'; $messages['foldercreated'] = 'Map succesvol aangemaakt'; $messages['invalidimageformat'] = 'Geen geldig afbeeldings formaat'; $messages['mispellingsfound'] = 'Spelfouten gedetecteerd in bericht'; -$messages['itemsdeleted'] = '$num items zijn verwijderd'; +$messages['parentnotwritable'] = 'U heeft niet voldoende rechten een map te maken / verplaatsen in deze map.'; ?> diff --git a/program/localization/nn_NO/labels.inc b/program/localization/nn_NO/labels.inc index a4e6d31..9146517 100644 --- a/program/localization/nn_NO/labels.inc +++ b/program/localization/nn_NO/labels.inc @@ -14,7 +14,7 @@ | Update: Odin Omdal Hørthe <odin.omdal@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4410 2011-01-12 18:25:02Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ @@ -39,11 +39,11 @@ $labels['to'] = 'Mottakar'; $labels['cc'] = 'Kopi'; $labels['bcc'] = 'Blindkopi'; $labels['replyto'] = 'Svar-til'; +$labels['followupto'] = 'Oppfylging-til'; $labels['date'] = 'Dato'; $labels['size'] = 'Storleik'; $labels['priority'] = 'Prioritet'; $labels['organization'] = 'Organisasjon'; -$labels['reply-to'] = 'Svar-til'; $labels['mailboxlist'] = 'Katalogar'; $labels['messagesfromto'] = 'Meldingar $from til $to av $count'; $labels['threadsfromto'] = 'TrÃ¥dar $from til $to ($count stk)'; @@ -98,18 +98,18 @@ $labels['checkmail'] = 'SjÃ¥ etter nye meldingar'; $labels['writenewmessage'] = 'Skriv ei ny melding'; $labels['replytomessage'] = 'Svar pÃ¥ meldinga'; $labels['replytoallmessage'] = 'Svar til sendar og alle mottakarar'; +$labels['replyall'] = 'Svar til alle'; +$labels['replylist'] = 'Svar til liste'; +$labels['forwardinline'] = 'Send vidare innebygd'; +$labels['forwardattachment'] = 'Send vidare som vedlegg'; $labels['forwardmessage'] = 'Vidaresend meldinga'; $labels['deletemessage'] = 'Slett melding'; $labels['movemessagetotrash'] = 'Flytt melding til «sletta element»'; $labels['printmessage'] = 'Skriv ut meldinga'; $labels['previousmessage'] = 'Vis føregÃ¥ande melding'; -$labels['previousmessages'] = 'Vis føregÃ¥ande side med meldingar'; $labels['firstmessage'] = 'Vis den fyrste meldinga'; -$labels['firstmessages'] = 'Vis fyrste side med meldingar'; $labels['nextmessage'] = 'Vis den neste meldinga'; -$labels['nextmessages'] = 'Vis neste side med med meldingar'; $labels['lastmessage'] = 'Vis den siste meldinga'; -$labels['lastmessages'] = 'Vis den siste sida med meldingar'; $labels['backtolist'] = 'Tilbake til meldingslista'; $labels['viewsource'] = 'Vis kjelde'; $labels['markmessages'] = 'Marker meldingar'; @@ -117,7 +117,7 @@ $labels['markread'] = 'Som lese'; $labels['markunread'] = 'Som ulese'; $labels['markflagged'] = 'Som flagga'; $labels['markunflagged'] = 'Som uflagga'; -$labels['messageactions'] = 'Fleire handlingar...'; +$labels['moreactions'] = 'Fleire handlingar'; $labels['select'] = 'Vel'; $labels['all'] = 'Alle'; $labels['none'] = 'Ingen'; @@ -149,9 +149,9 @@ $labels['listcolumns'] = 'Vis kolonner'; $labels['listsorting'] = 'Sorteringskolonne'; $labels['listorder'] = 'Sorteringsveg'; $labels['listmode'] = 'Listevisningmodus'; +$labels['folderactions'] = 'Mappehandlingar'; $labels['compact'] = 'Kompakt'; $labels['empty'] = 'Tom'; -$labels['purge'] = 'Reinska opp'; $labels['quota'] = 'Plassbruk'; $labels['unknown'] = 'ukjend'; $labels['unlimited'] = 'ubegrensa'; @@ -169,12 +169,18 @@ $labels['addattachment'] = 'Legg ved ei fil'; $labels['charset'] = 'Teiknkoding'; $labels['editortype'] = 'Redigeringstype'; $labels['returnreceipt'] = 'Epost-er-lest-kvittering'; +$labels['dsn'] = 'Leveringsstatus'; +$labels['mailreplyintro'] = 'Den $date skreiv $sender:'; +$labels['originalmessage'] = 'Opphavleg melding'; +$labels['editidents'] = 'Redigere identitetar'; $labels['checkspelling'] = 'Stavekontroll'; -$labels['resumeediting'] = 'Fortsett redigering'; +$labels['resumeediting'] = 'Hald fram redigering'; $labels['revertto'] = 'Tilbakestill til'; $labels['attachments'] = 'Vedlegg'; $labels['upload'] = 'Last opp'; +$labels['uploadprogress'] = '$percent ($current frÃ¥ $total)'; $labels['close'] = 'Steng'; +$labels['messageoptions'] = 'Meldingsalternativ'; $labels['low'] = 'LÃ¥g'; $labels['lowest'] = 'LÃ¥gast'; $labels['normal'] = 'Normal'; @@ -191,6 +197,7 @@ $labels['maxuploadsize'] = 'Maksimalt tillatte storleik pÃ¥ filar er $size'; $labels['addcc'] = 'Legg til kopi'; $labels['addbcc'] = 'Legg til blindkopi'; $labels['addreplyto'] = 'Legg til svaradressa'; +$labels['addfollowupto'] = 'Legg til oppfylgjing'; $labels['mdnrequest'] = 'Sendaren av denne meldinga ynskjer Ã¥ fÃ¥ kvittering nÃ¥r du har lest meldinga. Ynskjer du Ã¥ senda denne kvitteringa?'; $labels['receiptread'] = 'Svarkvittering (eposten-er-lest-kvittering)'; $labels['yourmessage'] = 'Dette er ein retur-kvittering for meldinga di.'; @@ -198,13 +205,55 @@ $labels['receiptnote'] = 'Hugs: Denne kvitteringa seier berre at meldinga di var $labels['name'] = 'Visingsnamn'; $labels['firstname'] = 'Førenamn'; $labels['surname'] = 'Etternamn'; +$labels['middlename'] = 'Mellomnamn'; +$labels['nickname'] = 'Kallenamn'; +$labels['jobtitle'] = 'Jobbtittel'; +$labels['department'] = 'Avdeling'; +$labels['gender'] = 'Kjønn'; +$labels['maidenname'] = 'Pikenamn'; $labels['email'] = 'E-post'; +$labels['phone'] = 'Telefon'; +$labels['address'] = 'Adresse'; +$labels['street'] = 'Gate'; +$labels['locality'] = 'By'; +$labels['zipcode'] = 'Postnummer'; +$labels['country'] = 'Land'; +$labels['birthday'] = 'Fødselsdag'; +$labels['website'] = 'Internettside'; +$labels['notes'] = 'Notatar'; +$labels['male'] = 'Mann'; +$labels['female'] = 'Kvinne'; +$labels['assistant'] = 'Assistent'; +$labels['allfields'] = 'Alle felt'; +$labels['search'] = 'Søk'; +$labels['advsearch'] = 'Avansert søk'; +$labels['other'] = 'Andre'; +$labels['typehome'] = 'Heim'; +$labels['typework'] = 'Jobb'; +$labels['typeother'] = 'Andre'; +$labels['typemobile'] = 'Mobil'; +$labels['typemain'] = 'Hovud'; +$labels['typehomefax'] = 'Heimefax'; +$labels['typeworkfax'] = 'Jobbfax'; +$labels['typecar'] = 'Bil'; +$labels['typepager'] = 'Personsøkjar'; +$labels['typevideo'] = 'VIdeo'; +$labels['typeassistant'] = 'Assistent'; +$labels['typehomepage'] = 'Heimeside'; +$labels['typeblog'] = 'Blogg'; +$labels['typeprofile'] = 'Profil'; +$labels['addfield'] = 'Legg til felt...'; $labels['addcontact'] = 'Legg til ny kontakt'; $labels['editcontact'] = 'Redigere kontakt'; +$labels['contacts'] = 'Kontakter'; +$labels['personalinfo'] = 'Personleg informasjon'; $labels['edit'] = 'Redigere'; $labels['cancel'] = 'Avbryt'; $labels['save'] = 'Lagre'; $labels['delete'] = 'Slette'; +$labels['rename'] = 'Gi nytt namn'; +$labels['addphoto'] = 'Legg til'; +$labels['replacephoto'] = 'Erstatt'; $labels['newcontact'] = 'Opprett nytt kontaktkort'; $labels['deletecontact'] = 'Slett valde kontaktar'; $labels['composeto'] = 'Ny melding til'; @@ -213,7 +262,8 @@ $labels['print'] = 'Skriv ut'; $labels['export'] = 'Eksport'; $labels['exportvcards'] = 'Eksporter kontaktar i vCard-format'; $labels['newcontactgroup'] = 'Lag ny kontaktgruppe'; -$labels['groupactions'] = 'Handlingar for kontaktgruppar...'; +$labels['grouprename'] = 'Endre namn pÃ¥ gruppe'; +$labels['groupdelete'] = 'Slett gruppe'; $labels['previouspage'] = 'Førre side'; $labels['firstpage'] = 'Fyrste side'; $labels['nextpage'] = 'Neste side'; @@ -221,9 +271,12 @@ $labels['lastpage'] = 'Siste side'; $labels['group'] = 'Gruppe'; $labels['groups'] = 'Gruppar'; $labels['personaladrbook'] = 'Personlege adresser'; +$labels['searchsave'] = 'Lagre søk'; +$labels['searchdelete'] = 'Slett søk'; $labels['import'] = 'Importer'; $labels['importcontacts'] = 'Importer kontaktar'; $labels['importfromfile'] = 'Importer frÃ¥ fil:'; +$labels['importtarget'] = 'Legg til kontakter i adresseboka'; $labels['importreplace'] = 'Byt ut heile adresseboka'; $labels['importtext'] = 'Du kan lasta opp kontaktar frÃ¥ ei eksisterande adressebok.Me stør innlasting frÃ¥ vCard-formatet.'; $labels['done'] = 'Ferdig'; @@ -239,6 +292,8 @@ $labels['edititem'] = 'Redigere element'; $labels['preferhtml'] = 'Føretrekk HTML'; $labels['defaultcharset'] = 'Standard karaktersett (charset)'; $labels['htmlmessage'] = 'HTML-melding'; +$labels['dateformat'] = 'Datoformat'; +$labels['timeformat'] = 'Tidsformat'; $labels['prettydate'] = 'Pene datoar'; $labels['setdefault'] = 'Set som standard'; $labels['autodetect'] = 'Automatisk'; @@ -312,9 +367,16 @@ $labels['create'] = 'Opprette'; $labels['createfolder'] = 'Opprett ny mappe'; $labels['managefolders'] = 'Mappehandsaming'; $labels['specialfolders'] = 'Spesialmapper'; +$labels['getfoldersize'] = 'Klikk for Ã¥ fÃ¥ mappestørrelse'; +$labels['changesubscription'] = 'Klikk for Ã¥ endre abonnement'; +$labels['foldertype'] = 'Mappetype'; +$labels['personalfolder'] = 'Privat mappe'; +$labels['otherfolder'] = 'Annan brukar si mappe'; +$labels['sharedfolder'] = 'Offentleg mappe'; $labels['sortby'] = 'Sorter etter'; $labels['sortasc'] = 'Sorter stigande'; $labels['sortdesc'] = 'Sorter søkkjande'; +$labels['undo'] = 'Gjer om'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/pl_PL/labels.inc b/program/localization/pl_PL/labels.inc index 85cb94d..ed3c4c4 100644 --- a/program/localization/pl_PL/labels.inc +++ b/program/localization/pl_PL/labels.inc @@ -18,7 +18,7 @@ | Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5165 2011-09-05 08:49:04Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -38,8 +38,8 @@ $labels['sent'] = 'WysÅane'; $labels['trash'] = 'Kosz'; $labels['junk'] = 'Spam'; $labels['subject'] = 'Temat'; -$labels['from'] = 'Nadawca'; -$labels['to'] = 'Odbiorca'; +$labels['from'] = 'Od'; +$labels['to'] = 'Do'; $labels['cc'] = 'Kopia'; $labels['bcc'] = 'Ukryta kopia'; $labels['replyto'] = 'Odpowiedź do'; @@ -137,7 +137,7 @@ $labels['threaded'] = 'PowÄ tkowane'; $labels['autoexpand_threads'] = 'Rozwijaj wÄ tki'; $labels['do_expand'] = 'wszystkie'; $labels['expand_only_unread'] = 'tylko nieprzeczytane'; -$labels['fromto'] = 'Nadawca/Odbiorca'; +$labels['fromto'] = 'Od/Do'; $labels['flag'] = 'Flaga'; $labels['attachment'] = 'ZaÅÄ cznik'; $labels['nonesort'] = 'Brak'; @@ -419,5 +419,27 @@ $labels['importtarget'] = 'Dodaj nowe kontakty do ksiÄ Å¼ki adresowej:'; $labels['grouprename'] = 'ZmieÅ nazwÄ grupy'; $labels['groupdelete'] = 'UsuÅ grupÄ'; $labels['undo'] = 'Cofnij'; +$labels['mailreplyintro'] = 'W dniu $date, $sender napisaÅ(a):'; +$labels['uploadprogress'] = '$percent ($current z $total)'; +$labels['originalmessage'] = 'WiadomoÅÄ oryginalna'; +$labels['moreactions'] = 'WiÄcej akcji...'; +$labels['searchsave'] = 'Zapisz wyszukiwanie'; +$labels['searchdelete'] = 'UsuÅ wyszukiwanie'; +$labels['spellcheckoptions'] = 'Opcje sprawdzania pisowni'; +$labels['spellcheckignoresyms'] = 'Ignoruj sÅowa zawierajÄ ce symbole'; +$labels['spellcheckignorenums'] = 'Ignoruj sÅowa zawierajÄ ce cyfry'; +$labels['spellcheckignorecaps'] = 'Ignoruj sÅowa pisane wielkimi literami'; +$labels['addtodict'] = 'Dodaj do sÅownika'; +$labels['dateformat'] = 'Format daty'; +$labels['timeformat'] = 'Format czasu'; +$labels['isdraft'] = 'To jest kopia robocza wiadomoÅci.'; +$labels['autocompletesingle'] = 'Nie pokazuj alternatywnych adresów przy autouzupeÅnianiu'; +$labels['plugin'] = 'Wtyczka'; +$labels['version'] = 'Wersja'; +$labels['source'] = 'ŹródÅa'; +$labels['license'] = 'Licencja'; +$labels['about'] = 'O programie'; +$labels['support'] = 'Wsparcie techniczne'; +$labels['defaultfont'] = 'Czcionka wiadomoÅci HTML'; ?> diff --git a/program/localization/pl_PL/messages.inc b/program/localization/pl_PL/messages.inc index 6593a80..6a509a6 100644 --- a/program/localization/pl_PL/messages.inc +++ b/program/localization/pl_PL/messages.inc @@ -18,7 +18,7 @@ | Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5003 2011-08-02 09:22:02Z alec $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -117,7 +117,6 @@ $messages['smtpautherror'] = 'BÅÄ d SMTP ($code): Uwierzytelnianie nie powiodÅ $messages['smtpfromerror'] = 'BÅÄ d SMTP ($code): Nie można ustawiÄ nadawcy "$from" ($msg).'; $messages['smtptoerror'] = 'BÅÄ d SMTP ($code): Nie można dodaÄ odbiorcy "$to" ($msg).'; $messages['smtprecipientserror'] = 'BÅÄ d SMTP: Parsowanie listy odbiorców nie powiodÅo siÄ.'; -$messages['smtpdsnerror'] = 'BÅÄ d SMTP: Statusy dostarczenia (DSN) nie sÄ obsÅugiwane przez serwer.'; $messages['smtperror'] = 'BÅÄ d SMTP: $msg'; $messages['emailformaterror'] = 'BÅÄdny adres e-mail: $email'; $messages['toomanyrecipients'] = 'Zbyt wielu odbiorców. Zmniejsz ich liczbÄ do $max.'; @@ -150,5 +149,20 @@ $messages['invalidimageformat'] = 'Niepoprawny format obrazka.'; $messages['mispellingsfound'] = 'Wykryto bÅÄdy pisowni w tej wiadomoÅci.'; $messages['contactrestoreerror'] = 'Przywracanie kontaktów nie powiodÅo siÄ.'; $messages['contactrestored'] = 'Kontakt(y) zostaÅy przywrócone.'; +$messages['dberror'] = 'BÅÄ d bazy danych!'; +$messages['contactnameexists'] = 'Kontakt z podanÄ nazwÄ już istnieje!'; +$messages['copyingcontact'] = 'Kopiowanie kontaktów...'; +$messages['addingmember'] = 'Dodawanie kontaktów do grupy...'; +$messages['removingmember'] = 'Usuwanie kontaktów z grupy...'; +$messages['parentnotwritable'] = 'Nie można utworzyÄ/przenieÅÄ folderu w wybrane miejsce. Brak upranieÅ.'; +$messages['contactsearchsuccessful'] = 'Znaleziono $nr kontaktów.'; +$messages['savedsearchdeleted'] = 'Wyszukiwanie usuniÄto pomyÅlnie.'; +$messages['savedsearchdeleteerror'] = 'Nie można usunÄ Ä wyszukiwania.'; +$messages['savedsearchcreated'] = 'Wyszukiwanie zapisano pomyÅlnie.'; +$messages['savedsearchcreateerror'] = 'Nie można zapisaÄ wyszukiwania.'; +$messages['contactsearchonly'] = 'Użyj wyszukiwarki aby wyÅwietliÄ kontakty.'; +$messages['contactdeleting'] = 'Usuwanie kontaktów...'; +$messages['autocompletemore'] = 'Znaleziono wiÄcej pasujÄ cych wpisów. Wprowadź wiÄcej znaków.'; +$messages['messagetoobig'] = 'Ta czÄÅÄ wiadomoÅci jest zbyt duża aby jÄ przetworzyÄ.'; ?> diff --git a/program/localization/pt_BR/labels.inc b/program/localization/pt_BR/labels.inc index 0255286..6a2d9db 100644 --- a/program/localization/pt_BR/labels.inc +++ b/program/localization/pt_BR/labels.inc @@ -18,7 +18,7 @@ | Jarbas Peixoto Junior <jarbas.peixoto@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5326 2011-10-10 09:39:58Z netbit $ */ @@ -122,7 +122,7 @@ $labels['markread'] = 'como lidas'; $labels['markunread'] = 'como não lidas'; $labels['markflagged'] = 'como sinalizadas'; $labels['markunflagged'] = 'como não sinalizadas'; -$labels['messageactions'] = 'Mais ações...'; +$labels['moreactions'] = 'Mais ações...'; $labels['select'] = 'Selecionar'; $labels['all'] = 'Todas'; $labels['none'] = 'Nenhuma'; @@ -175,6 +175,8 @@ $labels['charset'] = 'Codificação'; $labels['editortype'] = 'Tipo de editor'; $labels['returnreceipt'] = 'Solicitar confirmação de recebimento'; $labels['dsn'] = 'Recibo de entrega'; +$labels['mailreplyintro'] = 'Em $date, $sender escreveu:'; +$labels['originalmessage'] = 'Mensagem original'; $labels['editidents'] = 'Editar identidades'; $labels['checkspelling'] = 'Verificar ortografia'; $labels['resumeediting'] = 'Continuar a edição'; @@ -222,7 +224,7 @@ $labels['address'] = 'Endereço'; $labels['street'] = 'Rua'; $labels['locality'] = 'Cidade'; $labels['zipcode'] = 'CEP'; -$labels['region'] = 'Região'; +$labels['region'] = 'Estado'; $labels['country'] = 'PaÃs'; $labels['birthday'] = 'Nascimento'; $labels['anniversary'] = 'Aniversário'; @@ -249,6 +251,9 @@ $labels['typecar'] = 'Carro'; $labels['typepager'] = 'Pager'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Assistente'; +$labels['typehomepage'] = 'Página pessoal'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Perfil'; $labels['addfield'] = 'Adicionar campo...'; $labels['addcontact'] = 'Incluir novo contato'; $labels['editcontact'] = 'Editar contato'; @@ -270,7 +275,6 @@ $labels['print'] = 'Imprimir'; $labels['export'] = 'Exportar'; $labels['exportvcards'] = 'Exportar os contatos em formato vCard'; $labels['newcontactgroup'] = 'Criar novo grupo de contatos'; -$labels['groupactions'] = 'Ações para grupos de contatos...'; $labels['grouprename'] = 'Renomear grupo'; $labels['groupdelete'] = 'Excluir grupo'; $labels['previouspage'] = 'Página Anterior'; @@ -280,6 +284,8 @@ $labels['lastpage'] = 'Ãltima Página'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; $labels['personaladrbook'] = 'Endereços pessoais'; +$labels['searchsave'] = 'Salvar pesquisa'; +$labels['searchdelete'] = 'Excluir pesquisa'; $labels['import'] = 'Importar'; $labels['importcontacts'] = 'Importar contatos'; $labels['importfromfile'] = 'Importar de arquivo:'; @@ -299,6 +305,8 @@ $labels['edititem'] = 'Editar item'; $labels['preferhtml'] = 'Exibir formatação HTML em mensagens'; $labels['defaultcharset'] = 'Conjunto padrão de caracteres'; $labels['htmlmessage'] = 'Mensagem HTML'; +$labels['dateformat'] = 'Formato da data'; +$labels['timeformat'] = 'Formato da hora'; $labels['prettydate'] = 'Exibir datas amigáveis'; $labels['setdefault'] = 'Padrão'; $labels['autodetect'] = 'Automático'; @@ -371,6 +379,11 @@ $labels['reqdsn'] = 'Sempre pedir confirmação de entrega'; $labels['replysamefolder'] = 'Guardar as respostas na mesma pasta da mensagem original'; $labels['defaultaddressbook'] = 'Adicionar novos contatos para o catálogo de endereços:'; $labels['spellcheckbeforesend'] = 'Verificar ortografia antes de enviar uma mensagem'; +$labels['spellcheckoptions'] = 'Opções do Verificador de Ortografia'; +$labels['spellcheckignoresyms'] = 'Ignorar palavras com sÃmbolos'; +$labels['spellcheckignorenums'] = 'Ignorar palavras com números'; +$labels['spellcheckignorecaps'] = 'Ignorar palavras em maiúsculo'; +$labels['addtodict'] = 'Adicionar ao dicionário'; $labels['folder'] = 'Pasta'; $labels['folders'] = 'Pastas'; $labels['foldername'] = 'Nome da pasta'; diff --git a/program/localization/pt_BR/messages.inc b/program/localization/pt_BR/messages.inc index f0c9907..5f2df76 100644 --- a/program/localization/pt_BR/messages.inc +++ b/program/localization/pt_BR/messages.inc @@ -18,7 +18,7 @@ | Jarbas Peixoto Junior <jarbas.peixoto@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5326 2011-10-10 09:39:58Z netbit $ */ @@ -29,7 +29,7 @@ $messages['sessionerror'] = 'A sessão do seu navegador é inválida ou expirou' $messages['imaperror'] = 'Falha na conexão com o servidor IMAP'; $messages['servererror'] = 'Erro no Servidor!'; $messages['servererrormsg'] = 'Erro no Servidor: $msg'; -$messages['databaserror'] = 'Erro no banco de dados!'; +$messages['dberror'] = 'Erro no banco de dados!'; $messages['errorreadonly'] = 'Não foi possÃvel realizar a operação. Pasta somente leitura'; $messages['errornoperm'] = 'Não foi possÃvel realizar a operação. Acesso negado'; $messages['invalidrequest'] = 'Requisição inválida! Nenhum dado foi salvo.'; @@ -46,24 +46,29 @@ $messages['messagesent'] = 'Mensagem enviada com sucesso'; $messages['savingmessage'] = 'Salvando Mensagem...'; $messages['messagesaved'] = 'Mensagem gravada como rascunho'; $messages['successfullysaved'] = 'Gravado com sucesso'; -$messages['addedsuccessfully'] = 'Contato incluÃdo com sucesso'; -$messages['contactexists'] = 'Já existe um contato com esse e-mail'; -$messages['blockedimages'] = 'Para proteger sua privacidade, as imagens desta mensagem foram bloqueadas'; +$messages['addedsuccessfully'] = 'Contato incluÃdo com sucesso.'; +$messages['contactexists'] = 'Já existe um contato com esse mesmo e-mail.'; +$messages['contactnameexists'] = 'Já existe um contato com o mesmo nome.'; +$messages['blockedimages'] = 'Para proteger sua privacidade, as imagens desta mensagem foram bloqueadas.'; $messages['encryptedmessage'] = 'Esta mensagem está criptografada e não pode ser exibida. Desculpe.'; -$messages['nocontactsfound'] = 'Nenhum contato foi encontrado'; -$messages['contactnotfound'] = 'O contato solicitado não foi encontrado'; -$messages['sendingfailed'] = 'Falha no envio da mensagem'; -$messages['senttooquickly'] = 'Aguarde $sec s para enviar a mensagem'; -$messages['errorsavingsent'] = 'Ocorreu um erro ao salvar a mensagem enviada'; -$messages['errorsaving'] = 'Ocorreu um erro ao salvar'; -$messages['errormoving'] = 'Não foi possÃvel mover a mensagem'; -$messages['errorcopying'] = 'Não foi possÃvel copiar a(s) mensagem(ns)'; -$messages['errordeleting'] = 'Não foi possÃvel apagar a mensagem'; -$messages['errormarking'] = 'Não foi possÃvel marcar a mensagem'; +$messages['nocontactsfound'] = 'Nenhum contato foi encontrado.'; +$messages['contactnotfound'] = 'O contato solicitado não foi encontrado.'; +$messages['contactsearchonly'] = 'Informe os termos de pesquisa para localizar os contatos'; +$messages['sendingfailed'] = 'Falha no envio da mensagem.'; +$messages['senttooquickly'] = 'Aguarde $sec s para enviar a mensagem.'; +$messages['errorsavingsent'] = 'Ocorreu um erro ao salvar a mensagem enviada.'; +$messages['errorsaving'] = 'Ocorreu um erro ao salvar.'; +$messages['errormoving'] = 'Não foi possÃvel mover a mensagem.'; +$messages['errorcopying'] = 'Não foi possÃvel copiar a(s) mensagem(ns).'; +$messages['errordeleting'] = 'Não foi possÃvel apagar a mensagem.'; +$messages['errormarking'] = 'Não foi possÃvel marcar a mensagem.'; $messages['deletecontactconfirm'] = 'Deseja realmente excluir o(s) contato(s) selecionado(s)?'; +$messages['deletegroupconfirm'] = 'Deseja realmente excluir o grupo selecionado?'; $messages['deletemessagesconfirm'] = 'Deseja realmente excluir a(s) mensagem(s) selecionada(s)?'; $messages['deletefolderconfirm'] = 'Deseja realmente excluir esta pasta?'; $messages['purgefolderconfirm'] = 'Deseja realmente excluir todas mensagens desta pasta?'; +$messages['contactdeleting'] = 'Apagando contato(s)...'; +$messages['groupdeleting'] = 'Excluindo grupo...'; $messages['folderdeleting'] = 'Apagando pasta...'; $messages['foldermoving'] = 'Movendo pasta...'; $messages['foldersubscribing'] = 'Ativando pasta...'; @@ -78,10 +83,10 @@ $messages['nosubjectwarning'] = 'O campo "Assunto" não foi preenchido. Deseja i $messages['nobodywarning'] = 'Enviar a mensagem sem texto?'; $messages['notsentwarning'] = 'A mensagem não foi enviada, deseja excluÃ-la?'; $messages['noldapserver'] = 'Por favor, selecione um servidor LDAP para a pesquisa'; -$messages['nocontactsreturned'] = 'Nenhum contato foi encontrado'; $messages['nosearchname'] = 'Por favor, informe o nome do contado ou seu endereço de e-mail'; $messages['notuploadedwarning'] = 'Há anexos ainda não enviados. Aguarde ou cancele o envio.'; -$messages['searchsuccessful'] = '$nr mensagens encontradas'; +$messages['searchsuccessful'] = '$nr mensagens encontradas.'; +$messages['contactsearchsuccessful'] = '$nr contatos encontrados.'; $messages['searchnomatch'] = 'A pesquisa não encontrou resultados'; $messages['searching'] = 'Pesquisando...'; $messages['checking'] = 'Verificando...'; @@ -102,8 +107,11 @@ $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...'; $messages['copyingmessage'] = 'Copiando mensagem...'; +$messages['copyingcontact'] = 'Copiando contato(s)...'; $messages['deletingmessage'] = 'Excluindo mensagem(s)...'; $messages['markingmessage'] = 'Marcando mensagem(s)...'; +$messages['addingmember'] = 'Adicionando contato(s) para o grupo...'; +$messages['removingmember'] = 'Removendo contato(s) do grupo...'; $messages['receiptsent'] = 'Confirmação de recebimento enviada com sucesso'; $messages['errorsendingreceipt'] = 'Não foi possÃvel enviar a confirmação de recebimento'; $messages['nodeletelastidentity'] = 'Você não pode excluir a única identidade'; @@ -125,7 +133,6 @@ $messages['smtpautherror'] = 'Erro SMTP ($code): Falha na autenticação'; $messages['smtpfromerror'] = 'Erro SMTP ($code): Falha ao definir o remetente "$from" ($msg)'; $messages['smtptoerror'] = 'Erro SMTP ($code): Falha ao adicionar o destinatário "$to" ($msg)'; $messages['smtprecipientserror'] = 'Erro SMTP: Não é possÃvel processar a lista destinatários'; -$messages['smtpdsnerror'] = 'Erro SMTP: Sem suporte para Confirmação de Entrega (DSN)'; $messages['smtperror'] = 'Erro SMTP: $msg'; $messages['emailformaterror'] = 'Endereço de e-mail inválido: $email'; $messages['toomanyrecipients'] = 'Muitos destinatários. Reduza o número de destinatários para $max.'; @@ -138,16 +145,22 @@ $messages['contactrestored'] = 'Contato(s) recuperado(s) com sucesso.'; $messages['groupdeleted'] = 'Grupo excluÃdo com sucesso'; $messages['grouprenamed'] = 'Grupo renomeado com sucesso'; $messages['groupcreated'] = 'Grupo criado com sucesso'; +$messages['savedsearchdeleted'] = 'Pesquisa excluÃda com sucesso.'; +$messages['savedsearchdeleteerror'] = 'Não foi possÃvel excluir a pesquisa.'; +$messages['savedsearchcreated'] = 'Pesquisa criada com sucesso.'; +$messages['savedsearchcreateerror'] = 'Não foi possÃvel criar a pesquisa.'; $messages['messagedeleted'] = 'Mensagem(s) excluÃda(s) com sucesso'; $messages['messagemoved'] = 'Mensagem(s) movida(s) com sucesso'; $messages['messagecopied'] = 'Mensagem(s) copiada(s) com sucesso'; $messages['messagemarked'] = 'Mensagem(s) marcada(s) com sucesso'; $messages['autocompletechars'] = 'Digite pelo menos $min caractere(s) para auto-completar'; +$messages['autocompletemore'] = 'Muitos registros encontrados. Por favor, digite mais caracteres.'; $messages['namecannotbeempty'] = 'Nome não pode ser vazio'; $messages['nametoolong'] = 'Nome é muito longo'; $messages['folderupdated'] = 'Pasta atualizada com sucesso'; $messages['foldercreated'] = 'Pasta criada com sucesso'; $messages['invalidimageformat'] = 'Formato de imagem inválido.'; $messages['mispellingsfound'] = 'Foram detectados erros de ortografia.'; +$messages['parentnotwritable'] = 'Sem permissão para criar/mover a pasta dentro da pasta selecionada.'; ?> diff --git a/program/localization/pt_PT/labels.inc b/program/localization/pt_PT/labels.inc index 9c047dd..e864c65 100644 --- a/program/localization/pt_PT/labels.inc +++ b/program/localization/pt_PT/labels.inc @@ -17,7 +17,7 @@ | Teotónio Ricardo <teotonio.ricardo@webtuga.pt> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -121,7 +121,7 @@ $labels['markread'] = 'Como lidas'; $labels['markunread'] = 'Como não lidas'; $labels['markflagged'] = 'Com sinalização'; $labels['markunflagged'] = 'Sem sinalização'; -$labels['messageactions'] = 'Mais acções...'; +$labels['moreactions'] = 'Mais acções...'; $labels['select'] = 'Seleccionar'; $labels['all'] = 'Todas'; $labels['none'] = 'Nenhuma'; @@ -193,6 +193,7 @@ $labels['highest'] = 'Mais alta'; $labels['nosubject'] = '(sem assunto)'; $labels['showimages'] = 'Exibir imagens'; $labels['alwaysshow'] = 'Mostrar sempre imagens a partir de $sender'; +$labels['isdraft'] = 'Esta é uma mensagem de rascunho.'; $labels['htmltoggle'] = 'HTML'; $labels['plaintoggle'] = 'Texto simples'; $labels['savesentmessagein'] = 'Guardar mensagem enviada em'; @@ -274,7 +275,6 @@ $labels['print'] = 'Imprimir'; $labels['export'] = 'Exportar'; $labels['exportvcards'] = 'Exportar contactos no formato vCard'; $labels['newcontactgroup'] = 'Criar novo grupo de contactos'; -$labels['groupactions'] = 'Acções para grupo de contactos...'; $labels['grouprename'] = 'Renomear grupo'; $labels['groupdelete'] = 'Eliminar grupo'; $labels['previouspage'] = 'Exibir página anterior'; @@ -284,6 +284,8 @@ $labels['lastpage'] = 'Exibir última página'; $labels['group'] = 'Grupo'; $labels['groups'] = 'Grupos'; $labels['personaladrbook'] = 'Endereços pessoais'; +$labels['searchsave'] = 'Guardar pesquisa'; +$labels['searchdelete'] = 'Eliminar pesquisa'; $labels['import'] = 'Importar'; $labels['importcontacts'] = 'Importar contactos'; $labels['importfromfile'] = 'Importar do ficheiro:'; @@ -292,6 +294,7 @@ $labels['importreplace'] = 'Substituir todo o livro de endereços'; $labels['importtext'] = 'Pode submeter contactos a partir de um livro de endereços. Actualmente suportamos importação de endereços no formato vCard.'; $labels['done'] = 'Terminado'; $labels['settingsfor'] = 'Configurações para'; +$labels['about'] = 'Acerca'; $labels['preferences'] = 'Preferências'; $labels['userpreferences'] = 'Preferências do utilizador'; $labels['editpreferences'] = 'Editar preferências do utilizador'; @@ -303,6 +306,8 @@ $labels['edititem'] = 'Editar item'; $labels['preferhtml'] = 'Exibir mensagens em HTML'; $labels['defaultcharset'] = 'Conjunto de caracteres predefinido'; $labels['htmlmessage'] = 'Mensagem em HTML'; +$labels['dateformat'] = 'Formato da data'; +$labels['timeformat'] = 'Formato da hora'; $labels['prettydate'] = 'Formatar datas'; $labels['setdefault'] = 'Marcar como predefinido'; $labels['autodetect'] = 'Auto'; @@ -374,7 +379,13 @@ $labels['reqmdn'] = 'Pedir sempre um recibo de leitura'; $labels['reqdsn'] = 'Pedir sempre um recibo de entrega'; $labels['replysamefolder'] = 'Guardar as respostas na mesma pasta da mensagem original'; $labels['defaultaddressbook'] = 'Adicionar novo contacto ao livro de endereços selecionado'; +$labels['autocompletesingle'] = 'Ignorar endereços de email alternativos no preenchimento automático'; $labels['spellcheckbeforesend'] = 'Verificar ortografia antes de enviar a mensagem'; +$labels['spellcheckoptions'] = 'Opções de verificação ortográfica'; +$labels['spellcheckignoresyms'] = 'Ignorar palavras com sÃmbolos'; +$labels['spellcheckignorenums'] = 'Ignorar palavras com números'; +$labels['spellcheckignorecaps'] = 'Ignorar palavras em maiúsculas'; +$labels['addtodict'] = 'Adicionar ao dicionário'; $labels['folder'] = 'Pasta'; $labels['folders'] = 'Pastas'; $labels['foldername'] = 'Nome da pasta'; @@ -399,6 +410,11 @@ $labels['sortby'] = 'Ordenar por'; $labels['sortasc'] = 'Ordenação Ascendente'; $labels['sortdesc'] = 'Ordenação Descendente'; $labels['undo'] = 'Anular'; +$labels['plugin'] = 'Plugin'; +$labels['version'] = 'Versão'; +$labels['source'] = 'Fonte'; +$labels['license'] = 'Licença'; +$labels['support'] = 'Obter suporte'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/pt_PT/messages.inc b/program/localization/pt_PT/messages.inc index 65bea81..ccf8791 100644 --- a/program/localization/pt_PT/messages.inc +++ b/program/localization/pt_PT/messages.inc @@ -12,11 +12,11 @@ +-----------------------------------------------------------------------+ | Authors: Sergio Rocha <sergio.rocha@makeitsimple.pt> | | João Vale <jpvale@gmail.com> | -| Nuno Costa <nuno@criacaoweb.net> | -| Teotónio Ricardo <teotonio.ricardo@webtuga.pt> | +| Nuno Costa <nuno@criacaoweb.net> | +| Teotónio Ricardo <teotonio.ricardo@webtuga.pt> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -27,7 +27,7 @@ $messages['sessionerror'] = 'A sua sessão é inválida ou expirou'; $messages['imaperror'] = 'A ligação ao servidor IMAP falhou'; $messages['servererror'] = 'Erro do Servidor!'; $messages['servererrormsg'] = 'Erro do Servidor: $msg'; -$messages['databaserror'] = 'Erro de base de dados!'; +$messages['dberror'] = 'Erro na base de dados!'; $messages['errorreadonly'] = 'Não foi possÃvel efectuar a operação. A pasta é só de leitura.'; $messages['errornoperm'] = 'Não tem permissões para efectuar esta operação.'; $messages['invalidrequest'] = 'Pedido inválido! Não foi guardada nenhuma informação.'; @@ -51,6 +51,7 @@ $messages['blockedimages'] = 'Para proteger a sua privacidade, as imagens desta $messages['encryptedmessage'] = 'Esta mensagem está encriptada e não pode ser exibida. Desculpe.'; $messages['nocontactsfound'] = 'Nenhum contacto encontrado'; $messages['contactnotfound'] = 'O contacto especificado não foi encontrado'; +$messages['contactsearchonly'] = 'Insira os termos de pesquisa para localizar os contactos'; $messages['sendingfailed'] = 'Falha no envio da mensagem'; $messages['senttooquickly'] = 'Por favor espere $sec seg(s). antes de enviar esta mensagem'; $messages['errorsavingsent'] = 'Ocorreu um erro ao guardar a mensagem enviada'; @@ -64,6 +65,7 @@ $messages['deletegroupconfirm'] = 'Tem a certeza que pretende eliminar o grupo s $messages['deletemessagesconfirm'] = 'Deseja realmente eliminar a(s) mensagem(ns) selecionada(s)?'; $messages['deletefolderconfirm'] = 'Deseja realmente eliminar esta pasta?'; $messages['purgefolderconfirm'] = 'Deseja realmente eliminar todas mensagens desta pasta?'; +$messages['contactdeleting'] = 'A eliminar contacto(s)...'; $messages['groupdeleting'] = 'A eliminar grupo...'; $messages['folderdeleting'] = 'A eliminar pasta...'; $messages['foldermoving'] = 'A mover pasta...'; @@ -79,10 +81,10 @@ $messages['nosubjectwarning'] = 'O campo "Assunto" não foi preenchido. Deseja i $messages['nobodywarning'] = 'Enviar a mensagem sem texto?'; $messages['notsentwarning'] = 'A mensagem não foi enviada, deseja apagá-la?'; $messages['noldapserver'] = 'Seleccione um servidor LDAP para a pesquisa'; -$messages['nocontactsreturned'] = 'Não foi encontrado nenhum contacto'; $messages['nosearchname'] = 'Por favor, escreva o nome do contacto ou endereço de e-mail'; $messages['notuploadedwarning'] = 'Nem todos os anexos foram ainda enviados. Por favor aguarde ou cancele o envio.'; $messages['searchsuccessful'] = '$nr mensagens encontradas'; +$messages['contactsearchsuccessful'] = '$nr contactos encontrados.'; $messages['searchnomatch'] = 'A pesquisa não devolveu resultados'; $messages['searching'] = 'A pesquisar...'; $messages['checking'] = 'A verificar...'; @@ -129,7 +131,6 @@ $messages['smtpautherror'] = 'Erro SMTP ($code): A autenticação falhou'; $messages['smtpfromerror'] = 'Erro SMTP ($code): Falha ao definir o remetente "$from" ($msg)'; $messages['smtptoerror'] = 'Erro SMTP ($code): Falha ao adicionar o destinatário: "$to" ($msg)'; $messages['smtprecipientserror'] = 'Erro SMTP: ImpossÃvel analisar a lista de destinatários'; -$messages['smtpdsnerror'] = 'Erro SMTP: Não há suporte para recibo de entrega'; $messages['smtperror'] = 'Erro SMTP: $msg'; $messages['emailformaterror'] = 'Endereço de e-mail incorrecto: $email'; $messages['toomanyrecipients'] = 'Demasiados destinatários. Reduza o numero de destinatários para o máximo de $max.'; @@ -142,11 +143,16 @@ $messages['contactrestored'] = 'Contacto(s) restaurado(s) com sucesso.'; $messages['groupdeleted'] = 'Grupo eliminado com sucesso'; $messages['grouprenamed'] = 'Grupo renomeado com sucesso'; $messages['groupcreated'] = 'Grupo criado com sucesso'; +$messages['savedsearchdeleted'] = 'Pesquisa guardada eliminada com sucesso.'; +$messages['savedsearchdeleteerror'] = 'Não foi possÃvel eliminar a pesquisa guardada.'; +$messages['savedsearchcreated'] = 'Pesquisa guardada criada com sucesso.'; +$messages['savedsearchcreateerror'] = 'Não foi possÃvel criar a pesquisa guardada.'; $messages['messagedeleted'] = 'Mensagens eliminadas com sucesso'; $messages['messagemoved'] = 'Mensagens movidas com sucesso'; $messages['messagecopied'] = 'Mensagens copiadas com sucesso'; $messages['messagemarked'] = 'Mensagens marcadas com sucesso'; $messages['autocompletechars'] = 'Indique pelo menos $min caracteres para auto completar'; +$messages['autocompletemore'] = 'Muitos registros encontrados. Por favor, insira mais caracteres.'; $messages['namecannotbeempty'] = 'O nome não pode estar em branco'; $messages['nametoolong'] = 'O nome é demasiado longo'; $messages['folderupdated'] = 'Actualização da pasta concluÃda com sucesso'; @@ -154,5 +160,6 @@ $messages['foldercreated'] = 'Pasta criada com sucesso'; $messages['invalidimageformat'] = 'Formato de imagem não suportado'; $messages['mispellingsfound'] = 'Foram detectados erros de ortografia nesta mensagem'; $messages['parentnotwritable'] = 'Não é possÃvel criar/mover esta pasta para a pasta seleccionada. Acesso negado.'; +$messages['messagetoobig'] = 'A mensagem é demasiado grande para ser processada.'; ?> diff --git a/program/localization/ru_RU/labels.inc b/program/localization/ru_RU/labels.inc index d4649c2..a89e530 100644 --- a/program/localization/ru_RU/labels.inc +++ b/program/localization/ru_RU/labels.inc @@ -15,7 +15,7 @@ | Support: www.roundcube.ru | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/ru_RU/messages.inc b/program/localization/ru_RU/messages.inc index c6b2aab..52e8484 100644 --- a/program/localization/ru_RU/messages.inc +++ b/program/localization/ru_RU/messages.inc @@ -14,7 +14,7 @@ | Updates: Sergey Dukachev <iam@dukess.ru> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: messages.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/sk_SK/labels.inc b/program/localization/sk_SK/labels.inc index 367b23d..3673389 100644 --- a/program/localization/sk_SK/labels.inc +++ b/program/localization/sk_SK/labels.inc @@ -17,7 +17,7 @@ | Martin Lacina <martin@whistler.sk> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5585 2011-12-09 19:28:20Z alec $ */ @@ -365,7 +365,7 @@ $labels['belowquote'] = 'nad citáciu'; $labels['abovequote'] = 'pod citáciu'; $labels['insertsignature'] = 'Vložit podpis'; $labels['previewpanemarkread'] = 'OznaÄiÅ¥ zobrazenej správy ako preÄÃtané'; -$labels['afternseconds'] = 'po $ sekundách'; +$labels['afternseconds'] = 'po $n sekundách'; $labels['reqmdn'] = 'Vždy požadovaÅ¥ doruÄenku'; $labels['reqdsn'] = 'Vždy vyžadovaÅ¥ potvrdenie o doruÄenà správy'; $labels['replysamefolder'] = 'UmietniÅ¥ odpoveÄ do adresára, kde je umiestnená správa, na ktorú sa odpovedalo'; diff --git a/program/localization/sk_SK/messages.inc b/program/localization/sk_SK/messages.inc index 3365111..ef5bbf4 100644 --- a/program/localization/sk_SK/messages.inc +++ b/program/localization/sk_SK/messages.inc @@ -17,7 +17,7 @@ | Martin Lacina <martin@whistler.sk> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5139 2011-08-28 09:47:15Z alec $ */ @@ -28,7 +28,7 @@ $messages['sessionerror'] = 'VaÅ¡e prihlásenie je neplatné alebo vyprÅ¡ala jeh $messages['imaperror'] = 'Nepodarilo sa spojiÅ¥ s IMAP serverom'; $messages['servererror'] = 'Chyba servera!'; $messages['servererrormsg'] = 'Chyba servera: $msg'; -$messages['databaserror'] = 'Databázová chyba!'; +$messages['dberror'] = 'Databázová chyba!'; $messages['errorreadonly'] = 'Nemožno vykonaÅ¥ operáciu. Adresár je len na ÄÃtanie'; $messages['errornoperm'] = 'Nemožno vykonaÅ¥ operáciu. PrÃstup odmietnutý'; $messages['invalidrequest'] = 'Chybný požiadavek. Žiadne údaje neboli uložené.'; diff --git a/program/localization/sl_SI/labels.inc b/program/localization/sl_SI/labels.inc index ad437cb..8a460f0 100644 --- a/program/localization/sl_SI/labels.inc +++ b/program/localization/sl_SI/labels.inc @@ -14,7 +14,7 @@ | Barbara Krasovec <barbarak@arnes.si> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -118,7 +118,7 @@ $labels['markread'] = 'Kot prebrano'; $labels['markunread'] = 'Kot neprebrano'; $labels['markflagged'] = 'Kot oznaÄeno'; $labels['markunflagged'] = 'Kot neoznaÄeno'; -$labels['messageactions'] = 'VeÄ možnosti'; +$labels['moreactions'] = 'VeÄ možnosti...'; $labels['select'] = 'Izberi'; $labels['all'] = 'Vse'; $labels['none'] = 'NiÄesar'; @@ -171,12 +171,15 @@ $labels['charset'] = 'Nabor znakov'; $labels['editortype'] = 'Vrsta urejevalnika'; $labels['returnreceipt'] = 'Potrdilo prejemnika'; $labels['dsn'] = 'Status dostave sporoÄila'; +$labels['mailreplyintro'] = '$date, je $sender napisal'; +$labels['originalmessage'] = 'Izvorno sporoÄilo'; $labels['editidents'] = 'Uredi identitete'; $labels['checkspelling'] = 'Preglej pravopis'; $labels['resumeediting'] = 'Nadaljuj z urejanjem'; $labels['revertto'] = 'Razveljavi'; $labels['attachments'] = 'Priponke'; $labels['upload'] = 'Naloži'; +$labels['uploadprogress'] = '$percent ($current od $total)'; $labels['close'] = 'Zapri'; $labels['messageoptions'] = 'Možnosti'; $labels['low'] = 'Nizka'; @@ -187,6 +190,7 @@ $labels['highest'] = 'NajviÅ¡ja'; $labels['nosubject'] = '(brez naslova)'; $labels['showimages'] = 'Prikaži slike'; $labels['alwaysshow'] = 'Vedno prikaži slike od $sender'; +$labels['isdraft'] = 'To je osnutek sporoÄila.'; $labels['htmltoggle'] = 'Obogateno besedilo (HTML)'; $labels['plaintoggle'] = 'Samo besedilo'; $labels['savesentmessagein'] = 'Shrani poslana sporoÄila v'; @@ -245,6 +249,8 @@ $labels['typepager'] = 'Pozivnik'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'PomoÄ'; $labels['typehomepage'] = 'DomaÄa stran'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; $labels['addfield'] = 'Dodaj polje...'; $labels['addcontact'] = 'Dodaj izbrane stike v imenik'; $labels['editcontact'] = 'Uredi vizitko'; @@ -266,7 +272,6 @@ $labels['print'] = 'Natisni'; $labels['export'] = 'Izvozi'; $labels['exportvcards'] = 'Izvozi stike v formatu vCard'; $labels['newcontactgroup'] = 'Ustvari novo skupino stikov'; -$labels['groupactions'] = 'Dejanja za skupine stikov...'; $labels['grouprename'] = 'Preimenuj skupino'; $labels['groupdelete'] = 'IzbriÅ¡i skupino'; $labels['previouspage'] = 'PrejÅ¡nja stran'; @@ -276,6 +281,8 @@ $labels['lastpage'] = 'Zadnja stran'; $labels['group'] = 'Skupina'; $labels['groups'] = 'Skupine'; $labels['personaladrbook'] = 'Stiki'; +$labels['searchsave'] = 'Shrani iskanje'; +$labels['searchdelete'] = 'IzbriÅ¡i iskanje'; $labels['import'] = 'Uvozi'; $labels['importcontacts'] = 'Uvozi stike'; $labels['importfromfile'] = 'Uvozi iz datoteke:'; @@ -284,6 +291,7 @@ $labels['importreplace'] = 'Zamenjaj celoten imenik'; $labels['importtext'] = 'Stike lahko prenesete iz obstojeÄega imenika<br/> Trenutno je podprto uvažanje naslovov v formatu <a href="http://en.wikipedia.org/wiki/VCard">vCard</a>'; $labels['done'] = 'DokonÄano'; $labels['settingsfor'] = 'Nastavitve za'; +$labels['about'] = 'Vizitka'; $labels['preferences'] = 'Nastavitve'; $labels['userpreferences'] = 'UporabniÅ¡ke nastavitve'; $labels['editpreferences'] = 'Uredi uporabniÅ¡ke nastavitve'; @@ -295,6 +303,8 @@ $labels['edititem'] = 'Uredi predmet'; $labels['preferhtml'] = 'Prednostno HTML'; $labels['defaultcharset'] = 'Privzeto kodiranje znakov'; $labels['htmlmessage'] = 'HTML sporoÄilo'; +$labels['dateformat'] = 'Prikaz datuma'; +$labels['timeformat'] = 'Prikaz Äasa'; $labels['prettydate'] = 'Bolj Äitljivi datumi'; $labels['setdefault'] = 'Nastavi privzeto'; $labels['autodetect'] = 'Samodejno'; @@ -366,7 +376,13 @@ $labels['reqmdn'] = 'Vedno zahtevaj povratnico'; $labels['reqdsn'] = 'Vedno zahtevaj obvestilo o statusu dostave'; $labels['replysamefolder'] = 'Shrani odgovore na sporoÄilo v mapo izvornega sporoÄila'; $labels['defaultaddressbook'] = 'Dodaj nove stike v izbran imenik'; +$labels['autocompletesingle'] = 'PreskoÄi nadomestni e-naslov pri samodejnem dokonÄanju'; $labels['spellcheckbeforesend'] = 'Preveri Ärkovanje pred poÅ¡iljanjem sporoÄila'; +$labels['spellcheckoptions'] = 'Možnosti Ärkovanja'; +$labels['spellcheckignoresyms'] = 'Ne upoÅ¡tevaj besed, ki vsebujejo simbole'; +$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['folder'] = 'Mapa'; $labels['folders'] = 'Mape'; $labels['foldername'] = 'Ime mape'; @@ -390,6 +406,12 @@ $labels['sharedfolder'] = 'Javna mapa'; $labels['sortby'] = 'Uredi po'; $labels['sortasc'] = 'Uredi naraÅ¡ÄajoÄe'; $labels['sortdesc'] = 'Uredi padajoÄe'; +$labels['undo'] = 'PrekliÄi'; +$labels['plugin'] = 'VtiÄnik'; +$labels['version'] = 'RazliÄica'; +$labels['source'] = 'Vir'; +$labels['license'] = 'Licenca'; +$labels['support'] = 'Podpora'; $labels['B'] = 'B'; $labels['KB'] = 'KB'; $labels['MB'] = 'MB'; diff --git a/program/localization/sl_SI/messages.inc b/program/localization/sl_SI/messages.inc index 996a0fd..1aa199c 100644 --- a/program/localization/sl_SI/messages.inc +++ b/program/localization/sl_SI/messages.inc @@ -21,7 +21,7 @@ $messages['sessionerror'] = 'Seja je neveljavna ali je potekla.'; $messages['imaperror'] = 'Povezava z IMAP strežnikom je spodletela.'; $messages['servererror'] = 'Napaka strežnika!'; $messages['servererrormsg'] = 'Napaka strežnikaÄ $msg'; -$messages['databaserror'] = 'Napaka v bazi'; +$messages['dberror'] = 'Napaka v bazi'; $messages['errorreadonly'] = 'Operacije ni bilo mogoÄe izvrÅ¡iti. Mapa je na voljo samo za branje.'; $messages['errornoperm'] = 'Operacije ni bilo mogoÄe izvrÅ¡iti. Dostop zavrnjen.'; $messages['invalidrequest'] = 'Neveljavna zahteva. Podatki niso bili shranjeni.'; @@ -40,10 +40,12 @@ $messages['messagesaved'] = 'SporoÄilo je bilo shranjeno v Osnutke'; $messages['successfullysaved'] = 'UspeÅ¡no shranjeno.'; $messages['addedsuccessfully'] = 'Stik je bil uspeÅ¡no dodan v imenik.'; $messages['contactexists'] = 'Stik s tem elektronskim naslovom že obstaja.'; +$messages['contactnameexists'] = 'Stik s tem imenom že obstaja'; $messages['blockedimages'] = 'Zaradi zaÅ¡Äite zasebnosti je prikaz slik v sporoÄilu onemogoÄen.'; $messages['encryptedmessage'] = 'SporoÄilo je Å¡ifrirano in ne more biti prikazano.'; $messages['nocontactsfound'] = 'Ni stikov.'; $messages['contactnotfound'] = 'Iskanega stika ni bilo mogoÄe najti.'; +$messages['contactsearchonly'] = 'VpiÅ¡ite iskalni parameter za iskanje stika'; $messages['sendingfailed'] = 'SporoÄila ni bilo mogoÄe poslati.'; $messages['senttooquickly'] = 'PoÄakajte $sec sekund in nato znova poskusite s poÅ¡iljanjem sporoÄila.'; $messages['errorsavingsent'] = 'Pri shranjevanju poslanega sporoÄila je priÅ¡lo do napake.'; @@ -53,9 +55,12 @@ $messages['errorcopying'] = 'SporoÄila ni bilo mogoÄe kopirati.'; $messages['errordeleting'] = 'SporoÄila ni bilo mogoÄe izbrisati.'; $messages['errormarking'] = 'SporoÄila ni bilo mogoÄe oznaÄiti.'; $messages['deletecontactconfirm'] = 'Ste prepriÄani, da želite izbrisati oznaÄen(e) stik(e)?'; +$messages['deletegroupconfirm'] = 'Ste prepriÄani, da želite izbrisati izbrano skupino?'; $messages['deletemessagesconfirm'] = 'Ste prepriÄani, da želite izbrisati oznaÄeno(a) sporoÄilo(a)?'; $messages['deletefolderconfirm'] = 'Ste prepriÄani, da želite to mapo izbrisati?'; $messages['purgefolderconfirm'] = 'Ste prepriÄani, da želite izbrisati vsa sporoÄila v mapi?'; +$messages['contactdeleting'] = 'Brisanje stika/ov...'; +$messages['groupdeleting'] = 'Brisanje skupine...'; $messages['folderdeleting'] = 'Brisanje mape...'; $messages['foldermoving'] = 'Premikanje mape...'; $messages['foldersubscribing'] = 'Prijavljanje mape...'; @@ -70,10 +75,10 @@ $messages['nosubjectwarning'] = 'Polje "Zadeva" je prazno. Želite dodati tekst $messages['nobodywarning'] = 'Želite poslati sporoÄilo brez vsebine?'; $messages['notsentwarning'] = 'SporoÄilo ni bilo poslano. Želite zavreÄi to sporoÄilo?'; $messages['noldapserver'] = 'Izberite LDAP strežnik, v katerem želite iskati?'; -$messages['nocontactsreturned'] = 'Nobenega stika ni bilo mogoÄe najti'; $messages['nosearchname'] = 'Vnesite ime ali elektronski naslov stika'; $messages['notuploadedwarning'] = 'Priponke se Å¡e nalagajo na strežnik. PoÄakajte ali prekinite prenos.'; $messages['searchsuccessful'] = '$nr najdenih sporoÄil'; +$messages['contactsearchsuccessful'] = '$nr najdenih stikov.'; $messages['searchnomatch'] = 'Ni zadetkov'; $messages['searching'] = 'Iskanje...'; $messages['checking'] = 'Preverjanje...'; @@ -94,8 +99,11 @@ $messages['sourceisreadonly'] = 'Ta naslov je na voljo samo za branje'; $messages['errorsavingcontact'] = 'Stika ni bilo mogoÄe shraniti'; $messages['movingmessage'] = 'Premikanje sporoÄila...'; $messages['copyingmessage'] = 'Kopiranje sporoÄila...'; +$messages['copyingcontact'] = 'Kopiranje stika/ov'; $messages['deletingmessage'] = 'Brisanje sporoÄil/a'; $messages['markingmessage'] = 'OznaÄevanje sporoÄil/a'; +$messages['addingmember'] = 'Dodajanje stika/ov v skupino...'; +$messages['removingmember'] = 'Odstranjevanje stika/ov iz skupine..'; $messages['receiptsent'] = 'SporoÄilo o branju je bilo uspeÅ¡no poslano'; $messages['errorsendingreceipt'] = 'SporoÄila o branju ni bilo mogoÄe poslati'; $messages['nodeletelastidentity'] = 'Te identitete ni mogoÄe izbrisati, saj je edina.'; @@ -117,7 +125,6 @@ $messages['smtpautherror'] = 'Napaka pri poÅ¡iljanju($code): Avtentikacija je sp $messages['smtpfromerror'] = 'Napaka pri poÅ¡iljanju ($code): Neveljaven elektronski naslov poÅ¡iljatelja "$from" ($msg)'; $messages['smtptoerror'] = 'Napaka pri poÅ¡iljanju ($code): Neveljaven elektronski naslov prejemnika "$to" ($msg)'; $messages['smtprecipientserror'] = 'Napaka pri poÅ¡iljanju: Seznama prejemnikov ni bilo mogoÄe razÄleniti'; -$messages['smtpdsnerror'] = 'Napaka pri poÅ¡iljanju: Ni podpore za poÅ¡iljanje obvestil o statusu dostave'; $messages['smtperror'] = 'Napaka pri poÅ¡iljanju:$msg'; $messages['emailformaterror'] = 'Nepravilen elektronski naslov: $email'; $messages['toomanyrecipients'] = 'Navedli ste preveÄ prejemnikov. ZmanjÅ¡ajte Å¡tevilo prejemnikov na $max'; @@ -125,19 +132,27 @@ $messages['maxgroupmembersreached'] = 'Å tevilo Älanov skupine presega najveÄj $messages['internalerror'] = 'PriÅ¡lo je do napake. Poskusite znova.'; $messages['contactdelerror'] = 'Stika/ov ni bilo mogoÄe izbrisati'; $messages['contactdeleted'] = 'Stik/i so bili uspeÅ¡no izbrisani'; +$messages['contactrestoreerror'] = 'Ni bilo mogoÄe obnoviti izbrisanih stikov.'; +$messages['contactrestored'] = 'Stiki so bili uspeÅ¡no obnovljeni.'; $messages['groupdeleted'] = 'Skupina je bila uspeÅ¡no izbrisana'; $messages['grouprenamed'] = 'Skupina je bila uspeÅ¡no preimenovana'; $messages['groupcreated'] = 'Skupina je bila uspeÅ¡no ustvarjena'; +$messages['savedsearchdeleted'] = 'Shranjeno iskanje je bilo uspeÅ¡no izbrisano.'; +$messages['savedsearchdeleteerror'] = 'Ni bilo mogoÄe izbrisati shranjenega iskanja.'; +$messages['savedsearchcreated'] = 'Iskanje je bilo uspeÅ¡no shranjeno.'; +$messages['savedsearchcreateerror'] = 'Iskanja ni bilo mogoÄe shraniti.'; $messages['messagedeleted'] = 'SporoÄila so bila uspeÅ¡no izbrisana'; $messages['messagemoved'] = 'SporoÄila so bila uspeÅ¡no premaknjena'; $messages['messagecopied'] = 'SporoÄila so bila uspeÅ¡no kopirana'; $messages['messagemarked'] = 'SporoÄila so bila uspeÅ¡no oznaÄena'; $messages['autocompletechars'] = 'Vnesite vsaj $min znakov za samodejno dokonÄanje'; +$messages['autocompletemore'] = 'Z iskanjem se ujema veÄ vnosov. Vnesite dodatne Ärke.'; $messages['namecannotbeempty'] = 'Imena ni mogoÄe izbrisati'; $messages['nametoolong'] = 'Ime je predolgo'; $messages['folderupdated'] = 'Mapa je bila uspeÅ¡no posodobljena'; $messages['foldercreated'] = 'Mapa je bila uspeÅ¡no ustvarjena'; $messages['invalidimageformat'] = 'Neveljaven format slike'; $messages['mispellingsfound'] = 'V sporoÄilu so bile najdene napake v Ärkovanju'; +$messages['parentnotwritable'] = 'Podmape v tej mapi ni bilo mogoÄe ustvariti/premakniti. Nimate pravic.'; ?> diff --git a/program/localization/sv_SE/labels.inc b/program/localization/sv_SE/labels.inc index c864c5e..947a5ae 100644 --- a/program/localization/sv_SE/labels.inc +++ b/program/localization/sv_SE/labels.inc @@ -1,4 +1,4 @@ -<?php +a<?php /* @@ -15,7 +15,7 @@ | Andreas Henriksson <andreas@fatal.se> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ @@ -119,7 +119,7 @@ $labels['markread'] = 'Läst'; $labels['markunread'] = 'Oläst'; $labels['markflagged'] = 'Flaggat'; $labels['markunflagged'] = 'Oflaggat'; -$labels['messageactions'] = 'Hantera meddelande'; +$labels['moreactions'] = 'Ytterligare hantering...'; $labels['select'] = 'Välj'; $labels['all'] = 'Alla'; $labels['none'] = 'Ingen'; @@ -173,6 +173,7 @@ $labels['editortype'] = 'Textredigerare'; $labels['returnreceipt'] = 'Mottagarkvitto'; $labels['dsn'] = 'Leveransstatusmeddelande'; $labels['mailreplyintro'] = '$date skrev $sender:'; +$labels['originalmessage'] = 'Ursprungligt meddelande'; $labels['editidents'] = 'Ãndra identiteter'; $labels['checkspelling'] = 'Kontrollera stavning'; $labels['resumeediting'] = 'à teruppta redigering'; @@ -248,6 +249,8 @@ $labels['typepager'] = 'Personsökare'; $labels['typevideo'] = 'Video'; $labels['typeassistant'] = 'Assistent'; $labels['typehomepage'] = 'Webbsida'; +$labels['typeblog'] = 'Blog'; +$labels['typeprofile'] = 'Profil'; $labels['addfield'] = 'Lägg till fält...'; $labels['addcontact'] = 'Lägg till ny kontakt'; $labels['editcontact'] = 'Ãndra kontakt'; @@ -269,7 +272,6 @@ $labels['print'] = 'Skriv ut'; $labels['export'] = 'Exportera'; $labels['exportvcards'] = 'Exportera kontakter'; $labels['newcontactgroup'] = 'Ny kontaktgrupp'; -$labels['groupactions'] = 'Hantera kontaktgrupper'; $labels['grouprename'] = 'Ãndra gruppnamn'; $labels['groupdelete'] = 'Ta bort grupp'; $labels['previouspage'] = 'Visa föregÃ¥ende sida'; @@ -279,6 +281,8 @@ $labels['lastpage'] = 'Visa sista sidan'; $labels['group'] = 'Grupp'; $labels['groups'] = 'Kontaktgrupper'; $labels['personaladrbook'] = 'Personliga adresser'; +$labels['searchsave'] = 'Lägg till sökning'; +$labels['searchdelete'] = 'Ta bort sökning'; $labels['import'] = 'Importera'; $labels['importcontacts'] = 'Importera kontakter'; $labels['importfromfile'] = 'Importera frÃ¥n fil:'; @@ -298,6 +302,8 @@ $labels['edititem'] = 'Ãndra information'; $labels['preferhtml'] = 'Visa meddelanden i HTML-format'; $labels['defaultcharset'] = 'Förvald teckenkodning'; $labels['htmlmessage'] = 'HTML-meddelande'; +$labels['dateformat'] = 'Datumformat'; +$labels['timeformat'] = 'Tidformat'; $labels['prettydate'] = 'Fina datum'; $labels['setdefault'] = 'Sätt som standard'; $labels['autodetect'] = 'Automatiskt'; @@ -370,6 +376,11 @@ $labels['reqdsn'] = 'Begär alltid leveransstatusmeddelande'; $labels['replysamefolder'] = 'Placera svar i samma katalog som besvarat meddelande'; $labels['defaultaddressbook'] = 'Lägg till nya kontakter i vald adressbok'; $labels['spellcheckbeforesend'] = 'Kontrollera stavning innan meddelanden skickas'; +$labels['spellcheckoptions'] = 'Rättstavningsalternativ'; +$labels['spellcheckignoresyms'] = 'Ignorera ord med symboler'; +$labels['spellcheckignorenums'] = 'Ignorera ord med siffror'; +$labels['spellcheckignorecaps'] = 'Ignorera ord med enbart stora bokstäver'; +$labels['addtodict'] = 'Lägg till i ordlista'; $labels['folder'] = 'Katalog'; $labels['folders'] = 'Kataloger'; $labels['foldername'] = 'Katalognamn'; diff --git a/program/localization/sv_SE/messages.inc b/program/localization/sv_SE/messages.inc index 3e1cf34..5af843f 100644 --- a/program/localization/sv_SE/messages.inc +++ b/program/localization/sv_SE/messages.inc @@ -15,7 +15,7 @@ | Andreas Henriksson <andreas@fatal.se> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5175 2011-09-05 18:42:24Z thomasb $ +@version $Id: messages.inc 5290 2011-09-28 17:09:50Z thomasb $ */ @@ -26,7 +26,7 @@ $messages['sessionerror'] = 'Din inloggning är felaktig eller har gÃ¥tt ut'; $messages['imaperror'] = 'Anslutning till IMAP-servern misslyckades'; $messages['servererror'] = 'Serverfel!'; $messages['servererrormsg'] = 'Serverfel: $msg'; -$messages['databaserror'] = 'Databasfel!'; +$messages['dberror'] = 'Databasfel!'; $messages['errorreadonly'] = 'à tgärden kunde inte utföras. Katalogen är skrivskyddad'; $messages['errornoperm'] = 'à tgärden kunde inte utföras. Otillräcklig befogenhet'; $messages['invalidrequest'] = 'Ogiltig begäran! Informationen sparades inte.'; @@ -50,6 +50,7 @@ $messages['blockedimages'] = 'Externt länkade bilder i meddelandet har blockera $messages['encryptedmessage'] = 'Meddelandet är krypterat och kan tyvärr inte visas.'; $messages['nocontactsfound'] = 'Inga kontakter hittades'; $messages['contactnotfound'] = 'EfterfrÃ¥gad kontakt hittades inte'; +$messages['contactsearchonly'] = 'Ange sökord för att hitta kontakter'; $messages['sendingfailed'] = 'Meddelandet kunde inte skickas'; $messages['senttooquickly'] = 'Vänta ytterligare $sec sekunder med att skicka meddelandet'; $messages['errorsavingsent'] = 'Ett fel inträffade när det skickade meddelandet skulle sparas'; @@ -63,6 +64,7 @@ $messages['deletegroupconfirm'] = 'Vill du verkligen ta bort den valda gruppen?' $messages['deletemessagesconfirm'] = 'Vill du verkligen ta bort valda meddelanden?'; $messages['deletefolderconfirm'] = 'Vill du verkligen ta bort den här katalogen?'; $messages['purgefolderconfirm'] = 'Vill du verkligen ta bort alla meddelanden i den här katalogen?'; +$messages['contactdeleting'] = 'Tar bort kontakt...'; $messages['groupdeleting'] = 'Tar bort grupp...'; $messages['folderdeleting'] = 'Tar bort katalog...'; $messages['foldermoving'] = 'Flyttar katalog...'; @@ -78,10 +80,10 @@ $messages['nosubjectwarning'] = 'Ãmnesraden är tom. Vill du ange ämne nu?'; $messages['nobodywarning'] = 'Skicka det här meddelandet utan text?'; $messages['notsentwarning'] = 'Meddelandet har inte skickats. Vill du avbryta meddelandet?'; $messages['noldapserver'] = 'Ange en LDAP-server för att söka'; -$messages['nocontactsreturned'] = 'Inga kontakter hittades'; $messages['nosearchname'] = 'Ange ett kontaktnamn eller en adress'; $messages['notuploadedwarning'] = 'Alla bilagor har inte överförts ännu. Vänligen vänta eller avbryt överföringen.'; $messages['searchsuccessful'] = '$nr meddelanden hittades'; +$messages['contactsearchsuccessful'] = '$nr kontakter hittades'; $messages['searchnomatch'] = 'Sökningen gav inget resultat'; $messages['searching'] = 'Söker...'; $messages['checking'] = 'Kontrollerar...'; @@ -141,11 +143,16 @@ $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['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['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'; diff --git a/program/localization/tr_TR/labels.inc b/program/localization/tr_TR/labels.inc index 089e0b1..9409f95 100644 --- a/program/localization/tr_TR/labels.inc +++ b/program/localization/tr_TR/labels.inc @@ -14,7 +14,7 @@ | Author: Gökdeniz KaradaÄ <gokdenizk@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: labels.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/tr_TR/messages.inc b/program/localization/tr_TR/messages.inc index 004644f..aed1172 100644 --- a/program/localization/tr_TR/messages.inc +++ b/program/localization/tr_TR/messages.inc @@ -14,7 +14,7 @@ | Author: Gökdeniz KaradaÄ <gokdenizk@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5291 2011-09-28 17:10:45Z thomasb $ +@version $Id: messages.inc 5290 2011-09-28 17:09:50Z thomasb $ */ diff --git a/program/localization/uk_UA/labels.inc b/program/localization/uk_UA/labels.inc index 99f2d2e..d4fbd75 100644 --- a/program/localization/uk_UA/labels.inc +++ b/program/localization/uk_UA/labels.inc @@ -13,7 +13,7 @@ | Author: Volodymyr M. Kononenko aka kvm <vmkononenko@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -100,6 +100,8 @@ $labels['replytomessage'] = 'ÐÑдповÑÑÑи вÑдпÑавникÑ'; $labels['replytoallmessage'] = 'ÐÑдповÑÑÑи до лиÑÑа або вÑдпÑÐ°Ð²Ð½Ð¸ÐºÑ Ñа ÑÑÑм оÑÑимÑваÑам'; $labels['replyall'] = 'ÐÑдповÑÑÑи ÑÑÑм'; $labels['replylist'] = 'ÐÑдповÑÑÑи до лиÑÑа'; +$labels['forwardinline'] = 'ÐеÑеÑлаÑи Ñ ÑÑÐ»Ñ Ð»Ð¸ÑÑа'; +$labels['forwardattachment'] = 'ÐеÑеÑлаÑи Ñк пÑикÑÑпленнÑ'; $labels['forwardmessage'] = 'ÐеÑеÑлаÑи повÑдомленнÑ'; $labels['deletemessage'] = 'У коÑик'; $labels['movemessagetotrash'] = 'ÐеÑемÑÑÑиÑи лиÑÑ Ñ ÐºÐ¾Ñик'; @@ -115,7 +117,7 @@ $labels['markread'] = 'ÐознаÑиÑи Ñк пÑоÑиÑане'; $labels['markunread'] = 'ÐознаÑиÑи Ñк непÑоÑиÑане'; $labels['markflagged'] = 'ÐодаÑи зÑÑоÑкÑ'; $labels['markunflagged'] = 'ÐнÑÑи зÑÑоÑкÑ'; -$labels['messageactions'] = 'ÐодаÑÐºÐ¾Ð²Ñ Ð´ÑÑ...'; +$labels['moreactions'] = 'ÐнÑÑ Ð´ÑÑ...'; $labels['select'] = 'ÐибÑаÑи'; $labels['all'] = 'ÐÑÑ'; $labels['none'] = 'Ðодного'; @@ -168,12 +170,15 @@ $labels['charset'] = 'ÐодÑваннÑ'; $labels['editortype'] = 'РедакÑоÑ'; $labels['returnreceipt'] = 'ÐÐ°Ð¿Ð¸Ñ Ð²ÑдповÑдÑ'; $labels['dsn'] = 'ÐовÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñо доÑÑавкÑ'; +$labels['mailreplyintro'] = '$date, $sender напиÑав:'; +$labels['originalmessage'] = 'ÐÑигÑналÑне повÑдомленнÑ'; $labels['editidents'] = 'ÐмÑниÑи даннÑ'; $labels['checkspelling'] = 'ÐеÑевÑÑиÑи оÑÑогÑаÑÑÑ'; $labels['resumeediting'] = 'ÐÑодовжиÑи ÑедагÑваннÑ'; $labels['revertto'] = 'ÐÑдмÑниÑи ÑедагÑваннÑ'; $labels['attachments'] = 'ÐÐºÐ»Ð°Ð´ÐµÐ½Ñ Ñайли'; $labels['upload'] = 'ÐклаÑÑи'; +$labels['uploadprogress'] = '$percent ($current з $total)'; $labels['close'] = 'ÐакÑиÑи'; $labels['messageoptions'] = 'ÐалаÑÑÑÐ²Ð°Ð½Ð½Ñ Ð»Ð¸ÑÑÑв'; $labels['low'] = 'ÐизÑкий'; @@ -226,6 +231,10 @@ $labels['female'] = 'жÑноÑий'; $labels['manager'] = 'ÐенеждеÑ'; $labels['assistant'] = 'ÐомÑÑник'; $labels['spouse'] = 'ШлÑбний паÑÑнеÑ'; +$labels['allfields'] = 'УÑÑ Ð¿Ð¾Ð»Ñ'; +$labels['search'] = 'ÐоÑÑк'; +$labels['advsearch'] = 'РозÑиÑений поÑÑк'; +$labels['other'] = 'ÐнÑе'; $labels['typehome'] = 'ÐÑм'; $labels['typework'] = 'РобоÑа'; $labels['typeother'] = 'ÐнÑе'; @@ -237,6 +246,9 @@ $labels['typecar'] = 'ÐвÑомобÑлÑ'; $labels['typepager'] = 'ÐейджеÑ'; $labels['typevideo'] = 'ÐÑдео'; $labels['typeassistant'] = 'ÐомÑÑник'; +$labels['typehomepage'] = 'ÐомаÑÐ½Ñ ÑÑоÑÑнка'; +$labels['typeblog'] = 'Ðлог'; +$labels['typeprofile'] = 'ÐÑоÑÑлÑ'; $labels['addfield'] = 'ÐодаÑи поле...'; $labels['addcontact'] = 'ÐодаÑи вибÑÐ°Ð½Ñ ÐºÐ¾Ð½ÑакÑи до ÑпиÑÐºÑ ÐºÐ¾Ð½ÑакÑÑв'; $labels['editcontact'] = 'РедагÑваÑи конÑакÑ'; @@ -258,7 +270,8 @@ $labels['print'] = 'ÐÑÑкÑваÑи'; $labels['export'] = 'ÐкÑпоÑÑÑваÑи'; $labels['exportvcards'] = 'ÐкÑпоÑÑÑваÑи конÑакÑи Ñ ÑоÑÐ¼Ð°Ñ vCard'; $labels['newcontactgroup'] = 'СÑвоÑиÑи Ð½Ð¾Ð²Ñ Ð³ÑÑÐ¿Ñ ÐºÐ¾Ð½ÑакÑÑв'; -$labels['groupactions'] = 'ÐÑÑ Ð· гÑÑпами конÑакÑÑв'; +$labels['grouprename'] = 'ÐеÑейменÑваÑи гÑÑпÑ'; +$labels['groupdelete'] = 'ÐидалиÑи гÑÑпÑ'; $labels['previouspage'] = 'ÐопеÑÐµÐ´Ð½Ñ ÑÑоÑÑнка'; $labels['firstpage'] = 'ÐеÑÑа ÑÑоÑÑнка'; $labels['nextpage'] = 'ÐаÑÑÑпна ÑÑоÑÑнка'; @@ -266,9 +279,12 @@ $labels['lastpage'] = 'ÐÑÑÐ°Ð½Ð½Ñ ÑÑоÑÑнка'; $labels['group'] = 'ÐÑÑпа'; $labels['groups'] = 'ÐÑÑпи'; $labels['personaladrbook'] = 'ÐеÑÑоналÑÐ½Ñ Ð°Ð´ÑеÑи'; +$labels['searchsave'] = 'ÐбеÑегÑи поÑÑк'; +$labels['searchdelete'] = 'ÐидалиÑи поÑÑк'; $labels['import'] = 'ÐмпоÑÑ'; $labels['importcontacts'] = 'ÐмпоÑÑÑваÑи конÑакÑи'; $labels['importfromfile'] = 'ÐмпоÑÑÑваÑи з ÑайлÑ:'; +$labels['importtarget'] = 'ÐодаÑи Ð½Ð¾Ð²Ñ ÐºÐ¾Ð½ÑакÑи до адÑеÑÐ½Ð¾Ñ ÐºÐ½Ð¸Ð³Ð¸'; $labels['importreplace'] = 'ÐамÑниÑи вÑÑ Ð°Ð´ÑеÑÐ½Ñ ÐºÐ½Ð¸Ð³Ñ'; $labels['importtext'] = 'Ðи можеÑе заванÑажиÑи конÑакÑи з ÑÑнÑÑÑÐ¾Ñ Ð°Ð´ÑеÑÐ½Ð¾Ñ ÐºÐ½Ð¸Ð³Ð¸. Ðа даний Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¿ÑдÑÑимÑÑÑÑÑÑ ÑмпоÑÑÑÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½ÑакÑÑв з ÑоÑмаÑÑ vCard'; $labels['done'] = 'ÐоÑово'; @@ -284,6 +300,8 @@ $labels['edititem'] = 'РедагÑваÑи'; $labels['preferhtml'] = 'ÐоказÑваÑи в HTML'; $labels['defaultcharset'] = 'ÐодÑÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовÑÑванннÑм'; $labels['htmlmessage'] = 'ÐиÑÑ Ñ HTML'; +$labels['dateformat'] = 'ФоÑÐ¼Ð°Ñ Ð´Ð°Ñи'; +$labels['timeformat'] = 'ФоÑÐ¼Ð°Ñ ÑаÑÑ'; $labels['prettydate'] = 'ÐаÑи Ñ Ð·ÑÑÑÐ½Ð¾Ð¼Ñ ÑоÑмаÑÑ'; $labels['setdefault'] = 'ÐÑÑановиÑи за замовÑÑваннÑм'; $labels['autodetect'] = 'ÐизнаÑаÑи авÑомаÑиÑно'; @@ -354,6 +372,13 @@ $labels['afternseconds'] = 'ÑеÑез $n ÑекÑнд'; $labels['reqmdn'] = 'Ðавжди вимагаÑи повÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñо доÑÑавкÑ'; $labels['reqdsn'] = 'Ðавжди вимагаÑи повÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñо ÑÑаÑÑÑ Ð´Ð¾ÑÑавки'; $labels['replysamefolder'] = 'РозмÑÑÑиÑи вÑдповÑÐ´Ñ Ñ ÑÑй же папÑÑ, де Ð·Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑÑ Ð¾ÑигÑнал'; +$labels['defaultaddressbook'] = 'ÐодаÑи Ð½Ð¾Ð²Ñ ÐºÐ¾Ð½ÑакÑи до обÑÐ°Ð½Ð¾Ñ Ð°Ð´ÑеÑÐ½Ð¾Ñ ÐºÐ½Ð¸Ð³Ð¸'; +$labels['spellcheckbeforesend'] = 'ÐеÑевÑÑиÑи оÑÑогÑаÑÑÑ Ð¿ÐµÑед вÑдпÑÐ°Ð²ÐºÐ¾Ñ Ð¿Ð¾Ð²ÑдомленнÑ'; +$labels['spellcheckoptions'] = 'ÐалаÑÑÑÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑевÑÑки оÑÑогÑаÑÑÑ'; +$labels['spellcheckignoresyms'] = 'ÐгноÑÑваÑи Ñлова Ñз Ñимволами'; +$labels['spellcheckignorenums'] = 'ÐгноÑÑваÑи Ñлова Ñз ÑиÑлами'; +$labels['spellcheckignorecaps'] = 'ÐгноÑÑваÑи Ñлова Ñз великими бÑквами'; +$labels['addtodict'] = 'ÐодаÑи до Ñловника'; $labels['folder'] = 'Ðапка'; $labels['folders'] = 'Ðапки'; $labels['foldername'] = 'Ðазва папки'; @@ -377,6 +402,7 @@ $labels['sharedfolder'] = 'ÐÑблÑÑний каÑалог'; $labels['sortby'] = 'ÐÑдÑоÑÑÑваÑи за'; $labels['sortasc'] = 'СоÑÑÑваÑи за зÑоÑÑаннÑм'; $labels['sortdesc'] = 'СоÑÑÑваÑи за ÑпаданнÑм'; +$labels['undo'] = 'ÐÑдмÑниÑи'; $labels['B'] = 'б'; $labels['KB'] = 'Ðб'; $labels['MB'] = 'Ðб'; diff --git a/program/localization/uk_UA/messages.inc b/program/localization/uk_UA/messages.inc index 341f0ba..e302710 100644 --- a/program/localization/uk_UA/messages.inc +++ b/program/localization/uk_UA/messages.inc @@ -13,7 +13,7 @@ | Author: Volodymyr M. Kononenko aka kvm <vmkononenko@gmail.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 4671 2011-04-20 08:47:44Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -24,6 +24,7 @@ $messages['sessionerror'] = 'ÐаÑа ÑеÑÑÑ Ð·Ð°ÑÑаÑÑла'; $messages['imaperror'] = 'Ðевдале з`ÑÐ´Ð½Ð°Ð½Ð½Ñ Ð· IMAP ÑеÑвеÑом'; $messages['servererror'] = 'Ðомилка ÑеÑвеÑа!'; $messages['servererrormsg'] = 'Ðомилка ÑеÑвеÑа: $msg'; +$messages['dberror'] = 'Ðомилка бази Ð´Ð°Ð½Ð¸Ñ !'; $messages['errorreadonly'] = 'Ðеможливо виконаÑи опеÑаÑÑÑ. Ðапка доÑÑÑпна ÑÑлÑки Ð´Ð»Ñ ÑиÑаннÑ.'; $messages['errornoperm'] = 'Ðеможливо виконаÑи опеÑаÑÑÑ. ÐоÑÑÑп забоÑонено'; $messages['invalidrequest'] = 'ÐевÑÑний запиÑ! ÐÐ°Ð½Ñ Ð½Ðµ збеÑежено.'; @@ -32,6 +33,7 @@ $messages['loggedout'] = 'ÐаÑÑ ÑеÑÑÑ Ð·Ð°Ð²ÐµÑÑено. ÐÑÑого $messages['mailboxempty'] = 'ÐоÑÑова ÑкÑинÑка поÑожнÑ'; $messages['loading'] = 'ÐаванÑаженнÑ...'; $messages['uploading'] = 'Файл вÑдпÑавлÑÑÑÑÑÑ...'; +$messages['uploadingmany'] = 'ÐаванÑÐ°Ð¶ÐµÐ½Ð½Ñ ÑайлÑв...'; $messages['loadingdata'] = 'ÐаванÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ ...'; $messages['checkingmail'] = 'ÐеÑевÑÑка Ð½Ð¾Ð²Ð¸Ñ Ð»Ð¸ÑÑÑв...'; $messages['sendingmessage'] = 'ÐÑдпÑавка лиÑÑа...'; @@ -41,10 +43,12 @@ $messages['messagesaved'] = 'ÐбеÑежено в ЧеÑнеÑÐºÐ°Ñ '; $messages['successfullysaved'] = 'ÐбеÑежено'; $messages['addedsuccessfully'] = 'ÐонÑÐ°ÐºÑ ÑÑпÑÑно доданий до ÑпиÑÐºÑ ÐºÐ¾Ð½ÑакÑÑв'; $messages['contactexists'] = 'ÐонÑÐ°ÐºÑ Ð· ÑÐ°ÐºÐ¾Ñ ÐµÐ»ÐµÐºÑÑÐ¾Ð½Ð½Ð¾Ñ Ð°Ð´ÑеÑÐ¾Ñ Ð²Ð¶Ðµ ÑÑнÑÑ'; +$messages['contactnameexists'] = 'ÐонÑÐ°ÐºÑ Ð· Ñаким Ñамим Ñменем вже ÑÑнÑÑ.'; $messages['blockedimages'] = 'РмеÑÐ¾Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ зобÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð· зовнÑÑнÑÑ Ð´Ð¶ÐµÑел заблоковано Ñ ÑÑÐ¾Ð¼Ñ Ð»Ð¸ÑÑÑ.'; $messages['encryptedmessage'] = 'ÐиÑÑ Ð·Ð°ÑиÑÑовано Ñ Ð½Ðµ може бÑÑи вÑдобÑажено.'; $messages['nocontactsfound'] = 'ÐонÑакÑи не знайденÑ'; $messages['contactnotfound'] = 'ÐапиÑаний конÑÐ°ÐºÑ Ð½Ðµ знайдений'; +$messages['contactsearchonly'] = 'ÐведÑÑÑ Ð´ÐµÑÐºÑ ÐºÑиÑеÑÑÑ Ð¿Ð¾ÑÑкÑ, Ñоб знайÑи конÑакÑи'; $messages['sendingfailed'] = 'Ðе вдалоÑÑ Ð²ÑдпÑавиÑи лиÑÑа'; $messages['senttooquickly'] = 'ÐÑÐ´Ñ Ð»Ð°Ñка, заÑекайÑе $sec ÑекÑнд Ð´Ð»Ñ Ð²ÑдпÑавки лиÑÑа'; $messages['errorsavingsent'] = 'Ðомилка пÑи збеÑÐµÐ¶ÐµÐ½Ð½Ñ Ð²ÑдпÑавленого лиÑÑа'; @@ -54,9 +58,12 @@ $messages['errorcopying'] = 'Ðе вдалоÑÑ Ð·ÐºÐ¾Ð¿ÑÑваÑи лиÑÑи $messages['errordeleting'] = 'Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñи лиÑÑи'; $messages['errormarking'] = 'Ðе вдалоÑÑ Ð¿Ð¾Ð·Ð½Ð°ÑиÑи лиÑÑи'; $messages['deletecontactconfirm'] = 'Ðи дÑйÑно бажаÑÑе видалиÑи вибÑÐ°Ð½Ñ ÐºÐ¾Ð½ÑакÑи?'; +$messages['deletegroupconfirm'] = 'Ðи дÑйÑно Ñ Ð¾ÑеÑе видалиÑи обÑÐ°Ð½Ñ Ð³ÑÑпÑ?'; $messages['deletemessagesconfirm'] = 'Ðи дÑйÑно бажаÑÑе видалиÑи вибÑÐ°Ð½Ñ Ð»Ð¸ÑÑи?'; $messages['deletefolderconfirm'] = 'Ðи дÑйÑно бажаÑÑе видалиÑи ÑÑ Ð¿Ð°Ð¿ÐºÑ?'; $messages['purgefolderconfirm'] = 'Ðи дÑйÑно бажаÑÑе видалиÑи вÑÑ Ð»Ð¸ÑÑи Ñ ÑÑй папÑÑ?'; +$messages['contactdeleting'] = 'ÐÐ¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð½ÑакÑÑ(Ñв)...'; +$messages['groupdeleting'] = 'ÐÐ¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð³ÑÑпи...'; $messages['folderdeleting'] = 'ÐÐ¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸...'; $messages['foldermoving'] = 'ÐеÑемÑÑÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸...'; $messages['foldersubscribing'] = 'ÐÑдпиÑаÑи папкÑ...'; @@ -71,10 +78,10 @@ $messages['nosubjectwarning'] = 'Ðе вказано ÑÐµÐ¼Ñ Ð»Ð¸ÑÑа. Ðаж $messages['nobodywarning'] = 'ÐÑдпÑавиÑи лиÑÑа без ÑекÑÑÑ?'; $messages['notsentwarning'] = 'ÐиÑÑ Ð½Ðµ бÑло вÑдпÑавлено. Ðи бажаÑÑе вÑÐ´Ñ Ð¸Ð»Ð¸Ñи вÑдпÑавкÑ?'; $messages['noldapserver'] = 'ÐÑÐ´Ñ Ð»Ð°Ñка, вибеÑÑÑÑ LDAP ÑеÑÐ²ÐµÑ Ð´Ð»Ñ Ð¿Ð¾ÑÑкÑ'; -$messages['nocontactsreturned'] = 'ÐонÑакÑи не знайденÑ'; $messages['nosearchname'] = 'ÐÑÐ´Ñ Ð»Ð°Ñка, введÑÑÑ Ñм`Ñ Ñи елекÑÑÐ¾Ð½Ð½Ñ Ð°Ð´ÑеÑÑ'; $messages['notuploadedwarning'] = 'ÐеÑÐºÑ Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ð½Ñ Ð½Ðµ бÑло заванÑажено. ÐÑÐ´Ñ Ð»Ð°Ñка, поÑекайÑе або вÑдмÑнÑÑÑ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ.'; $messages['searchsuccessful'] = 'Ðайдено $nr лиÑÑÑв'; +$messages['contactsearchsuccessful'] = '$nr конÑакÑÑв знайдено.'; $messages['searchnomatch'] = 'ÐиÑÑÑв не знайдено'; $messages['searching'] = 'ÐоÑÑк...'; $messages['checking'] = 'ÐеÑевÑÑка...'; @@ -95,8 +102,11 @@ $messages['sourceisreadonly'] = 'Ðане джеÑело адÑÐµÑ Ð´Ð¾ÑÑÑп $messages['errorsavingcontact'] = 'Ðеможливо збеÑегÑи адÑеÑÑ ÐºÐ¾Ð½ÑакÑÑ'; $messages['movingmessage'] = 'ÐеÑемÑÑÐµÐ½Ð½Ñ Ð»Ð¸ÑÑа...'; $messages['copyingmessage'] = 'ÐопÑÑÐ²Ð°Ð½Ð½Ñ Ð»Ð¸ÑÑа...'; +$messages['copyingcontact'] = 'ÐопÑÑÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½ÑакÑÑ(Ñв)...'; $messages['deletingmessage'] = 'ÐÐ¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð»Ð¸ÑÑа (Ñв)'; $messages['markingmessage'] = 'ÐознаÑÐµÐ½Ð½Ñ Ð»Ð¸ÑÑа (Ñв)'; +$messages['addingmember'] = 'ÐÐ¾Ð´Ð°Ð½Ð½Ñ ÐºÐ¾Ð½ÑакÑÑ(Ñв) до гÑÑпи...'; +$messages['removingmember'] = 'ÐÐ¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð½ÑакÑÑ(Ñв) з гÑÑпи...'; $messages['receiptsent'] = 'ÐовÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñо пÑоÑиÑÐ°Ð½Ð½Ñ Ð²ÑдпÑавлено'; $messages['errorsendingreceipt'] = 'Ðе вдалоÑÑ Ð²ÑдпÑавиÑи повÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñо пÑоÑиÑаннÑ'; $messages['nodeletelastidentity'] = 'Ðи не можеÑе видалиÑи Ñей пÑоÑÑлÑ, вÑн Ñ ÐÐ°Ñ Ð¾ÑÑаннÑй.'; @@ -126,18 +136,27 @@ $messages['maxgroupmembersreached'] = 'ЧиÑло адÑÐµÑ Ñ Ð³ÑÑÐ¿Ñ Ð¿Ðµ $messages['internalerror'] = 'Ðиникла внÑÑÑÑÑÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. ÐÑÐ´Ñ Ð»Ð°Ñка, ÑпÑобÑйÑе Ñе Ñаз'; $messages['contactdelerror'] = 'Ðеможливо видалиÑи конÑакÑ(и)'; $messages['contactdeleted'] = 'ÐонÑакÑ(и) видалено ÑÑпÑÑно'; +$messages['contactrestoreerror'] = 'Ðеможливо вÑдновиÑи видалений(Ñ) конÑакÑ(и).'; +$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['autocompletemore'] = 'Ðнайдено багаÑо вÑдповÑÐ´Ð½Ð¸Ñ Ð·Ð°Ð¿Ð¸ÑÑв. ÐÑÐ´Ñ Ð»Ð°Ñка введÑÑÑ Ð±ÑлÑÑе ÑимволÑв.'; $messages['namecannotbeempty'] = 'ÐмâÑ Ð½Ðµ може бÑÑи пÑÑÑим'; $messages['nametoolong'] = 'ÐанадÑо довге ÑмâÑ'; $messages['folderupdated'] = 'Ðапка вÑдновлена'; $messages['foldercreated'] = 'Ðапка ÑÑвоÑена'; $messages['invalidimageformat'] = 'ÐевÑÑний ÑоÑÐ¼Ð°Ñ Ð·Ð¾Ð±ÑаженнÑ'; +$messages['mispellingsfound'] = 'Ðнайдено оÑÑогÑаÑÑÑÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¸ Ñ Ð¿Ð¾Ð²ÑдомленнÑ.'; +$messages['parentnotwritable'] = 'Ðеможливо ÑÑвоÑиÑи/пеÑемÑÑÑиÑи Ð¿Ð°Ð¿ÐºÑ Ð´Ð¾ обÑÐ°Ð½Ð¾Ñ Ð±Ð°ÑÑкÑвÑÑÐºÐ¾Ñ Ð¿Ð°Ð¿ÐºÐ¸. Ðема пÑав доÑÑÑпÑ.'; ?> diff --git a/program/localization/zh_CN/labels.inc b/program/localization/zh_CN/labels.inc index 68fd505..442f4a6 100644 --- a/program/localization/zh_CN/labels.inc +++ b/program/localization/zh_CN/labels.inc @@ -12,13 +12,16 @@ +-----------------------------------------------------------------------+ | Author: Xue zhong sheng <xue.zhongsheng@gmail.com> | | Zhang Huang bin <michaelbibby@gmail.com> | +| Kelphon Tang <kelphon@kingstor.com> | +-----------------------------------------------------------------------+ -@version $Id: labels.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: labels.inc 5569 2011-12-07 14:47:32Z thomasb $ */ $labels = array(); + +// login page $labels['welcome'] = '欢è¿ä½¿ç¨ $product'; $labels['username'] = 'ç¨æ·å'; $labels['password'] = 'å¯ç '; @@ -27,8 +30,8 @@ $labels['login'] = 'ç»å½'; // taskbar $labels['logout'] = '注é'; -$labels['mail'] = 'çµåé®ä»¶'; -$labels['settings'] = 'é®ç®±è®¾ç½®'; +$labels['mail'] = 'é®ä»¶'; +$labels['settings'] = '设置'; $labels['addressbook'] = 'é讯å½'; // mailbox names @@ -122,18 +125,16 @@ $labels['replytomessage'] = 'åå¤å件人'; $labels['replytoallmessage'] = 'å夿æ'; $labels['replyall'] = 'åå¤å ¨é¨'; $labels['replylist'] = 'åå¤å表'; +$labels['forwardinline'] = 'ç´æ¥è½¬å'; +$labels['forwardattachment'] = '以é件转å'; $labels['forwardmessage'] = '转åé®ä»¶'; $labels['deletemessage'] = 'å é¤é®ä»¶'; $labels['movemessagetotrash'] = 'ç§»å¨é®ä»¶å°åæ¶ç«'; $labels['printmessage'] = 'æå°é®ä»¶'; $labels['previousmessage'] = 'æ¾ç¤ºä¸ä¸å°é®ä»¶'; -$labels['previousmessages'] = 'ä¸ä¸é¡µ'; $labels['firstmessage'] = 'æ¾ç¤ºç¬¬ä¸å°é®ä»¶'; -$labels['firstmessages'] = '第ä¸é¡µ'; $labels['nextmessage'] = 'ä¸ä¸å°'; -$labels['nextmessages'] = 'ä¸ä¸é¡µ'; $labels['lastmessage'] = 'æåä¸å°'; -$labels['lastmessages'] = 'æåä¸é¡µ'; $labels['backtolist'] = 'è¿åé®ä»¶å表'; $labels['viewsource'] = 'æ¾ç¤ºé®ä»¶æºæä»¶'; $labels['markmessages'] = 'æ è®°é®ä»¶'; @@ -160,6 +161,7 @@ $labels['expand-all'] = 'å±å¼å ¨é¨'; $labels['expand-unread'] = 'å±å¼æªè¯»'; $labels['collapse-all'] = 'æ¶åå ¨é¨'; $labels['threaded'] = '线索'; + $labels['autoexpand_threads'] = 'å±å¼æ¶æ¯ä¸»é¢'; $labels['do_expand'] = 'ææä¸»é¢'; $labels['expand_only_unread'] = 'ä» æªè¯»æ¶æ¯'; @@ -179,16 +181,19 @@ $labels['listmode'] = 'å表è§å¾æ ·å¼'; $labels['folderactions'] = 'ç®å½æä½...'; $labels['compact'] = 'å缩'; $labels['empty'] = 'æ¸ ç©º'; -$labels['purge'] = 'æ¸ é¤'; + $labels['quota'] = 'é®ç®±å®¹é'; $labels['unknown'] = 'æªç¥'; $labels['unlimited'] = 'æ éå¶'; + $labels['quicksearch'] = 'å¿«éæ¥æ¾'; $labels['resetsearch'] = 'æ¸ ç©ºæ¥æ¾å 容'; $labels['searchmod'] = 'æå¯»æ¨¡å¼'; $labels['msgtext'] = 'æ´ä¸ªé®ä»¶'; + $labels['openinextwin'] = '卿°çªå£ä¸æå¼'; $labels['emlsave'] = 'ä¸è½½ï¼.emlï¼'; + // message compose $labels['compose'] = 'åæ°é®ä»¶'; $labels['editasnew'] = 'ç¼è¾ä¸ºæ°é®ä»¶'; @@ -199,6 +204,7 @@ $labels['charset'] = 'å符é'; $labels['editortype'] = 'ç¼è¾å¨ç±»å'; $labels['returnreceipt'] = 'é®ä»¶åæ§'; $labels['dsn'] = 'æéç¶ææç¤º'; +$labels['mailreplyintro'] = 'äº $date, $sender åå¤:'; $labels['editidents'] = 'ç¼è¾èº«ä»½'; $labels['checkspelling'] = 'æ¼åæ£æ¥'; @@ -207,6 +213,7 @@ $labels['revertto'] = 'æ¢å¤è³'; $labels['attachments'] = 'éä»¶'; $labels['upload'] = 'ä¸ä¼ '; +$labels['uploadprogress'] = '$percent ($current / $total)'; $labels['close'] = 'å ³é'; $labels['messageoptions'] = 'é®ä»¶é项...'; @@ -241,18 +248,67 @@ $labels['receiptnote'] = '注æï¼åæ§åªè¡¨ç¤ºé®ä»¶å¨æ¶ä»¶äººççµèä¸ $labels['name'] = 'æ¾ç¤ºåç§°'; $labels['firstname'] = 'åå'; $labels['surname'] = 'å§æ°'; -$labels['email'] = 'é®ä»¶å°å'; - +$labels['middlename'] = 'ä¸å'; +$labels['nameprefix'] = 'åç¼'; +$labels['namesuffix'] = 'åç¼'; +$labels['nickname'] = 'æµç§°'; +$labels['jobtitle'] = 'èä½'; +$labels['organization'] = 'å ¬å¸'; +$labels['department'] = 'é¨é¨'; +$labels['gender'] = 'Gender'; +$labels['maidenname'] = 'å¨å®¶å§'; +$labels['email'] = 'Email'; +$labels['phone'] = 'çµè¯'; +$labels['address'] = 'å°å'; +$labels['street'] = 'è¡é'; +$labels['locality'] = 'åå¸'; +$labels['zipcode'] = 'é®ç¼'; +$labels['region'] = 'ç份'; +$labels['country'] = 'å½å®¶'; +$labels['birthday'] = 'çæ¥'; +$labels['anniversary'] = '纪念æ¥'; +$labels['website'] = '主页'; +$labels['instantmessenger'] = 'QQ'; +$labels['notes'] = '夿³¨'; +$labels['male'] = 'ç·'; +$labels['female'] = '女'; +$labels['manager'] = 'ç»ç'; +$labels['assistant'] = 'å©ç'; +$labels['spouse'] = 'é å¶'; +$labels['allfields'] = 'ææé¡¹ç®'; +$labels['search'] = 'æ¥è¯¢'; +$labels['advsearch'] = 'é«çº§æ¥è¯¢'; +$labels['other'] = 'å ¶ä»'; + +$labels['typehome'] = 'å®¶åº'; +$labels['typework'] = 'å·¥ä½'; +$labels['typeother'] = 'å ¶ä»'; +$labels['typemobile'] = 'ææº'; +$labels['typemain'] = '主'; +$labels['typehomefax'] = 'å®¶åºä¼ ç'; +$labels['typeworkfax'] = 'å·¥ä½ä¼ ç'; +$labels['typecar'] = '车ç'; +$labels['typepager'] = '弿º'; +$labels['typevideo'] = 'è§é¢'; +$labels['typeassistant'] = 'å©ç'; +$labels['typehomepage'] = '主页'; +$labels['typeblog'] = 'å客'; +$labels['typeprofile'] = 'èµå'; + +$labels['addfield'] = 'å¢å 项..'; $labels['addcontact'] = 'æ·»å è系人'; $labels['editcontact'] = 'ç¼è¾è系人'; $labels['contacts'] = 'è系人'; $labels['contactproperties'] = 'è系人信æ¯'; +$labels['personalinfo'] = '个人信æ¯'; $labels['edit'] = 'ç¼è¾'; $labels['cancel'] = 'åæ¶'; $labels['save'] = 'ä¿å'; $labels['delete'] = 'å é¤'; $labels['rename'] = 'æ´å'; +$labels['addphoto'] = 'ä¸ä¼ '; +$labels['replacephoto'] = 'è¦ç'; $labels['newcontact'] = 'æ°å»ºè系人'; $labels['deletecontact'] = 'å é¤éä¸çè系人'; @@ -261,8 +317,10 @@ $labels['contactsfromto'] = '第 $from å° $to 个è系人ï¼å ± $count 个'; $labels['print'] = 'æå°'; $labels['export'] = '导åº'; $labels['exportvcards'] = '以 vCard æ ¼å¼å¯¼åºè系人'; -$labels['newcontactgroup'] = 'å建æ°çè系人ç»'; -$labels['groupactions'] = 'èç³»äººç»æä½...'; +$labels['newcontactgroup'] = 'å建æ°çç»'; +$labels['groupactions'] = 'ç»æä½...'; +$labels['grouprename'] = 'éå½åç»'; +$labels['groupdelete'] = 'å é¤ç»'; $labels['previouspage'] = 'ä¸ä¸é¡µ'; $labels['firstpage'] = '第ä¸é¡µ'; @@ -271,11 +329,12 @@ $labels['lastpage'] = 'æåä¸é¡µ'; $labels['group'] = 'åç»'; $labels['groups'] = 'åç»'; -$labels['personaladrbook'] = '个人å°å'; +$labels['personaladrbook'] = '个人é讯å½'; $labels['import'] = 'å¯¼å ¥'; $labels['importcontacts'] = 'å¯¼å ¥è系人'; $labels['importfromfile'] = 'ä»æä»¶å¯¼å ¥'; +$labels['importtarget'] = 'å¢å æ°è系人å°é讯å½:'; $labels['importreplace'] = 'æ¿æ¢æ´ä¸ªå°åç°¿'; $labels['importtext'] = 'ä½ å¯ä»¥ä»å·²æçå°åç°¿å¯¼å ¥è系人ãç®åæ¯æä» vCard æ°æ®æ ¼å¼å¯¼å ¥å°åç°¿ã'; $labels['done'] = '宿'; @@ -287,7 +346,7 @@ $labels['preferences'] = 'å好设置'; $labels['userpreferences'] = '个人å好'; $labels['editpreferences'] = 'ä¿®æ¹ä¸ªäººå好'; -$labels['identities'] = 'åé®ä»¶ç身份'; +$labels['identities'] = 'å件身份'; $labels['manageidentities'] = 'ç®¡çæ¤è´¦å·ç身份'; $labels['newidentity'] = 'æ·»å 身份'; @@ -314,7 +373,7 @@ $labels['logoutclear'] = 'éåºæ¶æ¸ ç©ºåæ¶ç«'; $labels['logoutcompact'] = 'éåºæ¶å缩æ¶ä»¶ç®±'; $labels['uisettings'] = 'ç¨æ·çé¢'; $labels['serversettings'] = 'æå¡å¨è®¾ç½®'; -$labels['mailboxview'] = 'é®ç®±æ¥çæ¹å¼'; +$labels['mailboxview'] = 'æ¾ç¤ºé®ä»¶'; $labels['mdnrequests'] = 'å件人请æ±åæ§'; $labels['askuser'] = '询é®ç¨æ·'; $labels['autosend'] = 'èªå¨åé'; @@ -334,8 +393,8 @@ $labels['everynminutes'] = 'æ¯é $n åé'; $labels['keepalive'] = 'æ£æ¥æ°é®ä»¶'; $labels['never'] = 'ä»ä¸'; $labels['immediately'] = 'ç«å³'; -$labels['messagesdisplaying'] = 'é®ä»¶æ¾ç¤ºè®¾ç½®'; -$labels['messagescomposition'] = 'åé®ä»¶'; +$labels['messagesdisplaying'] = 'æ¾ç¤ºåæ°'; +$labels['messagescomposition'] = 'æ°åé®ä»¶'; $labels['mimeparamfolding'] = 'éä»¶å'; $labels['2231folding'] = '宿´ç RFC 2231ï¼Thunderbirdï¼'; $labels['miscfolding'] = 'RFC 2047/2232ï¼MS Outlookï¼'; @@ -367,16 +426,18 @@ $labels['afternseconds'] = '$n ç§ä¹å'; $labels['reqmdn'] = 'æ»æ¯è¦æ±åæ§'; $labels['reqdsn'] = 'æ»æ¯è¦æ±æéç¶æéç¥'; $labels['replysamefolder'] = 'ä¿ååå¤é®ä»¶å°é®ä»¶ç¸åçç®å½'; +$labels['defaultaddressbook'] = 'å¢å èç³»äººå°æéé讯å½'; +$labels['spellcheckbeforesend'] = 'åé®ä»¶åè¿è¡æ¼åæ£æ¥'; -$labels['folder'] = 'é®ä»¶å¤¹'; -$labels['folders'] = 'é®ä»¶å¤¹'; +$labels['folder'] = 'ç®å½ç®¡ç'; +$labels['folders'] = 'ç®å½ç®¡ç'; $labels['foldername'] = 'é®ä»¶å¤¹åç§°'; $labels['subscribed'] = '已订é '; $labels['messagecount'] = 'é®ä»¶æ°é'; $labels['create'] = '建ç«'; $labels['createfolder'] = 'å»ºç«æ°é®ä»¶å¤¹'; $labels['managefolders'] = '管çé®ä»¶å¤¹'; -$labels['specialfolders'] = 'æå®é®ä»¶å¤¹'; +$labels['specialfolders'] = 'å®ä¹é®ä»¶å¤¹'; $labels['properties'] = '屿§'; $labels['folderproperties'] = 'æä»¶å¤¹å±æ§'; $labels['parentfolder'] = 'ç¶æä»¶å¤¹'; @@ -384,10 +445,15 @@ $labels['location'] = 'ä½ç½®'; $labels['info'] = 'ä¿¡æ¯'; $labels['getfoldersize'] = 'è·å¾æä»¶å¤¹å®¹é'; $labels['changesubscription'] = 'æ´æ¹è®¢é '; +$labels['foldertype'] = 'ç®å½ç±»å'; +$labels['personalfolder'] = 'ç§æç®å½'; +$labels['otherfolder'] = 'ä»äººç®å½'; +$labels['sharedfolder'] = 'å ±äº«ç®å½'; $labels['sortby'] = 'æåº'; $labels['sortasc'] = 'é墿åº'; $labels['sortdesc'] = 'éåæåº'; +$labels['undo'] = 'æ¤é'; // units $labels['B'] = 'B'; @@ -415,4 +481,4 @@ $labels['japanese'] = 'æ¥æ'; $labels['korean'] = 'é©è¯'; $labels['chinese'] = '䏿'; -?> +?> \ No newline at end of file diff --git a/program/localization/zh_CN/messages.inc b/program/localization/zh_CN/messages.inc index f14d1b5..28df0e5 100644 --- a/program/localization/zh_CN/messages.inc +++ b/program/localization/zh_CN/messages.inc @@ -12,9 +12,10 @@ +-----------------------------------------------------------------------+ | Author: Xue zhong sheng <xue.zhongsheng@gmail.com> | | Zhang Huang bin <michaelbibby@gmail.com> | +| Kelphon Tang <kelphon@kingstor.com> | +-----------------------------------------------------------------------+ -@version $Id: messages.inc 5067 2011-08-14 18:47:58Z thomasb $ +@version $Id: messages.inc 5569 2011-12-07 14:47:32Z thomasb $ */ @@ -25,6 +26,7 @@ $messages['sessionerror'] = 'ä¼è¯å·²è¿æ'; $messages['imaperror'] = 'è¿æ¥å°é®ä»¶æå¡å¨å¤±è´¥'; $messages['servererror'] = 'æå¡å¨é误ï¼'; $messages['servererrormsg'] = 'æå¡å¨é误: $msg'; +$messages['databaserror'] = 'æ°æ®åºé误!'; $messages['errorreadonly'] = 'ä¸å¯å¯¹åªè¯»æä»¶å¤¹è¿è¡æä½'; $messages['errornoperm'] = 'æ æéæä½'; $messages['invalidrequest'] = 'æ æç请æ±ï¼æ°æ®ä¿å失败ã'; @@ -33,6 +35,7 @@ $messages['loggedout'] = 'æ¨å·²æå注é'; $messages['mailboxempty'] = 'é®ä»¶å¤¹ä¸ºç©º'; $messages['loading'] = 'æ£å¨å è½½...'; $messages['uploading'] = 'æ£å¨ä¸ä¼ æä»¶...'; +$messages['uploadingmany'] = 'æ£å¨ä¸ä¼ å¤ä¸ªæä»¶...'; $messages['loadingdata'] = 'æ£å¨å è½½æ°æ®...'; $messages['checkingmail'] = 'æ£æ¥æ°é®ä»¶...'; $messages['sendingmessage'] = 'æ£å¨åéé®ä»¶...'; @@ -42,6 +45,7 @@ $messages['messagesaved'] = 'é®ä»¶å·²æåå°è稿箱'; $messages['successfullysaved'] = 'ä¿åæå'; $messages['addedsuccessfully'] = 'æåæ·»å è系人'; $messages['contactexists'] = 'å½åè系人ççµåé®ä»¶å°åå·²åå¨'; +$messages['contactnameexists'] = 'å·²åå¨ååçè系人.'; $messages['blockedimages'] = 'ä¸ºä¿æ¤éç§ï¼æ¤é®ä»¶ä¸çè¿ç¨å¾çæªæ¾ç¤º'; $messages['encryptedmessage'] = 'å æ¤é®ä»¶å·²å å¯ï¼æ æ³æ£å¸¸æ¾ç¤º'; $messages['nocontactsfound'] = 'æªæ¾å°è系人'; @@ -55,9 +59,11 @@ $messages['errorcopying'] = 'æ æ³å¤å¶é®ä»¶'; $messages['errordeleting'] = 'æ æ³å é¤é®ä»¶'; $messages['errormarking'] = 'æ æ³æ è®°é®ä»¶'; $messages['deletecontactconfirm'] = 'ç¡®å®è¦å é¤å·²éä¸çè系人ï¼'; +$messages['deletegroupconfirm'] = 'ç¡®å®è¦å é¤ä»¥éä¸çç»?'; $messages['deletemessagesconfirm'] = 'ç¡®å®è¦å é¤å·²éä¸çé®ä»¶ï¼'; $messages['deletefolderconfirm'] = 'ç¡®å®è¦å é¤å·²éä¸çé®ä»¶å¤¹ï¼'; $messages['purgefolderconfirm'] = 'æ¯å¦ç¡®è®¤è¦å é¤å½åé®ä»¶å¤¹ä¸çææé®ä»¶ï¼'; +$messages['groupdeleting'] = 'æ£å¨å é¤ç»...'; $messages['folderdeleting'] = 'æ£å¨å é¤é®ä»¶å¤¹'; $messages['foldermoving'] = 'æ£å¨ç§»å¨ç®å½...'; $messages['foldersubscribing'] = '注åæä»¶å¤¹ä¸...'; @@ -96,8 +102,11 @@ $messages['sourceisreadonly'] = 'æºå°å为åªè¯»'; $messages['errorsavingcontact'] = 'æ æ³ä¿åè系人çå°å'; $messages['movingmessage'] = 'ç§»å¨é®ä»¶å°...'; $messages['copyingmessage'] = 'å¤å¶é®ä»¶å°...'; +$messages['copyingcontact'] = 'å¤å¶è系人...'; $messages['deletingmessage'] = 'æ£å¨å é¤é®ä»¶...'; $messages['markingmessage'] = 'æ£å¨æ è®°é®ä»¶...'; +$messages['addingmember'] = 'æ£å¨æ·»å è系人å°ç»...'; +$messages['removingmember'] = 'æ£å¨ä»ç»ä¸å é¤è系人...'; $messages['receiptsent'] = 'æååéäºä¸ä¸ªå·²è¯»åæ§'; $messages['errorsendingreceipt'] = 'æ æ³åéåæ§'; $messages['nodeletelastidentity'] = 'æ æ³å é¤è¿ä¸ªèº«ä»½ï¼è¿æ¯æåä¸ä¸ªã'; @@ -109,6 +118,7 @@ $messages['contactremovedfromgroup'] = 'æåä»è¿ä¸ªåç»ç§»é¤è系人'; $messages['importwait'] = 'æ£å¨å¯¼å ¥ï¼è¯·ç¨å...'; $messages['importerror'] = 'å¯¼å ¥å¤±è´¥ï¼æä¸ä¼ çæä»¶ä¸æ¯ææç vCard æä»¶ã'; $messages['importconfirm'] = '<b>æåå¯¼å ¥ $inserted è系人ï¼$skipped ä¹ç¥å·²åå¨çè系人</b>:<p><em>$names</em></p>'; +$messages['importconfirmskipped'] = '<b>è·³è¿å·²åå¨ $skipped 项ç®</b>'; $messages['opnotpermitted'] = 'ä¸å 许çæä½'; $messages['nofromaddress'] = 'éç§çèº«ä»½ä¸æ²¡æé®ä»¶å°å'; $messages['editorwarning'] = '忢å°çº¯ææ¬ç¼è¾å¨å°å¯¼è´é®ä»¶æ£æä¸çææææ¬æ ¼å¼å¤±æï¼æ¨ç¡®å®è¦è¿æ ·ååï¼'; @@ -126,9 +136,11 @@ $messages['maxgroupmembersreached'] = 'ç»åæ°éè¶ è¿æå¤§å¼ $max'; $messages['internalerror'] = 'éå°ä¸ä¸ªå é¨é误ï¼è¯·éè¯'; $messages['contactdelerror'] = 'æ æ³å é¤è系人'; $messages['contactdeleted'] = 'å é¤è系人æå'; -$messages['groupdeleted'] = 'æåå é¤è系人ç»'; -$messages['grouprenamed'] = 'èç³»äººç»æ¹åæå'; -$messages['groupcreated'] = 'æåå建è系人ç»'; +$messages['contactrestoreerror'] = 'æ æ³æ¢å¤å·²å é¤çè系人.'; +$messages['contactrestored'] = 'è系人æ¢å¤æå.'; +$messages['groupdeleted'] = 'æåå é¤ç»'; +$messages['grouprenamed'] = 'ç»æ¹åæå'; +$messages['groupcreated'] = 'æåå建ç»'; $messages['messagedeleted'] = 'å é¤é®ä»¶æå'; $messages['messagemoved'] = '转移é®ä»¶æå'; $messages['messagecopied'] = 'å¤å¶é®ä»¶æå'; @@ -138,4 +150,7 @@ $messages['namecannotbeempty'] = 'å¿ é¡»è¾å ¥åå'; $messages['nametoolong'] = 'åå太é¿'; $messages['folderupdated'] = 'æåæ´æ°æä»¶å¤¹'; $messages['foldercreated'] = 'æåå建æä»¶å¤¹'; +$messages['invalidimageformat'] = 'éæ³çå¾åç±»å.'; +$messages['mispellingsfound'] = 'æ£æ¥å°æ¼åé误.'; +$messages['parentnotwritable'] = 'æ æ³å建åè½¬ç§»å°æéçç®å½,æéä¸è¶³.'; ?> diff --git a/program/steps/addressbook/copy.inc b/program/steps/addressbook/copy.inc index e07d62a..5e526e1 100644 --- a/program/steps/addressbook/copy.inc +++ b/program/steps/addressbook/copy.inc @@ -60,9 +60,9 @@ foreach ($cids as $source => $cid) // Check if contact exists, if so, we'll need it's ID // Note: Some addressbooks allows empty email address field if (!empty($a_record['email'])) - $result = $TARGET->search('email', $a_record['email'], true, true, true); + $result = $TARGET->search('email', $a_record['email'], 1, true, true); else if (!empty($a_record['name'])) - $result = $TARGET->search('name', $a_record['name'], true, true, true); + $result = $TARGET->search('name', $a_record['name'], 1, true, true); else $result = new rcube_result_set(); diff --git a/program/steps/addressbook/export.inc b/program/steps/addressbook/export.inc index a710aa2..8ba1c08 100644 --- a/program/steps/addressbook/export.inc +++ b/program/steps/addressbook/export.inc @@ -66,7 +66,6 @@ else { } // send downlaod headers -send_nocacheing_headers(); header('Content-Type: text/x-vcard; charset='.RCMAIL_CHARSET); header('Content-Disposition: attachment; filename="rcube_contacts.vcf"'); diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index c03f3e3..40a23d7 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: func.inc 5165 2011-09-05 08:49:04Z thomasb $ + $Id: func.inc 5499 2011-11-28 09:03:27Z alec $ */ @@ -227,7 +227,32 @@ function rcmail_directory_list($attrib) $out = $groupdata['out']; } - $OUTPUT->set_env('contactgroups', $jsdata); + $line_templ = html::tag('li', array( + 'id' => 'rcmliS%s', 'class' => '%s'), + html::a(array('href' => '#', 'rel' => 'S%s', + 'onclick' => "return ".JS_OBJECT_NAME.".command('listsearch', '%s', this)"), '%s')); + + // Saved searches + $sources = $RCMAIL->user->list_searches(rcube_user::SEARCH_ADDRESSBOOK); + foreach ($sources as $j => $source) { + $id = $source['id']; + $js_id = JQ($id); + + // set class name(s) + $class_name = 'contactsearch'; + if ($current === $id) + $class_name .= ' selected'; + if ($source['class_name']) + $class_name .= ' ' . $source['class_name']; + + $out .= sprintf($line_templ, + html_identifier($id), + $class_name, + $id, + $js_id, (!empty($source['name']) ? Q($source['name']) : Q($id))); + } + + $OUTPUT->set_env('contactgroups', $jsdata); $OUTPUT->add_gui_object('folderlist', $attrib['id']); // add some labels to client $OUTPUT->add_label('deletegroupconfirm', 'groupdeleting', 'addingmember', 'removingmember'); @@ -287,7 +312,7 @@ function rcmail_contacts_list($attrib) $OUTPUT->include_script('list.js'); // add some labels to client - $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact'); + $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'contactdeleting'); return $out; } @@ -383,12 +408,12 @@ function rcmail_get_rowcount_text($result=null) function rcmail_get_type_label($type) { $label = 'type'.$type; - if (rcube_label_exists($label)) - return rcube_label($label); + if (rcube_label_exists($label, '*', $domain)) + return rcube_label($label, $domain); else if (preg_match('/\w+(\d+)$/', $label, $m) && ($label = preg_replace('/(\d+)$/', '', $label)) - && rcube_label_exists($label)) - return rcube_label($label) . ' ' . $m[1]; + && rcube_label_exists($label, '*', $domain)) + return rcube_label($label, $domain) . ' ' . $m[1]; return ucfirst($type); } @@ -397,6 +422,7 @@ function rcmail_get_type_label($type) function rcmail_contact_form($form, $record, $attrib = null) { global $RCMAIL, $CONFIG; + static $jqueryui_loaded = 0; // Allow plugins to modify contact form content $plugin = $RCMAIL->plugins->exec_hook('contact_form', array( @@ -583,6 +609,19 @@ function rcmail_contact_form($form, $record, $attrib = null) if ($colprop['subtypes'] || $colprop['limit'] != 1) $colprop['array'] = true; + // load jquery UI datepickert for date fields + if ($colprop['type'] == 'date') { + if (!$jqueryui_loaded++) { + $RCMAIL->plugins->load_plugin('jqueryui'); + $RCMAIL->output->set_env('date_format', strtr($RCMAIL->config->get('date_format', 'Y-m-d'), array('y'=>'y', 'Y'=>'yy', 'm'=>'mm', 'n'=>'m', 'd'=>'dd', 'j'=>'d'))); + foreach (array('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec') as $month) + $month_names[] = rcube_label($month); + $RCMAIL->output->set_env('month_names', $month_names); + } + $colprop['class'] .= ($colprop['class'] ? ' ' : '') . 'datepicker'; + $val = format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false); + } + $val = rcmail_get_edit_field($col, $val, $colprop, $colprop['type']); $coltypes[$field]['count']++; } @@ -618,11 +657,16 @@ function rcmail_contact_form($form, $record, $attrib = null) } // wrap rows in fieldgroup container - $content .= html::tag('fieldset', array('class' => 'contactfieldgroup ' . ($colprop['subtypes'] ? 'contactfieldgroupmulti ' : '') . 'contactcontroller' . $col, 'style' => ($rows ? null : 'display:none')), - ($colprop['subtypes'] ? html::tag('legend', null, Q($colprop['label'])) : ' ') . - $rows); + if ($rows) { + $content .= html::tag('fieldset', array('class' => 'contactfieldgroup ' . ($colprop['subtypes'] ? 'contactfieldgroupmulti ' : '') . 'contactcontroller' . $col, 'style' => ($rows ? null : 'display:none')), + ($colprop['subtypes'] ? html::tag('legend', null, Q($colprop['label'])) : ' ') . + $rows); + } } + if (!$content) + continue; + // also render add-field selector if ($edit_mode) $content .= html::p('addfield', $select_add->show(null, array('style' => $select_add->_count ? null : 'display:none'))); @@ -633,7 +677,8 @@ function rcmail_contact_form($form, $record, $attrib = null) $content = $fieldset['content']; } - $out .= html::tag('fieldset', null, html::tag('legend', null, Q($fieldset['name'])) . $content) ."\n"; + if ($content) + $out .= html::tag('fieldset', null, html::tag('legend', null, Q($fieldset['name'])) . $content) ."\n"; } if ($edit_mode) { @@ -660,7 +705,7 @@ function rcmail_contact_photo($attrib) $RCMAIL->output->set_env('photo_placeholder', $photo_img); unset($attrib['placeholder']); - if (strpos($record['photo'], 'http:') === 0) + if (preg_match('!^https?://!i', $record['photo'])) $photo_img = $record['photo']; else if ($record['photo']) $photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID)); @@ -683,7 +728,7 @@ function rcmail_contact_photo($attrib) function rcmail_format_date_col($val) { global $RCMAIL; - return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d')); + return format_date($val, $RCMAIL->config->get('date_format', 'Y-m-d'), false); } @@ -713,9 +758,12 @@ function rcmail_get_cids() foreach ($cid as $id) { // if _source is not specified we'll find it from decoded ID if (!$got_source) { - list ($c, $s) = explode('-', $id, 2); - if (strlen($s)) { - $result[(string)$s][] = $c; + if ($sep = strrpos($id, '-')) { + $contact_id = substr($id, 0, $sep); + $source_id = substr($id, $sep+1); + if (strlen($source_id)) { + $result[(string)$source_id][] = $contact_id; + } } } else { @@ -745,4 +793,6 @@ $RCMAIL->register_action_map(array( 'group-delete' => 'groups.inc', 'group-addmembers' => 'groups.inc', 'group-delmembers' => 'groups.inc', + 'search-create' => 'search.inc', + 'search-delete' => 'search.inc', )); diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 1b9aea1..63a6dae 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -174,9 +174,9 @@ if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name' if (!$replace && $email) { // compare e-mail address - $existing = $CONTACTS->search('email', $email, false, false); + $existing = $CONTACTS->search('email', $email, 1, false); if (!$existing->count && $vcard->displayname) { // compare display name - $existing = $CONTACTS->search('name', $vcard->displayname, false, false); + $existing = $CONTACTS->search('name', $vcard->displayname, 1, false); } if ($existing->count) { $IMPORT_STATS->skipped++; diff --git a/program/steps/addressbook/list.inc b/program/steps/addressbook/list.inc index ab82faf..6b00a82 100644 --- a/program/steps/addressbook/list.inc +++ b/program/steps/addressbook/list.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: list.inc 4850 2011-06-14 13:45:26Z alec $ + $Id: list.inc 5315 2011-10-06 12:31:38Z thomasb $ */ @@ -73,6 +73,11 @@ else { // get contacts for this user $result = $CONTACTS->list_records(array('name')); + + if (!$result->count && $result->searchonly) { + $OUTPUT->show_message('contactsearchonly', 'notice'); + $OUTPUT->command('command', 'advanced-search'); + } } // update message count display diff --git a/program/steps/addressbook/mailto.inc b/program/steps/addressbook/mailto.inc index 5996b9d..c40ecdf 100644 --- a/program/steps/addressbook/mailto.inc +++ b/program/steps/addressbook/mailto.inc @@ -21,6 +21,7 @@ $cids = rcmail_get_cids(); $mailto = array(); +$recipients = null; foreach ($cids as $source => $cid) { @@ -30,12 +31,35 @@ foreach ($cids as $source => $cid) { $CONTACTS->set_page(1); $CONTACTS->set_pagesize(count($cid) + 2); // +2 to skip counting query - $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, false, true, true, 'email'); + $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, 0, true, true, 'email'); + } +} + +if (!empty($_REQUEST['_gid']) && isset($_REQUEST['_source'])) +{ + $source = get_input_value('_source', RCUBE_INPUT_GPC); + $CONTACTS = $RCMAIL->get_address_book($source); + + $group_id = get_input_value('_gid', RCUBE_INPUT_GPC); + $group_data = $CONTACTS->get_group($group_id); + + // group has an email address assigned: use that + if ($group_data['email']) { + $mailto[] = format_email_recipient($group_data['email'][0], $group_data['name']); + } + else if ($CONTACTS->ready) { + $CONTACTS->set_group($group_id); + $CONTACTS->set_page(1); + $CONTACTS->set_pagesize(200); // limit somehow + $recipients = $CONTACTS->list_records(); + } +} - while (is_object($recipients) && ($rec = $recipients->iterate())) { - $emails = $CONTACTS->get_col_values('email', $rec, true); - $mailto[] = format_email_recipient($emails[0], $rec['name']); - } +if ($recipients) +{ + while (is_object($recipients) && ($rec = $recipients->iterate())) { + $emails = $CONTACTS->get_col_values('email', $rec, true); + $mailto[] = format_email_recipient($emails[0], $rec['name']); } } diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc index ef4387a..d573b0e 100644 --- a/program/steps/addressbook/save.inc +++ b/program/steps/addressbook/save.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: save.inc 5130 2011-08-25 08:30:01Z alec $ + $Id: save.inc 5541 2011-12-04 17:05:42Z thomasb $ */ @@ -50,10 +50,12 @@ foreach ($GLOBALS['CONTACT_COLTYPES'] as $col => $colprop) { foreach ((array)$vals as $i => $val) $values[$i][$childcol] = $val; } - $subtypes = get_input_value('_subtype_' . $col, RCUBE_INPUT_POST); - foreach ($subtypes as $i => $subtype) + $subtypes = isset($_REQUEST['_subtype_' . $col]) ? (array)get_input_value('_subtype_' . $col, RCUBE_INPUT_POST) : array(''); + foreach ($subtypes as $i => $subtype) { + $suffix = $subtype ? ':'.$subtype : ''; if ($values[$i]) - $a_record[$col.':'.$subtype][] = $values[$i]; + $a_record[$col.$suffix][] = $values[$i]; + } } // assign values and subtypes else if (is_array($_POST[$fname])) { @@ -162,7 +164,7 @@ else { // show notice if existing contacts with same e-mail are found $existing = false; foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) { - if ($email && ($res = $CONTACTS->search('email', $email, false, false, true)) && $res->count) { + if ($email && ($res = $CONTACTS->search('email', $email, 1, false, true)) && $res->count) { $OUTPUT->show_message('contactexists', 'notice', null, false); break; } diff --git a/program/steps/addressbook/search.inc b/program/steps/addressbook/search.inc index 352556d..643cc60 100644 --- a/program/steps/addressbook/search.inc +++ b/program/steps/addressbook/search.inc @@ -21,6 +21,63 @@ */ +if ($RCMAIL->action == 'search-create') { + $id = get_input_value('_search', RCUBE_INPUT_POST); + $name = get_input_value('_name', RCUBE_INPUT_POST, true); + + if (($params = $_SESSION['search_params']) && $params['id'] == $id) { + + $data = array( + 'type' => rcube_user::SEARCH_ADDRESSBOOK, + 'name' => $name, + 'data' => array( + 'fields' => $params['data'][0], + 'search' => $params['data'][1], + ), + ); + + $plugin = $RCMAIL->plugins->exec_hook('saved_search_create', array('data' => $data)); + + if (!$plugin['abort']) + $result = $RCMAIL->user->insert_search($plugin['data']); + else + $result = $plugin['result']; + } + + if ($result) { + $OUTPUT->show_message('savedsearchcreated', 'confirmation'); + $OUTPUT->command('insert_saved_search', Q($name), Q($result)); + } + else + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'savedsearchcreateerror', 'error'); + + $OUTPUT->send(); +} + +if ($RCMAIL->action == 'search-delete') { + $id = get_input_value('_sid', RCUBE_INPUT_POST); + + $plugin = $RCMAIL->plugins->exec_hook('saved_search_delete', array('id' => $id)); + + if (!$plugin['abort']) + $result = $RCMAIL->user->delete_search($id); + else + $result = $plugin['result']; + + if ($result) { + $OUTPUT->show_message('savedsearchdeleted', 'confirmation'); + $OUTPUT->command('remove_search_item', Q($id)); + // contact list will be cleared, clear also page counter + $OUTPUT->command('set_rowcount', rcube_label('nocontactsfound')); + $OUTPUT->set_env('pagecount', 0); + } + else + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'savedsearchdeleteerror', 'error'); + + $OUTPUT->send(); +} + + if (!isset($_GET['_form'])) { rcmail_contact_search(); } @@ -34,9 +91,15 @@ function rcmail_contact_search() global $RCMAIL, $OUTPUT, $CONFIG, $SEARCH_MODS_DEFAULT; $adv = isset($_POST['_adv']); + $sid = get_input_value('_sid', RCUBE_INPUT_GET); + // get search criteria from saved search + if ($sid && ($search = $RCMAIL->user->get_search($sid))) { + $fields = $search['data']['fields']; + $search = $search['data']['search']; + } // get fields/values from advanced search form - if ($adv) { + else if ($adv) { foreach (array_keys($_POST) as $key) { $s = trim(get_input_value($key, RCUBE_INPUT_POST, true)); if (strlen($s) && preg_match('/^_search_([a-zA-Z0-9_-]+)$/', $key, $m)) { @@ -74,6 +137,9 @@ function rcmail_contact_search() } } + // Values matching mode + $mode = (int) $RCMAIL->config->get('addressbook_search_mode'); + // get sources list $sources = $RCMAIL->get_address_sources(); $search_set = array(); @@ -105,7 +171,7 @@ function rcmail_contact_search() $source->set_pagesize(9999); // get contacts count - $result = $source->search($fields, $search, false, false); + $result = $source->search($fields, $search, $mode, false); if (!$result->count) { continue; @@ -145,6 +211,7 @@ function rcmail_contact_search() // save search settings in session $_SESSION['search'][$search_request] = $search_set; + $_SESSION['search_params'] = array('id' => $search_request, 'data' => array($fields, $search)); $_SESSION['page'] = 1; if ($adv) @@ -153,6 +220,7 @@ function rcmail_contact_search() if ($result->count > 0) { // create javascript list rcmail_js_contacts_list($result); + $OUTPUT->show_message('contactsearchsuccessful', 'confirmation', array('nr' => $result->count)); } else { $OUTPUT->show_message('nocontactsfound', 'notice'); @@ -162,9 +230,14 @@ function rcmail_contact_search() $OUTPUT->command('set_env', 'search_request', $search_request); $OUTPUT->command('set_env', 'pagecount', ceil($result->count / $CONFIG['pagesize'])); $OUTPUT->command('set_rowcount', rcmail_get_rowcount_text($result)); + // Re-set current source + $OUTPUT->command('set_env', 'search_id', $sid); + $OUTPUT->command('set_env', 'source', ''); + $OUTPUT->command('set_env', 'group', ''); // unselect currently selected directory/group - $OUTPUT->command('unselect_directory'); + if (!$sid) + $OUTPUT->command('unselect_directory'); $OUTPUT->command('update_group_commands'); // send response diff --git a/program/steps/addressbook/upload_photo.inc b/program/steps/addressbook/upload_photo.inc index bd9b839..6aeaea6 100644 --- a/program/steps/addressbook/upload_photo.inc +++ b/program/steps/addressbook/upload_photo.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: upload_photo.inc 5130 2011-08-25 08:30:01Z alec $ + $Id: upload_photo.inc 5110 2011-08-22 14:33:02Z alec $ */ diff --git a/program/steps/mail/addcontact.inc b/program/steps/mail/addcontact.inc index 4df3a78..5b77b56 100644 --- a/program/steps/mail/addcontact.inc +++ b/program/steps/mail/addcontact.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: addcontact.inc 4933 2011-07-18 16:57:15Z thomasb $ + $Id: addcontact.inc 5415 2011-11-11 15:04:45Z alec $ */ @@ -50,7 +50,7 @@ if (!empty($_POST['_address']) && is_object($CONTACTS)) $OUTPUT->show_message('errorsavingcontact', 'error'); $OUTPUT->send(); } - + $email = rcube_idn_to_ascii($contact['email']); if (!check_email($email, false)) { $OUTPUT->show_message('emailformaterror', 'error', array('email' => $contact['email'])); @@ -60,8 +60,18 @@ if (!empty($_POST['_address']) && is_object($CONTACTS)) $contact['email'] = rcube_idn_to_utf8($contact['email']); $contact['name'] = rcube_addressbook::compose_display_name($contact); + // validate contact record + if (!$CONTACTS->validate($contact, true)) { + $error = $CONTACTS->get_error(); + // TODO: show dialog to complete record + // if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { } + + $OUTPUT->show_message($error['message'] ? $error['message'] : 'errorsavingcontact', 'error'); + $OUTPUT->send(); + } + // check for existing contacts - $existing = $CONTACTS->search('email', $contact['email'], true, false); + $existing = $CONTACTS->search('email', $contact['email'], 1, false); if ($done = $existing->count) $OUTPUT->show_message('contactexists', 'warning'); diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc index a5bc21f..3a85fa5 100644 --- a/program/steps/mail/attachments.inc +++ b/program/steps/mail/attachments.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: attachments.inc 5229 2011-09-16 19:13:27Z thomasb $ + $Id: attachments.inc 5543 2011-12-05 07:24:36Z alec $ */ @@ -25,9 +25,12 @@ if (!empty($_GET['_progress'])) { } $COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GPC); -$_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; +$COMPOSE = null; -if (!$_SESSION['compose']) { +if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID]) + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; + +if (!$COMPOSE) { die("Invalid session var!"); } @@ -38,15 +41,15 @@ if ($RCMAIL->action=='remove-attachment') $id = 'undefined'; if (preg_match('/^rcmfile(\w+)$/', $_POST['_file'], $regs)) $id = $regs[1]; - if ($attachment = $_SESSION['compose']['attachments'][$id]) + if ($attachment = $COMPOSE['attachments'][$id]) $attachment = $RCMAIL->plugins->exec_hook('attachment_delete', $attachment); if ($attachment['status']) { - if (is_array($_SESSION['compose']['attachments'][$id])) { - unset($_SESSION['compose']['attachments'][$id]); + if (is_array($COMPOSE['attachments'][$id])) { + unset($COMPOSE['attachments'][$id]); $OUTPUT->command('remove_from_attachment_list', "rcmfile$id"); } } - + $OUTPUT->send(); exit; } @@ -56,16 +59,16 @@ if ($RCMAIL->action=='display-attachment') $id = 'undefined'; if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs)) $id = $regs[1]; - if ($attachment = $_SESSION['compose']['attachments'][$id]) + if ($attachment = $COMPOSE['attachments'][$id]) $attachment = $RCMAIL->plugins->exec_hook('attachment_display', $attachment); - + if ($attachment['status']) { if (empty($attachment['size'])) $attachment['size'] = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']); header('Content-Type: ' . $attachment['mimetype']); header('Content-Length: ' . $attachment['size']); - + if ($attachment['data']) echo $attachment['data']; else if ($attachment['path']) @@ -76,8 +79,8 @@ if ($RCMAIL->action=='display-attachment') // attachment upload action -if (!is_array($_SESSION['compose']['attachments'])) { - $_SESSION['compose']['attachments'] = array(); +if (!is_array($COMPOSE['attachments'])) { + $COMPOSE['attachments'] = array(); } // clear all stored output properties (like scripts and env vars) @@ -107,9 +110,9 @@ if (is_array($_FILES['_attachments']['tmp_name'])) { // store new attachment in session unset($attachment['status'], $attachment['abort']); - $_SESSION['compose']['attachments'][$id] = $attachment; + $COMPOSE['attachments'][$id] = $attachment; - if (($icon = $_SESSION['compose']['deleteicon']) && is_file($icon)) { + if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) { $button = html::img(array( 'src' => $icon, 'alt' => rcube_label('delete') diff --git a/program/steps/mail/autocomplete.inc b/program/steps/mail/autocomplete.inc index d92f108..7769ec8 100644 --- a/program/steps/mail/autocomplete.inc +++ b/program/steps/mail/autocomplete.inc @@ -5,7 +5,8 @@ | program/steps/mail/autocomplete.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2010, Roundcube Dev Team | + | Copyright (C) 2008-2011, Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -15,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: autocomplete.inc 4963 2011-07-25 10:49:39Z alec $ + $Id: autocomplete.inc 5426 2011-11-15 10:50:30Z alec $ */ @@ -31,14 +32,17 @@ if ($RCMAIL->action == 'group-expand') { $members[] = format_email_recipient($email, $sql_arr['name']); } - $OUTPUT->command('replace_group_recipients', $gid, join(', ', $members)); + $separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' '; + $OUTPUT->command('replace_group_recipients', $gid, join($separator, array_unique($members))); } $OUTPUT->send(); } -$MAXNUM = (int)$RCMAIL->config->get('autocomplete_max', 15); +$MAXNUM = (int) $RCMAIL->config->get('autocomplete_max', 15); +$mode = (int) $RCMAIL->config->get('addressbook_search_mode'); +$single = (bool) $RCMAIL->config->get('autocomplete_single'); $search = get_input_value('_search', RCUBE_INPUT_GPC, true); $source = get_input_value('_source', RCUBE_INPUT_GPC); $sid = get_input_value('_id', RCUBE_INPUT_GPC); @@ -49,45 +53,73 @@ else $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); if (!empty($book_types) && strlen($search)) { - $contacts = array(); + $contacts = array(); + $sort_keys = array(); $books_num = count($book_types); + $search_lc = mb_strtolower($search); foreach ($book_types as $id) { $abook = $RCMAIL->get_address_book($id); $abook->set_pagesize($MAXNUM); - if ($result = $abook->search(array('email','name'), $search, false, true, true, 'email')) { + if ($result = $abook->search(array('email','name'), $search, $mode, true, true, 'email')) { while ($sql_arr = $result->iterate()) { // Contact can have more than one e-mail address $email_arr = (array)$abook->get_col_values('email', $sql_arr, true); $email_cnt = count($email_arr); + $idx = 0; foreach ($email_arr as $email) { - if (empty($email)) + if (empty($email)) { continue; + } + $contact = format_email_recipient($email, $sql_arr['name']); + // skip entries that don't match - if ($email_cnt > 1 && stripos($contact, $search) === false) { + if ($email_cnt > 1 && strpos(mb_strtolower($contact), $search_lc) === false) { continue; } - // when we've got more than one book, we need to skip duplicates - if ($books_num == 1 || !in_array($contact, $contacts)) { - $contacts[] = $contact; + + // skip duplicates + if (!in_array($contact, $contacts)) { + $contacts[] = $contact; + $sort_keys[] = sprintf('%s %03d', $sql_arr['name'] , $idx++); + if (count($contacts) >= $MAXNUM) break 2; } + + // skip redundant entries (show only first email address) + if ($single) { + break; + } } } } // also list matching contact groups - if ($abook->groups) { + if ($abook->groups && count($contacts) < $MAXNUM) { foreach ($abook->list_groups($search) as $group) { $abook->reset(); $abook->set_group($group['ID']); - $result = $abook->count(); + $group_prop = $abook->get_group($group['ID']); + + // group (distribution list) with email address(es) + if ($group_prop['email']) { + $idx = 0; + foreach ((array)$group_prop['email'] as $email) { + $contacts[] = format_email_recipient($email, $group['name']); + $sort_keys[] = sprintf('%s %03d', $group['name'] , $idx++); + + if (count($contacts) >= $MAXNUM) + break 2; + } + } + // show group with count + else if (($result = $abook->count()) && $result->count) { + $contacts[] = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id); + $sort_keys[] = $group['name']; - if ($result->count) { - $contacts[] = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id); if (count($contacts) >= $MAXNUM) break; } @@ -95,17 +127,16 @@ if (!empty($book_types) && strlen($search)) { } } - usort($contacts, 'contact_results_sort'); + if (count($contacts)) { + // sort contacts index + asort($sort_keys, SORT_LOCALE_STRING); + // re-sort contacts according to index + foreach ($sort_keys as $idx => $val) { + $sort_keys[$idx] = $contacts[$idx]; + } + $contacts = array_values($sort_keys); + } } $OUTPUT->command('ksearch_query_results', $contacts, $search, $sid); $OUTPUT->send(); - - -function contact_results_sort($a, $b) -{ - $name_a = is_array($a) ? $a['name'] : $a; - $name_b = is_array($b) ? $b['name'] : $b; - return strcoll(trim($name_a, '" '), trim($name_b, '" ')); -} - diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index f3c9be0..3b6b4ec 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: check_recent.inc 4872 2011-06-22 05:52:48Z thomasb $ + $Id: check_recent.inc 5266 2011-09-22 07:49:33Z alec $ */ @@ -34,10 +34,24 @@ else { // check recent/unseen counts foreach ($a_mailboxes as $mbox_name) { - if ($mbox_name == $current && ($status = $IMAP->mailbox_status($mbox_name))) { + $is_current = $mbox_name == $current; + if ($is_current) { + // Synchronize mailbox cache, handle flag changes + $IMAP->mailbox_sync($mbox_name); + } + + // Get mailbox status + $status = $IMAP->mailbox_status($mbox_name); + + if ($status & 1) { + // trigger plugin hook + $RCMAIL->plugins->exec_hook('new_messages', + array('mailbox' => $mbox_name, 'is_current' => $is_current)); + } - rcmail_send_unread_count($mbox_name, true); + rcmail_send_unread_count($mbox_name, true); + if ($status && $is_current) { // refresh saved search set $search_request = get_input_value('_search', RCUBE_INPUT_GPC); if ($search_request && isset($_SESSION['search']) @@ -67,14 +81,9 @@ foreach ($a_mailboxes as $mbox_name) { $OUTPUT->set_env('messagecount', $all_count); $OUTPUT->set_env('pagecount', ceil($all_count/$IMAP->page_size)); - $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($all_count)); + $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($all_count), $mbox_name); $OUTPUT->set_env('current_page', $all_count ? $IMAP->list_page : 1); - if ($status & 1) { - // trigger plugin hook - $RCMAIL->plugins->exec_hook('new_messages', array('mailbox' => $mbox_name)); - } - // remove old rows (and clear selection if new list is empty) $OUTPUT->command('message_list.clear', $all_count ? false : true); @@ -86,9 +95,6 @@ foreach ($a_mailboxes as $mbox_name) { $OUTPUT->command('update_selection'); } } - else { - rcmail_send_unread_count($mbox_name, true); - } } $RCMAIL->plugins->exec_hook('keep_alive', array()); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 8c60a7e..ca10898 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -5,7 +5,7 @@ | program/steps/mail/compose.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2009, The Roundcube Dev Team | + | Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: compose.inc 5281 2011-09-27 07:29:49Z alec $ + $Id: compose.inc 5545 2011-12-05 12:59:21Z thomasb $ */ @@ -25,15 +25,26 @@ define('RCUBE_COMPOSE_FORWARD', 0x0107); define('RCUBE_COMPOSE_DRAFT', 0x0108); define('RCUBE_COMPOSE_EDIT', 0x0109); -$MESSAGE_FORM = NULL; -$MESSAGE = NULL; - -$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); -$_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; +$MESSAGE_FORM = null; +$MESSAGE = null; +$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); +$COMPOSE = null; + +if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID]) + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; + +// give replicated session storage some time to synchronize +$retries = 0; +while ($COMPOSE_ID && !is_array($COMPOSE) && $RCMAIL->db->is_replicated() && $retries++ < 5) { + usleep(500000); + $RCMAIL->session->reload(); + if ($_SESSION['compose_data_'.$COMPOSE_ID]) + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; +} // Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or // if a compose-ID is given (i.e. when the compose step is opened in a new window/tab). -if (!is_array($_SESSION['compose'])) +if (!is_array($COMPOSE)) { // Infinite redirect prevention in case of broken session (#1487028) if ($COMPOSE_ID) @@ -41,31 +52,33 @@ if (!is_array($_SESSION['compose'])) 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid compose ID"), true, true); - $_SESSION['compose'] = array( - 'id' => uniqid(mt_rand()), - 'param' => request2param(RCUBE_INPUT_GET), + $COMPOSE_ID = uniqid(mt_rand()); + $_SESSION['compose_data_'.$COMPOSE_ID] = array( + 'id' => $COMPOSE_ID, + 'param' => request2param(RCUBE_INPUT_GET), 'mailbox' => $IMAP->get_mailbox_name(), ); + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; // process values like "mailto:foo@bar.com?subject=new+message&cc=another" - if ($_SESSION['compose']['param']['to']) { + if ($COMPOSE['param']['to']) { // #1486037: remove "mailto:" prefix - $_SESSION['compose']['param']['to'] = preg_replace('/^mailto:/i', '', $_SESSION['compose']['param']['to']); - $mailto = explode('?', $_SESSION['compose']['param']['to']); + $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $COMPOSE['param']['to']); + $mailto = explode('?', $COMPOSE['param']['to']); if (count($mailto) > 1) { - $_SESSION['compose']['param']['to'] = $mailto[0]; + $COMPOSE['param']['to'] = $mailto[0]; parse_str($mailto[1], $query); foreach ($query as $f => $val) - $_SESSION['compose']['param'][$f] = $val; + $COMPOSE['param'][$f] = $val; } } // select folder where to save the sent message - $_SESSION['compose']['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); + $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); // pipe compose parameters thru plugins - $plugin = $RCMAIL->plugins->exec_hook('message_compose', $_SESSION['compose']); - $_SESSION['compose']['param'] = array_merge($_SESSION['compose']['param'], $plugin['param']); + $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE); + $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']); // add attachments listed by message_compose hook if (is_array($plugin['attachments'])) { @@ -92,18 +105,18 @@ if (!is_array($_SESSION['compose'])) if ($attachment['status'] && !$attachment['abort']) { unset($attachment['data'], $attachment['status'], $attachment['abort']); - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; } } } // check if folder for saving sent messages exists and is subscribed (#1486802) - if ($sent_folder = $_SESSION['compose']['param']['sent_mbox']) { + if ($sent_folder = $COMPOSE['param']['sent_mbox']) { rcmail_check_sent_folder($sent_folder, true); } // redirect to a unique URL with all parameters stored in session - $OUTPUT->redirect(array('_action' => 'compose', '_id' => $_SESSION['compose']['id'])); + $OUTPUT->redirect(array('_action' => 'compose', '_id' => $COMPOSE['id'])); } @@ -111,9 +124,9 @@ if (!is_array($_SESSION['compose'])) $OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubjectwarning', 'cancel', 'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage', 'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany', - 'fileuploaderror'); + 'fileuploaderror', 'sendmessage'); -$OUTPUT->set_env('compose_id', $COMPOSE_ID); +$OUTPUT->set_env('compose_id', $COMPOSE['id']); // add config parameters to client script if (!empty($CONFIG['drafts_mbox'])) { @@ -122,19 +135,23 @@ if (!empty($CONFIG['drafts_mbox'])) { } // set current mailbox in client environment $OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name()); -$OUTPUT->set_env('sig_above', $CONFIG['sig_above']); -$OUTPUT->set_env('top_posting', $CONFIG['top_posting']); +$OUTPUT->set_env('sig_above', $RCMAIL->config->get('sig_above', false)); +$OUTPUT->set_env('top_posting', $RCMAIL->config->get('top_posting', false)); +$OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); + +// use jquery UI for showing prompt() dialogs +$RCMAIL->plugins->load_plugin('jqueryui'); // get reference message and set compose mode -if ($msg_uid = $_SESSION['compose']['param']['draft_uid']) { +if ($msg_uid = $COMPOSE['param']['draft_uid']) { $RCMAIL->imap->set_mailbox($CONFIG['drafts_mbox']); $compose_mode = RCUBE_COMPOSE_DRAFT; } -else if ($msg_uid = $_SESSION['compose']['param']['reply_uid']) +else if ($msg_uid = $COMPOSE['param']['reply_uid']) $compose_mode = RCUBE_COMPOSE_REPLY; -else if ($msg_uid = $_SESSION['compose']['param']['forward_uid']) +else if ($msg_uid = $COMPOSE['param']['forward_uid']) $compose_mode = RCUBE_COMPOSE_FORWARD; -else if ($msg_uid = $_SESSION['compose']['param']['uid']) +else if ($msg_uid = $COMPOSE['param']['uid']) $compose_mode = RCUBE_COMPOSE_EDIT; $config_show_sig = $RCMAIL->config->get('show_sig', 1); @@ -156,30 +173,30 @@ if (!empty($msg_uid)) // 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 - if ($MESSAGE && $MESSAGE->headers && !$MESSAGE->headers->seen) + if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN'])) $IMAP->set_flag($msg_uid, 'SEEN'); if (!empty($MESSAGE->headers->charset)) $IMAP->set_charset($MESSAGE->headers->charset); - + if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $_SESSION['compose']['reply_uid'] = $msg_uid; - $_SESSION['compose']['reply_msgid'] = $MESSAGE->headers->messageID; - $_SESSION['compose']['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); + $COMPOSE['reply_uid'] = $msg_uid; + $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; + $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); - if (!empty($_SESSION['compose']['param']['all'])) - $MESSAGE->reply_all = $_SESSION['compose']['param']['all']; + if (!empty($COMPOSE['param']['all'])) + $MESSAGE->reply_all = $COMPOSE['param']['all']; $OUTPUT->set_env('compose_mode', 'reply'); // Save the sent message in the same folder of the message being replied to - if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $_SESSION['compose']['mailbox']) + if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) && rcmail_check_sent_folder($sent_folder, false) ) { - $_SESSION['compose']['param']['sent_mbox'] = $sent_folder; + $COMPOSE['param']['sent_mbox'] = $sent_folder; } } else if ($compose_mode == RCUBE_COMPOSE_DRAFT) @@ -190,31 +207,31 @@ if (!empty($msg_uid)) $info = rcmail_draftinfo_decode($MESSAGE->headers->others['x-draft-info']); if ($info['type'] == 'reply') - $_SESSION['compose']['reply_uid'] = $info['uid']; + $COMPOSE['reply_uid'] = $info['uid']; else if ($info['type'] == 'forward') - $_SESSION['compose']['forward_uid'] = $info['uid']; + $COMPOSE['forward_uid'] = $info['uid']; - $_SESSION['compose']['mailbox'] = $info['folder']; + $COMPOSE['mailbox'] = $info['folder']; // Save the sent message in the same folder of the message being replied to if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder']) && rcmail_check_sent_folder($sent_folder, false) ) { - $_SESSION['compose']['param']['sent_mbox'] = $sent_folder; + $COMPOSE['param']['sent_mbox'] = $sent_folder; } } if ($MESSAGE->headers->in_reply_to) - $_SESSION['compose']['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; + $COMPOSE['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; - $_SESSION['compose']['references'] = $MESSAGE->headers->references; + $COMPOSE['references'] = $MESSAGE->headers->references; } else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $_SESSION['compose']['forward_uid'] = $msg_uid; + $COMPOSE['forward_uid'] = $msg_uid; $OUTPUT->set_env('compose_mode', 'forward'); - if (!empty($_SESSION['compose']['param']['attachment'])) + if (!empty($COMPOSE['param']['attachment'])) $MESSAGE->forward_attachment = true; } } @@ -238,8 +255,8 @@ if (count($MESSAGE->identities)) if (!empty($_POST['_from'])) { $MESSAGE->compose['from'] = get_input_value('_from', RCUBE_INPUT_POST); } -else if (!empty($_SESSION['compose']['param']['from'])) { - $MESSAGE->compose['from'] = $_SESSION['compose']['param']['from']; +else if (!empty($COMPOSE['param']['from'])) { + $MESSAGE->compose['from'] = $COMPOSE['param']['from']; } else if (count($MESSAGE->identities)) { $a_recipients = array(); @@ -324,23 +341,28 @@ else if (count($MESSAGE->identities)) { // Set other headers $a_recipients = array(); $parts = array('to', 'cc', 'bcc', 'replyto', 'followupto'); +$separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' '; foreach ($parts as $header) { $fvalue = ''; $decode_header = true; // we have a set of recipients stored is session - if ($header == 'to' && ($mailto_id = $_SESSION['compose']['param']['mailto']) + if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto']) && $_SESSION['mailto'][$mailto_id] ) { $fvalue = urldecode($_SESSION['mailto'][$mailto_id]); $decode_header = false; + + // make session to not grow up too much + unset($_SESSION['mailto'][$mailto_id]); + $COMPOSE['param']['to'] = $fvalue; } else if (!empty($_POST['_'.$header])) { $fvalue = get_input_value('_'.$header, RCUBE_INPUT_POST, TRUE); } - else if (!empty($_SESSION['compose']['param'][$header])) { - $fvalue = $_SESSION['compose']['param'][$header]; + else if (!empty($COMPOSE['param'][$header])) { + $fvalue = $COMPOSE['param'][$header]; } else if ($compose_mode == RCUBE_COMPOSE_REPLY) { // get recipent address(es) out of the message headers @@ -348,11 +370,13 @@ foreach ($parts as $header) { $mailfollowup = $MESSAGE->headers->others['mail-followup-to']; $mailreplyto = $MESSAGE->headers->others['mail-reply-to']; + // Reply to mailing list... if ($MESSAGE->reply_all == 'list' && $mailfollowup) $fvalue = $mailfollowup; else if ($MESSAGE->reply_all == 'list' && preg_match('/<mailto:([^>]+)>/i', $MESSAGE->headers->others['list-post'], $m)) $fvalue = $m[1]; + // Reply to... else if ($MESSAGE->reply_all && $mailfollowup) $fvalue = $mailfollowup; else if ($mailreplyto) @@ -361,13 +385,18 @@ foreach ($parts as $header) { $fvalue = $MESSAGE->headers->replyto; else if (!empty($MESSAGE->headers->from)) $fvalue = $MESSAGE->headers->from; + + // Reply to message sent by yourself (#1487074) + if (!empty($ident) && $fvalue == $ident['ident']) { + $fvalue = $MESSAGE->headers->to; + } } // add recipient of original message if reply to all else if ($header == 'cc' && !empty($MESSAGE->reply_all) && $MESSAGE->reply_all != 'list') { if ($v = $MESSAGE->headers->to) $fvalue .= $v; if ($v = $MESSAGE->headers->cc) - $fvalue .= (!empty($fvalue) ? ', ' : '') . $v; + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; } } else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { @@ -410,7 +439,7 @@ foreach ($parts as $header) { } } - $fvalue = implode(', ', $fvalue); + $fvalue = implode($separator, $fvalue); } $MESSAGE->compose[$header] = $fvalue; @@ -513,7 +542,7 @@ function rcmail_compose_header_from($attrib) $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id); // add signature to array - if (!empty($sql_arr['signature']) && empty($_SESSION['compose']['param']['nosig'])) + if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) { $a_signatures[$identity_id]['text'] = $sql_arr['signature']; $a_signatures[$identity_id]['is_html'] = ($sql_arr['html_signature'] == 1) ? true : false; @@ -567,22 +596,22 @@ function rcmail_compose_editor_mode() function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { $body = get_input_value('_message', RCUBE_INPUT_POST, true); $isHtml = (bool) get_input_value('_is_html', RCUBE_INPUT_POST); } - else if ($_SESSION['compose']['param']['body']) { - $body = $_SESSION['compose']['param']['body']; + else if ($COMPOSE['param']['body']) { + $body = $COMPOSE['param']['body']; $isHtml = false; } // forward as attachment else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $MESSAGE->forward_attachment) { $isHtml = rcmail_compose_editor_mode(); $body = ''; - if (empty($_SESSION['compose']['attachments'])) + if (empty($COMPOSE['attachments'])) rcmail_write_forward_attachment($MESSAGE); } // reply/edit/draft/forward @@ -645,9 +674,9 @@ function rcmail_prepare_message_body() // add blocked.gif attachment (#1486516) if ($isHtml && preg_match('#<img src="\./program/blocked\.gif"#', $body)) { if ($attachment = rcmail_save_image('program/blocked.gif', 'image/gif')) { - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; $body = preg_replace('#\./program/blocked\.gif#', - $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id'], + $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id'], $body); } } @@ -706,8 +735,8 @@ function rcmail_compose_body($attrib) // include GoogieSpell if (!empty($CONFIG['enable_spellcheck'])) { - - $engine = $RCMAIL->config->get('spellcheck_engine','googie'); + $engine = $RCMAIL->config->get('spellcheck_engine','googie'); + $dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary'); $spellcheck_langs = (array) $RCMAIL->config->get('spellcheck_languages', array('da'=>'Dansk', 'de'=>'Deutsch', 'en' => 'English', 'es'=>'Español', 'fr'=>'Français', 'it'=>'Italiano', 'nl'=>'Nederlands', 'pl'=>'Polski', @@ -737,25 +766,28 @@ function rcmail_compose_body($attrib) foreach ($spellcheck_langs as $key => $name) { $editor_lang_set[] = ($key == $lang ? '+' : '') . JQ($name).'='.JQ($key); } - + $OUTPUT->include_script('googiespell.js'); $OUTPUT->add_script(sprintf( - "var googie = new GoogieSpell('\$__skin_path/images/googiespell/','?_task=utils&_action=spell&lang=');\n". + "var googie = new GoogieSpell('\$__skin_path/images/googiespell/','?_task=utils&_action=spell&lang=', %s);\n". "googie.lang_chck_spell = \"%s\";\n". "googie.lang_rsm_edt = \"%s\";\n". "googie.lang_close = \"%s\";\n". "googie.lang_revert = \"%s\";\n". "googie.lang_no_error_found = \"%s\";\n". + "googie.lang_learn_word = \"%s\";\n". "googie.setLanguages(%s);\n". "googie.setCurrentLanguage('%s');\n". "googie.setSpellContainer('spellcheck-control');\n". "googie.decorateTextarea('%s');\n". "%s.set_env('spellcheck', googie);", + !empty($dictionary) ? 'true' : 'false', JQ(Q(rcube_label('checkspelling'))), JQ(Q(rcube_label('resumeediting'))), JQ(Q(rcube_label('close'))), JQ(Q(rcube_label('revertto'))), JQ(Q(rcube_label('nospellerrors'))), + JQ(Q(rcube_label('addtodict'))), json_serialize($spellcheck_langs), $lang, $attrib['id'], @@ -828,24 +860,27 @@ function rcmail_create_reply_body($body, $bodyIsHtml) function rcmail_create_forward_body($body, $bodyIsHtml) { - global $IMAP, $MESSAGE, $OUTPUT; + global $RCMAIL, $MESSAGE, $COMPOSE; // add attachments - if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE->mime_parts)) + 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')); + $charset = $RCMAIL->output->get_charset(); + if (!$bodyIsHtml) { - $prefix = "\n\n\n-------- Original Message --------\n"; - $prefix .= 'Subject: ' . $MESSAGE->subject . "\n"; - $prefix .= 'Date: ' . $MESSAGE->headers->date . "\n"; - $prefix .= 'From: ' . $MESSAGE->get_header('from') . "\n"; - $prefix .= 'To: ' . $MESSAGE->get_header('to') . "\n"; + $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; + $prefix .= rcube_label('subject') . ': ' . $MESSAGE->subject . "\n"; + $prefix .= rcube_label('date') . ': ' . $date . "\n"; + $prefix .= rcube_label('from') . ': ' . $MESSAGE->get_header('from') . "\n"; + $prefix .= rcube_label('to') . ': ' . $MESSAGE->get_header('to') . "\n"; if ($MESSAGE->headers->cc) - $prefix .= 'Cc: ' . $MESSAGE->get_header('cc') . "\n"; + $prefix .= rcube_label('cc') . ': ' . $MESSAGE->get_header('cc') . "\n"; if ($MESSAGE->headers->replyto && $MESSAGE->headers->replyto != $MESSAGE->headers->from) - $prefix .= 'Reply-To: ' . $MESSAGE->get_header('replyto') . "\n"; + $prefix .= rcube_label('replyto') . ': ' . $MESSAGE->get_header('replyto') . "\n"; $prefix .= "\n"; } @@ -857,24 +892,26 @@ function rcmail_create_forward_body($body, $bodyIsHtml) $body = rcmail_wash_html($body, array('safe' => $MESSAGE->is_safe), $cid_map); $prefix = sprintf( - "<br /><p>-------- Original Message --------</p>" . + "<br /><p>-------- " . rcube_label('originalmessage') . " --------</p>" . "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">Subject: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">Date: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">From: </th><td>%s</td></tr>" . - "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">To: </th><td>%s</td></tr>", - Q($MESSAGE->subject), - Q($MESSAGE->headers->date), - htmlspecialchars(Q($MESSAGE->get_header('from'), 'replace'), ENT_COMPAT, $OUTPUT->get_charset()), - htmlspecialchars(Q($MESSAGE->get_header('to'), 'replace'), ENT_COMPAT, $OUTPUT->get_charset())); + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>" . + "<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + rcube_label('subject'), Q($MESSAGE->subject), + rcube_label('date'), Q($date), + rcube_label('from'), htmlspecialchars(Q($MESSAGE->get_header('from'), 'replace'), ENT_COMPAT, $charset), + rcube_label('to'), htmlspecialchars(Q($MESSAGE->get_header('to'), 'replace'), ENT_COMPAT, $charset)); if ($MESSAGE->headers->cc) - $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">Cc: </th><td>%s</td></tr>", - htmlspecialchars(Q($MESSAGE->get_header('cc'), 'replace'), ENT_COMPAT, $OUTPUT->get_charset())); + $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + rcube_label('cc'), + htmlspecialchars(Q($MESSAGE->get_header('cc'), 'replace'), ENT_COMPAT, $charset)); if ($MESSAGE->headers->replyto && $MESSAGE->headers->replyto != $MESSAGE->headers->from) - $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">Reply-To: </th><td>%s</td></tr>", - htmlspecialchars(Q($MESSAGE->get_header('replyto'), 'replace'), ENT_COMPAT, $OUTPUT->get_charset())); + $prefix .= sprintf("<tr><th align=\"right\" nowrap=\"nowrap\" valign=\"baseline\">%s: </th><td>%s</td></tr>", + rcube_label('replyto'), + htmlspecialchars(Q($MESSAGE->get_header('replyto'), 'replace'), ENT_COMPAT, $charset)); $prefix .= "</tbody></table><br>"; } @@ -885,13 +922,13 @@ function rcmail_create_forward_body($body, $bodyIsHtml) function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $OUTPUT; + global $MESSAGE, $OUTPUT, $COMPOSE; /** * add attachments * sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text! */ - if (empty($_SESSION['compose']['forward_attachments']) + if (empty($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts) && count($MESSAGE->mime_parts) > 0) { @@ -929,7 +966,7 @@ function rcmail_remove_signature($body) function rcmail_write_compose_attachments(&$message, $bodyIsHtml) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; $cid_map = $messages = array(); foreach ((array)$message->mime_parts as $pid => $part) @@ -951,9 +988,9 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) } if (!$skip && ($attachment = rcmail_save_attachment($message, $pid))) { - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; if ($bodyIsHtml && ($part->content_id || $part->content_location)) { - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id']; + $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -963,7 +1000,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) } } - $_SESSION['compose']['forward_attachments'] = true; + $COMPOSE['forward_attachments'] = true; return $cid_map; } @@ -971,14 +1008,14 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) function rcmail_write_inline_attachments(&$message) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; $cid_map = array(); foreach ((array)$message->mime_parts as $pid => $part) { if (($part->content_id || $part->content_location) && $part->filename) { if ($attachment = rcmail_save_attachment($message, $pid)) { - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id']; + $COMPOSE['attachments'][$attachment['id']] = $attachment; + $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -993,7 +1030,7 @@ function rcmail_write_inline_attachments(&$message) // Creates an attachment from the forwarded message function rcmail_write_forward_attachment(&$message) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; if (strlen($message->subject)) { $name = mb_substr($message->subject, 0, 64) . '.eml'; @@ -1020,7 +1057,7 @@ function rcmail_write_forward_attachment(&$message) } $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => $name, 'mimetype' => 'message/rfc822', 'data' => $data, @@ -1032,7 +1069,7 @@ function rcmail_write_forward_attachment(&$message) if ($attachment['status']) { unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; return true; } else if ($path) { @unlink($path); @@ -1044,6 +1081,8 @@ function rcmail_write_forward_attachment(&$message) function rcmail_save_attachment(&$message, $pid) { + global $COMPOSE; + $rcmail = rcmail::get_instance(); $part = $message->mime_parts[$pid]; $mem_limit = parse_bytes(ini_get('memory_limit')); @@ -1064,7 +1103,7 @@ function rcmail_save_attachment(&$message, $pid) } $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => $part->filename ? $part->filename : 'Part_'.$pid.'.'.$part->ctype_secondary, 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, 'content_id' => $part->content_id, @@ -1087,11 +1126,13 @@ function rcmail_save_attachment(&$message, $pid) function rcmail_save_image($path, $mimetype='') { + global $COMPOSE; + // handle attachments in memory $data = file_get_contents($path); $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => rcmail_basename($path), 'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name), 'data' => $data, @@ -1120,11 +1161,11 @@ function rcmail_basename($filename) function rcmail_compose_subject($attrib) { - global $MESSAGE, $compose_mode; - + global $MESSAGE, $COMPOSE, $compose_mode; + list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); - + $attrib['name'] = '_subject'; $attrib['spellcheck'] = 'true'; $textfield = new html_inputfield($attrib); @@ -1153,10 +1194,10 @@ function rcmail_compose_subject($attrib) else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { $subject = $MESSAGE->subject; } - else if (!empty($_SESSION['compose']['param']['subject'])) { - $subject = $_SESSION['compose']['param']['subject']; + else if (!empty($COMPOSE['param']['subject'])) { + $subject = $COMPOSE['param']['subject']; } - + $out = $form_start ? "$form_start\n" : ''; $out .= $textfield->show($subject); $out .= $form_end ? "\n$form_end" : ''; @@ -1167,17 +1208,16 @@ function rcmail_compose_subject($attrib) function rcmail_compose_attachment_list($attrib) { - global $OUTPUT, $CONFIG; - + global $OUTPUT, $CONFIG, $COMPOSE; + // add ID if not given if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - + $out = "\n"; $jslist = array(); - if (is_array($_SESSION['compose']['attachments'])) - { + if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { $button = html::img(array( 'src' => $CONFIG['skin_path'] . $attrib['deleteicon'], @@ -1187,11 +1227,11 @@ function rcmail_compose_attachment_list($attrib) else $button = Q(rcube_label('delete')); - foreach ($_SESSION['compose']['attachments'] as $id => $a_prop) + foreach ($COMPOSE['attachments'] as $id => $a_prop) { if (empty($a_prop)) continue; - + $out .= html::tag('li', array('id' => 'rcmfile'.$id), html::a(array( 'href' => "#delete", @@ -1204,7 +1244,7 @@ function rcmail_compose_attachment_list($attrib) } if ($attrib['deleteicon']) - $_SESSION['compose']['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; + $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; if ($attrib['cancelicon']) $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']); if ($attrib['loadingicon']) @@ -1372,12 +1412,15 @@ function rcmail_editor_selector($attrib) function rcmail_store_target_selection($attrib) { + global $COMPOSE; + $attrib['name'] = '_store_target'; $select = rcmail_mailbox_select(array_merge($attrib, array( 'noselection' => '- '.rcube_label('dontsave').' -', - 'folder_filter' => 'mail' + 'folder_filter' => 'mail', + 'folder_rights' => 'w', ))); - return $select->show($_SESSION['compose']['param']['sent_mbox'], $attrib); + return $select->show($COMPOSE['param']['sent_mbox'], $attrib); } @@ -1403,14 +1446,14 @@ function rcmail_check_sent_folder($folder, $create=false) function get_form_tags($attrib) { - global $RCMAIL, $MESSAGE_FORM; + global $RCMAIL, $MESSAGE_FORM, $COMPOSE; $form_start = ''; if (!$MESSAGE_FORM) { $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); $hiddenfields->add(array('name' => '_action', 'value' => 'send')); - $hiddenfields->add(array('name' => '_id', 'value' => $_SESSION['compose']['id'])); + $hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id'])); $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : ''; $form_start .= $hiddenfields->show(); diff --git a/program/steps/mail/folders.inc b/program/steps/mail/folders.inc index 7e0399e..80936a0 100644 --- a/program/steps/mail/folders.inc +++ b/program/steps/mail/folders.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: folders.inc 4410 2011-01-12 18:25:02Z thomasb $ + $Id: folders.inc 5266 2011-09-22 07:49:33Z alec $ */ // only process ajax requests @@ -65,7 +65,7 @@ else if ($RCMAIL->action == 'purge') $OUTPUT->set_env('messagecount', 0); $OUTPUT->set_env('pagecount', 0); $OUTPUT->command('message_list.clear'); - $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text()); + $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text(), $mbox); $OUTPUT->command('set_unread_count', $mbox, 0); $OUTPUT->command('set_quota', rcmail_quota_content()); rcmail_set_unseen_count($mbox, 0); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 8b0e589..3c93cda 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: func.inc 5235 2011-09-19 06:43:57Z alec $ + $Id: func.inc 5601 2011-12-14 09:08:54Z alec $ */ @@ -253,7 +253,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null return; // remove 'threads', 'attachment', 'flag', 'status' columns, we don't need them here - foreach (array('threads', 'attachment', 'flag', 'status') as $col) { + foreach (array('threads', 'attachment', 'flag', 'status', 'priority') as $col) { if (($key = array_search($col, $a_show_cols)) !== FALSE) unset($a_show_cols[$key]); } @@ -287,6 +287,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $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) @@ -297,23 +298,15 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $a_msg_flags['has_children'] = $header->has_children; if ($header->unread_children) $a_msg_flags['unread_children'] = $header->unread_children; - if ($header->deleted) - $a_msg_flags['deleted'] = 1; - if (!$header->seen) - $a_msg_flags['unread'] = 1; - if ($header->answered) - $a_msg_flags['replied'] = 1; - if ($header->forwarded) - $a_msg_flags['forwarded'] = 1; - if ($header->flagged) - $a_msg_flags['flagged'] = 1; 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 + // 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)) @@ -327,7 +320,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null } if ($IMAP->threading) { - $OUTPUT->command('init_threads', (array) $roots); + $OUTPUT->command('init_threads', (array) $roots, $mbox); } } @@ -372,6 +365,7 @@ function rcmail_message_list_head($attrib, $a_show_cols) $col_name = '<span class="flagged"> </span>'; break; case 'attachment': + case 'priority': case 'status': $col_name = '<span class="' . $col .'"> </span>'; break; @@ -556,7 +550,7 @@ function rcmail_check_safe(&$message) * @param array CID map replaces (inline images) * @return string Clean HTML */ -function rcmail_wash_html($html, $p = array(), $cid_replaces) +function rcmail_wash_html($html, $p, $cid_replaces) { global $REMOTE_OBJECTS; @@ -565,7 +559,7 @@ function rcmail_wash_html($html, $p = array(), $cid_replaces) // special replacements (not properly handled by washtml class) $html_search = array( '/(<\/nobr>)(\s+)(<nobr>)/i', // space(s) between <NOBR> - '/<title[^>]*>.*<\/title>/i', // PHP bug #32547 workaround: remove title tag + '/<title[^>]*>[^<]*<\/title>/i', // PHP bug #32547 workaround: remove title tag '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', // byte-order mark (only outlook?) '/<html\s[^>]+>/i', // washtml/DOMDocument cannot handle xml namespaces ); @@ -596,16 +590,16 @@ function rcmail_wash_html($html, $p = array(), $cid_replaces) $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', 'rcmail_html_tag_callback', $html); // charset was converted to UTF-8 in rcube_imap::get_message_part(), - // -> change charset specification in HTML accordingly - $charset_pattern = '(<meta\s+[^>]*content=)[\'"]?(\w+\/\w+;\s*charset=)([a-z0-9-_]+[\'"]?)'; - if (preg_match("/$charset_pattern/Ui", $html)) { - $html = preg_replace("/$charset_pattern/i", '\\1"\\2'.RCMAIL_CHARSET.'"', $html); - } - else { - // add meta content-type to malformed messages, washtml cannot work without that - if (!preg_match('/<head[^>]*>(.*)<\/head>/Uims', $html)) - $html = '<head></head>'. $html; - $html = substr_replace($html, '<meta http-equiv="Content-Type" content="text/html; charset='.RCMAIL_CHARSET.'" />', intval(stripos($html, '<head>')+6), 0); + // 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; } // turn relative into absolute urls @@ -645,6 +639,9 @@ function rcmail_wash_html($html, $p = array(), $cid_replaces) 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; @@ -772,7 +769,7 @@ function rcmail_plain_body($body, $flowed=false) // previous line is flowed? if (isset($body[$last]) && $body[$n] - && $last != $last_sig + && $last !== $last_sig && $body[$last][strlen($body[$last])-1] == ' ' ) { $body[$last] .= $body[$n]; @@ -824,7 +821,7 @@ function rcmail_plain_body($body, $flowed=false) /** * Callback function for washtml cleaning class */ -function rcmail_washtml_callback($tagname, $attrib, $content) +function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) { switch ($tagname) { case 'form': @@ -836,8 +833,11 @@ function rcmail_washtml_callback($tagname, $attrib, $content) $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|url\(|import[^a]/', $stripped)) { - $out = html::tag('style', array('type' => 'text/css'), $content); + 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; } @@ -1017,7 +1017,7 @@ function rcmail_message_body($attrib) $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); + $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); $div_attr = array('class' => 'message-htmlpart'); $style = array(); @@ -1043,15 +1043,14 @@ function rcmail_message_body($attrib) rcmail_plain_body(Q($MESSAGE->body, 'strict', false)))); } - $ctype_primary = strtolower($MESSAGE->structure->ctype_primary); - $ctype_secondary = strtolower($MESSAGE->structure->ctype_secondary); - // list images after mail body - if ($CONFIG['inline_images'] - && $ctype_primary == 'multipart' - && !empty($MESSAGE->attachments)) - { + if ($CONFIG['inline_images'] && !empty($MESSAGE->attachments)) { foreach ($MESSAGE->attachments as $attach_prop) { + // skip inline images + if ($attach_prop->content_id && $attach_prop->disposition == 'inline') { + continue; + } + // Content-Type: image/*... if (preg_match('/^image\//i', $attach_prop->mimetype) || // ...or known file extension: many clients are using application/octet-stream @@ -1061,7 +1060,7 @@ function rcmail_message_body($attrib) ) { $out .= html::tag('hr') . html::p(array('align' => "center"), html::img(array( - 'src' => $MESSAGE->get_part_url($attach_prop->mime_id), + 'src' => $MESSAGE->get_part_url($attach_prop->mime_id, true), 'title' => $attach_prop->filename, 'alt' => $attach_prop->filename, ))); @@ -1097,7 +1096,7 @@ function rcmail_resolve_base($body) /** * modify a HTML message that it can be displayed inside a HTML page */ -function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null) +function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false) { $last_style_pos = 0; $body_lc = strtolower($body); @@ -1110,7 +1109,7 @@ function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null // replace all css definitions with #container [def] $styles = rcmail_mod_css_styles( - substr($body, $pos, $pos2-$pos), $cont_id); + substr($body, $pos, $pos2-$pos), $cont_id, $allow_remote); $body = substr($body, 0, $pos) . $styles . substr($body, $pos2); $body_lc = strtolower($body); @@ -1288,6 +1287,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null) 'href' => "#add", 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, urlencode($string)), 'title' => rcube_label('addtoaddressbook'), + 'class' => 'rcmaddcontact', ), html::img(array( 'src' => $CONFIG['skin_path'] . $addicon, @@ -1451,7 +1451,7 @@ function rcmail_send_mdn($message, &$smtp_error) if (!is_object($message) || !is_a($message, 'rcube_message')) $message = new rcube_message($message); - if ($message->headers->mdn_to && !$message->headers->mdn_sent && + if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && ($IMAP->check_permflag('MDNSENT') || $IMAP->check_permflag('*'))) { $identity = $RCMAIL->user->get_identity(); @@ -1551,6 +1551,11 @@ function rcmail_search_filter($attrib) $select_filter->add(rcube_label('unanswered'), 'UNANSWERED'); if (!$CONFIG['skip_deleted']) $select_filter->add(rcube_label('deleted'), 'DELETED'); + $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']); diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index bf35d01..16f7acf 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -15,14 +15,14 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: get.inc 5151 2011-08-31 12:49:44Z alec $ + $Id: get.inc 5514 2011-11-30 11:35:43Z alec $ */ // show loading page if (!empty($_GET['_preload'])) { - $url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']); + $url = preg_replace('/[&?]+_preload=1/', '', $_SERVER['REQUEST_URI']); $message = rcube_label('loadingdata'); header('Content-Type: text/html; charset=' . RCMAIL_CHARSET); @@ -64,8 +64,6 @@ if (!empty($_GET['_uid'])) { $MESSAGE = new rcube_message(get_input_value('_uid', RCUBE_INPUT_GET)); } -send_nocacheing_headers(); - // show part page if (!empty($_GET['_frame'])) { $OUTPUT->send('messagepart'); @@ -136,11 +134,24 @@ else if ($pid = get_input_value('_part', RCUBE_INPUT_GET)) { header("Content-Disposition: $disposition; filename=\"$filename\""); - // turn off output buffering and print part content - if ($part->body) - echo $part->body; - else if ($part->size) - $IMAP->get_message_part($MESSAGE->uid, $part->mime_id, $part, true); + // do content filtering to avoid XSS through fake images + if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) { + if ($part->body) + echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body; + else if ($part->size) { + $stdout = fopen('php://output', 'w'); + stream_filter_register('rcube_content', 'rcube_content_filter') or die('Failed to register content filter'); + stream_filter_append($stdout, 'rcube_content'); + $IMAP->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $stdout); + } + } + else { + // turn off output buffering and print part content + if ($part->body) + echo $part->body; + else if ($part->size) + $IMAP->get_message_part($MESSAGE->uid, $part->mime_id, $part, true); + } } exit; @@ -168,3 +179,39 @@ header('HTTP/1.1 404 Not Found'); exit; + +/** + * PHP stream filter to detect html/javascript code in attachments + */ +class rcube_content_filter extends php_user_filter +{ + private $buffer = ''; + private $cutoff = 2048; + + function onCreate() + { + $this->cutoff = rand(2048, 3027); + return true; + } + + function filter($in, $out, &$consumed, $closing) + { + while ($bucket = stream_bucket_make_writeable($in)) { + $this->buffer .= $bucket->data; + + // check for evil content and abort + if (preg_match('/<(script|iframe|object)/i', $this->buffer)) + return PSFS_ERR_FATAL; + + // keep buffer small enough + if (strlen($this->buffer) > 4096) + $this->buffer = substr($this->buffer, $this->cutoff); + + $consumed += $bucket->datalen; + stream_bucket_append($out, $bucket); + } + + return PSFS_PASS_ON; + } +} + diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 70d7508..3505d48 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: list.inc 4410 2011-01-12 18:25:02Z thomasb $ + $Id: list.inc 5266 2011-09-22 07:49:33Z alec $ */ @@ -53,6 +53,9 @@ if ($save_arr) $mbox_name = $IMAP->get_mailbox_name(); +// Synchronize mailbox cache, handle flag changes +$IMAP->mailbox_sync($mbox_name); + // initialize searching result if search_filter is used if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { @@ -93,7 +96,7 @@ $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', $pages); $OUTPUT->set_env('threading', (bool) $IMAP->threading); $OUTPUT->set_env('current_page', $count ? $IMAP->list_page : 1); -$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count)); +$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); $OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text()); // add message rows @@ -116,5 +119,3 @@ else { // send response $OUTPUT->send(); - - diff --git a/program/steps/mail/mark.inc b/program/steps/mail/mark.inc index 94009fb..2d50391 100644 --- a/program/steps/mail/mark.inc +++ b/program/steps/mail/mark.inc @@ -14,7 +14,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: mark.inc 4410 2011-01-12 18:25:02Z thomasb $ + $Id: mark.inc 5266 2011-09-22 07:49:33Z alec $ */ @@ -104,7 +104,7 @@ if (($uids = get_input_value('_uid', RCUBE_INPUT_POST)) && ($flag = get_input_va $OUTPUT->command('set_unread_count', $mbox, $unseen_count, ($mbox == 'INBOX')); rcmail_set_unseen_count($mbox, $unseen_count); } - $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count)); + $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox); if ($IMAP->threading) $count = get_input_value('_count', RCUBE_INPUT_POST); diff --git a/program/steps/mail/move_del.inc b/program/steps/mail/move_del.inc index b575e58..30928d4 100644 --- a/program/steps/mail/move_del.inc +++ b/program/steps/mail/move_del.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: move_del.inc 4410 2011-01-12 18:25:02Z thomasb $ + $Id: move_del.inc 5266 2011-09-22 07:49:33Z alec $ */ @@ -116,12 +116,12 @@ else rcmail_set_unseen_count($mbox, $unseen_count); } - if ($RCMAIL->action=='moveto' && strlen($target)) { + if ($RCMAIL->action == 'moveto' && strlen($target)) { rcmail_send_unread_count($target, true); } $OUTPUT->command('set_quota', rcmail_quota_content()); - $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count)); + $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox); if ($IMAP->threading) $count = get_input_value('_count', RCUBE_INPUT_POST); diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 27bc531..e6fb629 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -11,7 +11,7 @@ | Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: search.inc 4812 2011-05-27 13:01:05Z alec $ + $Id: search.inc 5527 2011-12-02 09:58:03Z alec $ */ @@ -31,6 +31,7 @@ $str = get_input_value('_q', RCUBE_INPUT_GET, true); $mbox = get_input_value('_mbox', RCUBE_INPUT_GET, true); $filter = get_input_value('_filter', RCUBE_INPUT_GET); $headers = get_input_value('_headers', RCUBE_INPUT_GET); +$subject = array(); $search_request = md5($mbox.$filter.$str); @@ -70,15 +71,20 @@ else if (preg_match("/^body:.*/i", $str)) list(,$srch) = explode(":", $str); $subject['text'] = "TEXT"; } -else if(trim($str)) +else if (strlen(trim($str))) { if ($headers) { - foreach(explode(',', $headers) as $header) - switch ($header) { - case 'text': $subject['text'] = 'TEXT'; break; - default: $subject[$header] = 'HEADER '.strtoupper($header); + foreach (explode(',', $headers) as $header) { + if ($header == 'text') { + // #1488208: get rid of other headers when searching by "TEXT" + $subject = array('text' => 'TEXT'); + break; } - + else { + $subject[$header] = 'HEADER '.strtoupper($header); + } + } + // save search modifiers for the current folder to user prefs $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); $search_mods[$mbox] = array_fill_keys(array_keys($subject), 1); @@ -89,9 +95,9 @@ else if(trim($str)) } } -$search = $srch ? trim($srch) : trim($str); +$search = isset($srch) ? trim($srch) : trim($str); -if ($subject) { +if (!empty($subject)) { $search_str .= str_repeat(' OR', count($subject)-1); foreach ($subject as $sub) $search_str .= sprintf(" %s {%d}\r\n%s", $sub, strlen($search), $search); @@ -101,7 +107,7 @@ $search_str = trim($search_str); // execute IMAP search if ($search_str) - $result = $IMAP->search($mbox, $search_str, $imap_charset, $_SESSION['sort_col']); + $IMAP->search($mbox, $search_str, $imap_charset, $_SESSION['sort_col']); // Get the headers $result_h = $IMAP->list_headers($mbox, 1, $_SESSION['sort_col'], $_SESSION['sort_order']); @@ -135,7 +141,7 @@ else { $OUTPUT->set_env('search_request', $search_str ? $search_request : ''); $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', ceil($count/$IMAP->page_size)); -$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1)); +$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1), $mbox); $OUTPUT->send(); diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index 4c4f0d1..8ea9f55 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -5,7 +5,7 @@ | program/steps/mail/sendmail.inc | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, The Roundcube Dev Team | + | Copyright (C) 2005-2011, The Roundcube Dev Team | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -16,7 +16,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: sendmail.inc 5229 2011-09-16 19:13:27Z thomasb $ + $Id: sendmail.inc 5527 2011-12-02 09:58:03Z alec $ */ @@ -27,11 +27,11 @@ $OUTPUT->framed = TRUE; $savedraft = !empty($_POST['_draft']) ? true : false; $COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GPC); -$_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; +$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; /****** checks ********/ -if (!isset($_SESSION['compose']['id'])) { +if (!isset($COMPOSE['id'])) { raise_error(array('code' => 500, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid compose ID"), true, false); @@ -138,47 +138,47 @@ function rcmail_fix_emoticon_paths(&$mime_message) return $body; } -// parse email address input (and count addresses) +/** + * Parse and cleanup email address input (and count addresses) + * + * @param string Address input + * @param boolean Do count recipients (saved in global $RECIPIENT_COUNT) + * @param boolean Validate addresses (errors saved in global $EMAIL_FORMAT_ERROR) + * @return string Canonical recipients string separated by comma + */ function rcmail_email_input_format($mailto, $count=false, $check=true) { - global $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; + global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT; // simplified email regexp, supporting quoted local part $email_regexp = '(\S+|("[^"]+"))@\S+'; - $regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m', '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); - $replace = array(', ', ', ', '', ',', '\\1 \\2'); + $delim = trim($RCMAIL->config->get('recipients_separator', ',')); + $regexp = array("/[,;$delim]\s*[\r\n]+/", '/[\r\n]+/', "/[,;$delim]\s*\$/m", '/;/', '/(\S{1})(<'.$email_regexp.'>)/U'); + $replace = array($delim.' ', ', ', '', $delim, '\\1 \\2'); // replace new lines and strip ending ', ', make address input more valid $mailto = trim(preg_replace($regexp, $replace, $mailto)); $result = array(); - $items = rcube_explode_quoted_string(',', $mailto); + $items = rcube_explode_quoted_string($delim, $mailto); foreach($items as $item) { $item = trim($item); // address in brackets without name (do nothing) if (preg_match('/^<'.$email_regexp.'>$/', $item)) { - $item = rcube_idn_to_ascii($item); - $result[] = $item; + $item = rcube_idn_to_ascii(trim($item, '<>')); + $result[] = '<' . $item . '>'; // address without brackets and without name (add brackets) } else if (preg_match('/^'.$email_regexp.'$/', $item)) { $item = rcube_idn_to_ascii($item); - $result[] = '<'.$item.'>'; + $result[] = '<' . $item . '>'; // address with name (handle name) - } else if (preg_match('/'.$email_regexp.'>*$/', $item, $matches)) { + } else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) { $address = $matches[0]; - $name = str_replace($address, '', $item); - $name = trim($name); - if ($name && ($name[0] != '"' || $name[strlen($name)-1] != '"') - && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) { - $name = '"'.addcslashes($name, '"').'"'; - } - $address = rcube_idn_to_ascii($address); - if (!preg_match('/^<'.$email_regexp.'>$/', $address)) - $address = '<'.$address.'>'; - - $result[] = $name.' '.$address; + $name = trim(str_replace($address, '', $item), '" '); + $address = rcube_idn_to_ascii(trim($address, '<>')); + $result[] = format_email_recipient($address, $name); $item = $address; } else if (trim($item)) { continue; @@ -340,20 +340,20 @@ if (!empty($headers['Reply-To'])) { if (!empty($_POST['_followupto'])) { $headers['Mail-Followup-To'] = rcmail_email_input_format(get_input_value('_followupto', RCUBE_INPUT_POST, TRUE, $message_charset)); } -if (!empty($_SESSION['compose']['reply_msgid'])) { - $headers['In-Reply-To'] = $_SESSION['compose']['reply_msgid']; +if (!empty($COMPOSE['reply_msgid'])) { + $headers['In-Reply-To'] = $COMPOSE['reply_msgid']; } // remember reply/forward UIDs in special headers -if (!empty($_SESSION['compose']['reply_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $_SESSION['compose']['reply_uid']); +if (!empty($COMPOSE['reply_uid']) && $savedraft) { + $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $COMPOSE['reply_uid']); } -else if (!empty($_SESSION['compose']['forward_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $_SESSION['compose']['forward_uid']); +else if (!empty($COMPOSE['forward_uid']) && $savedraft) { + $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $COMPOSE['forward_uid']); } -if (!empty($_SESSION['compose']['references'])) { - $headers['References'] = $_SESSION['compose']['references']; +if (!empty($COMPOSE['references'])) { + $headers['References'] = $COMPOSE['references']; } if (!empty($_POST['_priority'])) { @@ -374,7 +374,7 @@ $headers['Message-ID'] = $message_id; $headers['X-Sender'] = $from; if (is_array($headers['X-Draft-Info'])) { - $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $_SESSION['compose']['mailbox'])); + $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $COMPOSE['mailbox'])); } if (!empty($CONFIG['useragent'])) { $headers['User-Agent'] = $CONFIG['useragent']; @@ -414,12 +414,12 @@ if (!$savedraft) { // Check spelling before send if ($CONFIG['spellcheck_before_send'] && $CONFIG['enable_spellcheck'] - && empty($_SESSION['compose']['spell_checked']) && !empty($message_body) + && empty($COMPOSE['spell_checked']) && !empty($message_body) ) { $spellchecker = new rcube_spellchecker(get_input_value('_lang', RCUBE_INPUT_GPC)); $spell_result = $spellchecker->check($message_body, $isHtml); - $_SESSION['compose']['spell_checked'] = true; + $COMPOSE['spell_checked'] = true; if (!$spell_result) { $result = $isHtml ? $spellchecker->get_words() : $spellchecker->get_xml(); @@ -458,12 +458,12 @@ $MAIL_MIME = new Mail_mime("\r\n"); // Check if we have enough memory to handle the message in it // It's faster than using files, so we'll do this if we only can -if (is_array($_SESSION['compose']['attachments']) && $CONFIG['smtp_server'] +if (is_array($COMPOSE['attachments']) && $CONFIG['smtp_server'] && ($mem_limit = parse_bytes(ini_get('memory_limit')))) { $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - foreach ($_SESSION['compose']['attachments'] as $id => $attachment) + foreach ($COMPOSE['attachments'] as $id => $attachment) $memory += $attachment['size']; // Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64 @@ -527,9 +527,9 @@ else { } // add stored attachments, if any -if (is_array($_SESSION['compose']['attachments'])) +if (is_array($COMPOSE['attachments'])) { - foreach ($_SESSION['compose']['attachments'] as $id => $attachment) { + foreach ($COMPOSE['attachments'] as $id => $attachment) { // This hook retrieves the attachment contents from the file storage backend $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment); @@ -624,12 +624,12 @@ if (!$savedraft) // save message sent time if (!empty($CONFIG['sendmail_delay'])) $RCMAIL->user->save_prefs(array('last_message_time' => time())); - + // set replied/forwarded flag - if ($_SESSION['compose']['reply_uid']) - $IMAP->set_flag($_SESSION['compose']['reply_uid'], 'ANSWERED', $_SESSION['compose']['mailbox']); - else if ($_SESSION['compose']['forward_uid']) - $IMAP->set_flag($_SESSION['compose']['forward_uid'], 'FORWARDED', $_SESSION['compose']['mailbox']); + if ($COMPOSE['reply_uid']) + $IMAP->set_flag($COMPOSE['reply_uid'], 'ANSWERED', $COMPOSE['mailbox']); + else if ($COMPOSE['forward_uid']) + $IMAP->set_flag($COMPOSE['forward_uid'], 'FORWARDED', $COMPOSE['mailbox']); } // End of SMTP Delivery Block @@ -637,11 +637,10 @@ if (!$savedraft) // Determine which folder to save message if ($savedraft) $store_target = $CONFIG['drafts_mbox']; -else +else $store_target = isset($_POST['_store_target']) ? get_input_value('_store_target', RCUBE_INPUT_POST) : $CONFIG['sent_mbox']; -if ($store_target) - { +if ($store_target) { // check if folder is subscribed if ($IMAP->mailbox_exists($store_target, true)) $store_folder = true; @@ -653,11 +652,10 @@ if ($store_target) // append message to sent box if ($store_folder) { - // message body in file if ($mailbody_file || $MAIL_MIME->getParam('delay_file_io')) { $headers = $MAIL_MIME->txtHeaders(); - + // file already created if ($mailbody_file) $msg = $mailbody_file; @@ -666,12 +664,12 @@ if ($store_target) $mailbody_file = tempnam($temp_dir, 'rcmMsg'); if (!PEAR::isError($msg = $MAIL_MIME->saveMessageBody($mailbody_file))) $msg = $mailbody_file; - } } + } else { $msg = $MAIL_MIME->getMessage(); $headers = ''; - } + } if (PEAR::isError($msg)) raise_error(array('code' => 650, 'type' => 'php', @@ -680,53 +678,58 @@ if ($store_target) TRUE, FALSE); else { $saved = $IMAP->save_message($store_target, $msg, $headers, $mailbody_file ? true : false); - } + } if ($mailbody_file) { unlink($mailbody_file); $mailbody_file = null; - } + } // raise error if saving failed if (!$saved) { raise_error(array('code' => 800, 'type' => 'imap', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not save message in $store_target"), TRUE, FALSE); - + if ($savedraft) { $OUTPUT->show_message('errorsaving', 'error'); $OUTPUT->send('iframe'); - } } } + } - if ($olddraftmessageid) - { + if ($olddraftmessageid) { // delete previous saved draft + // @TODO: use message UID (remember to check UIDVALIDITY) to skip this SEARCH $a_deleteid = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$olddraftmessageid, true); - $deleted = $IMAP->delete_message($a_deleteid, $CONFIG['drafts_mbox']); - // raise error if deletion of old draft failed - if (!$deleted) - raise_error(array('code' => 800, 'type' => 'imap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE); + if (!empty($a_deleteid)) { + $deleted = $IMAP->delete_message($a_deleteid, $CONFIG['drafts_mbox']); + + // raise error if deletion of old draft failed + if (!$deleted) + raise_error(array('code' => 800, 'type' => 'imap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE); } } +} // remove temp file else if ($mailbody_file) { unlink($mailbody_file); - } +} -if ($savedraft) - { +if ($savedraft) { $msgid = strtr($message_id, array('>' => '', '<' => '')); - - // remember new draft-uid - $draftuids = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid, true); - $_SESSION['compose']['param']['draft_uid'] = $draftuids[0]; + + // remember new draft-uid ($saved could be an UID or TRUE here) + if (is_bool($saved)) { + $draftuids = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid, true); + $saved = $draftuids[0]; + } + $COMPOSE['param']['draft_uid'] = $saved; // display success $OUTPUT->show_message('messagesaved', 'confirmation'); @@ -739,9 +742,8 @@ if ($savedraft) $OUTPUT->command('auto_save_start'); $OUTPUT->send('iframe'); - } -else - { +} +else { rcmail_compose_cleanup($COMPOSE_ID); if ($store_folder && !$saved) @@ -749,6 +751,4 @@ else else $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent')); $OUTPUT->send('iframe'); - } - - +} diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index a1f9977..2f28ade 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: show.inc 5151 2011-08-31 12:49:44Z alec $ + $Id: show.inc 5514 2011-11-30 11:35:43Z alec $ */ @@ -30,8 +30,6 @@ if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { rcmail_message_error($uid); } - send_nocacheing_headers(); - $mbox_name = $IMAP->get_mailbox_name(); // show images? @@ -76,12 +74,13 @@ if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { 'movingmessage', 'deletingmessage'); // check for unset disposition notification - if ($MESSAGE->headers->mdn_to && - !$MESSAGE->headers->mdn_sent && !$MESSAGE->headers->seen && - ($IMAP->check_permflag('MDNSENT') || $IMAP->check_permflag('*')) && - $mbox_name != $CONFIG['drafts_mbox'] && - $mbox_name != $CONFIG['sent_mbox']) - { + if ($MESSAGE->headers->mdn_to + && empty($MESSAGE->headers->flags['MDNSENT']) + && empty($MESSAGE->headers->flags['SEEN']) + && ($IMAP->check_permflag('MDNSENT') || $IMAP->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']))) { @@ -100,9 +99,12 @@ if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { } } - if (!$MESSAGE->headers->seen && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) + 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)); + } } @@ -130,7 +132,7 @@ function rcmail_message_attachments($attrib) $ol .= html::tag('li', null, html::a(array( - 'href' => $MESSAGE->get_part_url($attach_prop->mime_id), + '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, @@ -148,12 +150,13 @@ function rcmail_message_attachments($attrib) return $out; } -function rcmail_remote_objects_msg($attrib) +function rcmail_remote_objects_msg() { global $MESSAGE, $RCMAIL; - if (!$attrib['id']) - $attrib['id'] = 'rcmremoteobjmsg'; + $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'))); @@ -168,6 +171,48 @@ function rcmail_remote_objects_msg($attrib) return html::div($attrib, $msg); } +function rcmail_message_buttons() +{ + global $MESSAGE, $RCMAIL, $CONFIG; + + $mbox = $RCMAIL->imap->get_mailbox_name(); + $delim = $RCMAIL->imap->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; @@ -187,7 +232,8 @@ function rcmail_contact_exists($email) $OUTPUT->add_handlers(array( 'messageattachments' => 'rcmail_message_attachments', 'mailboxname' => 'rcmail_mailbox_name_display', - 'blockedobjects' => 'rcmail_remote_objects_msg')); + 'messageobjects' => 'rcmail_message_objects', +)); if ($RCMAIL->action=='print' && $OUTPUT->template_exists('messageprint')) @@ -199,7 +245,7 @@ else // mark message as read -if ($MESSAGE && $MESSAGE->headers && !$MESSAGE->headers->seen && +if ($MESSAGE && $MESSAGE->headers && empty($MESSAGE->headers->flags['SEEN']) && ($RCMAIL->action == 'show' || ($RCMAIL->action == 'preview' && intval($CONFIG['preview_pane_mark_read']) == 0))) { if ($IMAP->set_flag($MESSAGE->uid, 'SEEN')) { diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 46ccb40..e7db49c 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -15,7 +15,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: edit_folder.inc 5022 2011-08-04 09:01:36Z alec $ + $Id: edit_folder.inc 5402 2011-11-09 10:03:54Z alec $ */ @@ -119,7 +119,8 @@ function rcmail_folder_form($attrib) 'realnames' => false, 'maxlength' => 150, 'unsubscribed' => true, - 'exceptions' => array($mbox_imap), + 'skip_noinferiors' => true, + 'exceptions' => array($mbox_imap), )); $form['props']['fieldsets']['location']['content']['path'] = array( @@ -134,7 +135,7 @@ function rcmail_folder_form($attrib) ); // Settings: threading - if ($threading_supported && !$options['noselect'] && !$options['is_root']) { + if ($threading_supported && ($mbox_imap == 'INBOX' || (!$options['noselect'] && !$options['is_root']))) { $select = new html_select(array('name' => '_viewmode', 'id' => '_listmode')); $select->add(rcube_label('list'), 0); $select->add(rcube_label('threads'), 1); @@ -191,7 +192,7 @@ function rcmail_folder_form($attrib) 'content' => array() ); - if (!$options['noselect'] && !$options['is_root']) { + if ((!$options['noselect'] && !$options['is_root']) || $mbox_imap == 'INBOX') { $msgcount = $RCMAIL->imap->messagecount($mbox_imap, 'ALL', true, false); // Size diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 5cc6e0c..599fddb 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: edit_identity.inc 4668 2011-04-19 20:41:24Z thomasb $ + $Id: edit_identity.inc 5139 2011-08-28 09:47:15Z alec $ */ @@ -28,7 +28,7 @@ if (($_GET['_iid'] || $_POST['_iid']) && $RCMAIL->action=='edit-identity') { if (is_array($IDENTITY_RECORD)) $OUTPUT->set_env('iid', $IDENTITY_RECORD['identity_id']); else { - $OUTPUT->show_message('databaserror', 'error'); + $OUTPUT->show_message('dberror', 'error'); // go to identities page rcmail_overwrite_action('identities'); return; diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 69339e2..2cc863a 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -16,7 +16,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: folders.inc 5091 2011-08-18 18:34:56Z thomasb $ + $Id: folders.inc 5402 2011-11-09 10:03:54Z alec $ */ @@ -203,7 +203,7 @@ function rcube_subscription_form($attrib) $IMAP->clear_cache('mailboxes', true); $a_unsubscribed = $IMAP->list_unsubscribed(); - $a_subscribed = $IMAP->list_mailboxes(); + $a_subscribed = $IMAP->list_mailboxes('', '*', null, null, true); // unsorted $delimiter = $IMAP->get_hierarchy_delimiter(); $namespace = $IMAP->get_namespace(); $a_js_folders = array(); @@ -283,8 +283,8 @@ function rcube_subscription_form($attrib) } if (!$protected) { - $opts = $IMAP->mailbox_options($folder['id']); - $noselect = in_array('\\Noselect', $opts); + $attrs = $IMAP->mailbox_attributes($folder['id']); + $noselect = in_array('\\Noselect', $attrs); } $disabled = (($protected && $subscribed) || $noselect); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 9df9cab..8df3ce8 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: func.inc 4875 2011-06-23 17:43:44Z alec $ + $Id: func.inc 5481 2011-11-24 07:53:00Z alec $ */ @@ -178,7 +178,7 @@ function rcmail_user_prefs($current=null) // show page size selection if (!isset($no_override['timezone'])) { $field_id = 'rcmfd_timezone'; - $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id, 'onchange' => "document.getElementById('rcmfd_dst').disabled=this.selectedIndex==0")); + $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id, 'onchange' => "$('#rcmfd_dst').attr('disabled', this.selectedIndex==0)")); $select_timezone->add(rcube_label('autodetect'), 'auto'); $select_timezone->add('(GMT -11:00) Midway Island, Samoa', '-11'); $select_timezone->add('(GMT -10:00) Hawaii', '-10'); @@ -237,6 +237,33 @@ function rcmail_user_prefs($current=null) ); } + // 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'; @@ -410,14 +437,15 @@ function rcmail_user_prefs($current=null) if (!isset($no_override['show_images'])) { $field_id = 'rcmfd_show_images'; - $input_show_images = new html_select(array('name' => '_show_images', 'id' => $field_id)); + $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['show_images']), + 'content' => $input_show_images->show($config['prefer_html'] ? $config['show_images'] : 0), ); } @@ -448,8 +476,9 @@ function rcmail_user_prefs($current=null) case 'compose': $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), - 'sig' => array('name' => Q(rcube_label('signatureoptions'))), + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'spellcheck' => array('name' => Q(rcube_label('spellcheckoptions'))), + 'sig' => array('name' => Q(rcube_label('signatureoptions'))), ); // Show checkbox for HTML Editor @@ -549,12 +578,26 @@ function rcmail_user_prefs($current=null) $field_id = 'rcmfd_spellcheck_before_send'; $input_spellcheck = new html_checkbox(array('name' => '_spellcheck_before_send', 'id' => $field_id, 'value' => 1)); - $blocks['main']['options']['spellcheck_before_send'] = array( + $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)); @@ -617,6 +660,16 @@ function rcmail_user_prefs($current=null) ); } + 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 @@ -634,7 +687,7 @@ function rcmail_user_prefs($current=null) // load folders list only when needed if ($current) { $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, - 'maxlength' => 30, 'exceptions' => array('INBOX'))); + 'maxlength' => 30, 'exceptions' => array('INBOX'), 'folder_filter' => 'mail', 'folder_rights' => 'w')); } else // dummy select $select = new html_select(); diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc index 27d94b3..7af2c31 100644 --- a/program/steps/settings/save_folder.inc +++ b/program/steps/settings/save_folder.inc @@ -15,7 +15,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: save_folder.inc 5102 2011-08-19 16:32:38Z thomasb $ + $Id: save_folder.inc 5096 2011-08-19 08:07:05Z alec $ */ diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index e5dfdd9..2fefef1 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli <roundcube@gmail.com> | +-----------------------------------------------------------------------+ - $Id: save_prefs.inc 5151 2011-08-31 12:49:44Z alec $ + $Id: save_prefs.inc 5543 2011-12-05 07:24:36Z alec $ */ @@ -32,9 +32,17 @@ switch ($CURR_SECTION) 'timezone' => isset($_POST['_timezone']) ? (is_numeric($_POST['_timezone']) ? floatval($_POST['_timezone']) : get_input_value('_timezone', RCUBE_INPUT_POST)) : $CONFIG['timezone'], 'dst_active' => isset($_POST['_dst_active']) ? TRUE : FALSE, 'pagesize' => is_numeric($_POST['_pagesize']) ? max(2, intval($_POST['_pagesize'])) : $CONFIG['pagesize'], + 'date_format' => isset($_POST['_date_format']) ? get_input_value('_date_format', RCUBE_INPUT_POST) : $CONFIG['date_format'], + '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, 'skin' => isset($_POST['_skin']) ? get_input_value('_skin', RCUBE_INPUT_POST) : $CONFIG['skin'], ); + + // compose derived date/time format strings + if ((isset($_POST['_date_format']) || isset($_POST['_time_format'])) && $a_user_prefs['date_format'] && $a_user_prefs['time_format']) { + $a_user_prefs['date_short'] = 'D ' . $a_user_prefs['time_format']; + $a_user_prefs['date_long'] = $a_user_prefs['date_format'] . ' ' . $a_user_prefs['time_format']; + } break; @@ -71,6 +79,9 @@ switch ($CURR_SECTION) 'dsn_default' => isset($_POST['_dsn_default']) ? TRUE : FALSE, 'reply_same_folder' => isset($_POST['_reply_same_folder']) ? TRUE : FALSE, 'spellcheck_before_send' => isset($_POST['_spellcheck_before_send']) ? TRUE : FALSE, + 'spellcheck_ignore_syms' => isset($_POST['_spellcheck_ignore_syms']) ? TRUE : FALSE, + 'spellcheck_ignore_nums' => isset($_POST['_spellcheck_ignore_nums']) ? TRUE : FALSE, + 'spellcheck_ignore_caps' => isset($_POST['_spellcheck_ignore_caps']) ? TRUE : FALSE, 'show_sig' => isset($_POST['_show_sig']) ? intval($_POST['_show_sig']) : 1, 'top_posting' => !empty($_POST['_top_posting']), 'strip_existing_sig' => isset($_POST['_strip_existing_sig']), @@ -82,6 +93,7 @@ switch ($CURR_SECTION) case 'addressbook': $a_user_prefs = array( 'default_addressbook' => get_input_value('_default_addressbook', RCUBE_INPUT_POST, true), + 'autocomplete_single' => isset($_POST['_autocomplete_single']) ? TRUE : FALSE, ); break; @@ -133,6 +145,8 @@ switch ($CURR_SECTION) // switch skin (if valid, otherwise unset the pref and fall back to default) if (!$OUTPUT->set_skin($a_user_prefs['skin'])) unset($a_user_prefs['skin']); + else if ($RCMAIL->config->get('skin') != $a_user_prefs['skin']) + $OUTPUT->command('reload', 500); // force min size if ($a_user_prefs['pagesize'] < 1) @@ -167,7 +181,7 @@ switch ($CURR_SECTION) $a_user_prefs['default_imap_folders'][] = $a_user_prefs[$p]; } } - + break; } diff --git a/program/steps/utils/killcache.inc b/program/steps/utils/killcache.inc index 73c6c97..fd366a3 100644 --- a/program/steps/utils/killcache.inc +++ b/program/steps/utils/killcache.inc @@ -9,13 +9,13 @@ | Licensed under the GNU GPL | | | | PURPOSE: | - | Delete rows from cache and messages tables | + | Delete rows from cache tables | | | +-----------------------------------------------------------------------+ | Author: Dennis P. Nikolaenko <dennis@nikolaenko.ru> | +-----------------------------------------------------------------------+ - $Id: killcache.inc 4410 2011-01-12 18:25:02Z thomasb $ + $Id: killcache.inc 5578 2011-12-09 07:23:04Z alec $ */ @@ -41,12 +41,20 @@ if (PEAR::isError($res)) { exit($res->getMessage()); } -$res = $RCMAIL->db->query("DELETE FROM messages"); +$res = $RCMAIL->db->query("DELETE FROM cache_messages"); if (PEAR::isError($res)) { exit($res->getMessage()); } -echo "Cache cleared\n"; -exit; +$res = $RCMAIL->db->query("DELETE FROM cache_index"); +if (PEAR::isError($res)) { + exit($res->getMessage()); +} +$res = $RCMAIL->db->query("DELETE FROM cache_thread"); +if (PEAR::isError($res)) { + exit($res->getMessage()); +} +echo "Cache cleared\n"; +exit; diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index b45ff39..65623ec 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -15,7 +15,7 @@ | Author: Kris Steinhoff <steinhof@umich.edu> | +-----------------------------------------------------------------------+ - $Id: spell.inc 4815 2011-05-30 15:08:26Z alec $ + $Id: spell.inc 5181 2011-09-06 13:39:45Z alec $ */ @@ -23,6 +23,8 @@ $lang = get_input_value('lang', RCUBE_INPUT_GET); $data = file_get_contents('php://input'); +$learn_word = strpos($data, '<learnword>'); + // Get data string $left = strpos($data, '<text>'); $right = strrpos($data, '</text>'); @@ -30,8 +32,15 @@ $data = substr($data, $left+6, $right-($left+6)); $data = html_entity_decode($data, ENT_QUOTES, RCMAIL_CHARSET); $spellchecker = new rcube_spellchecker($lang); -$spellchecker->check($data); -$result = $spellchecker->get_xml(); + +if ($learn_word) { + $spellchecker->add_word($data); + $result = '<?xml version="1.0" encoding="'.RCMAIL_CHARSET.'"?><learnwordresult></learnwordresult>'; +} +else { + $spellchecker->check($data); + $result = $spellchecker->get_xml(); +} // 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 d0324c6..4567e13 100644 --- a/program/steps/utils/spell_html.inc +++ b/program/steps/utils/spell_html.inc @@ -15,7 +15,7 @@ | Author: Aleksander Machniak <alec@alec.pl> | +-----------------------------------------------------------------------+ - $Id: spell_html.inc 4815 2011-05-30 15:08:26Z alec $ + $Id: spell_html.inc 5181 2011-09-06 13:39:45Z alec $ */ @@ -40,6 +40,10 @@ if ($request['method'] == 'checkWords') { else if ($request['method'] == 'getSuggestions') { $result['result'] = $spellchecker->get_suggestions($data); } +else if ($request['method'] == 'learnWord') { + $spellchecker->add_word($data); + $result['result'] = true; +} if ($error = $spellchecker->error()) { echo '{"error":{"errstr":"' . addslashes($error) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}'; diff --git a/skins/default/addressbook.css b/skins/default/addressbook.css index f3b52c8..c604c75 100644 --- a/skins/default/addressbook.css +++ b/skins/default/addressbook.css @@ -109,7 +109,8 @@ #directorylistbox input { - margin: 2px; + margin: 0px; + font-size: 11px; width: 90%; } @@ -165,7 +166,12 @@ #directorylist li.contactgroup { padding-left: 15px; - background-position: 20px -144px; + background-position: 20px -143px; +} + +#directorylist li.contactsearch +{ + background-position: 6px -162px; } #directorylist li.selected diff --git a/skins/default/common.css b/skins/default/common.css index f5b1d3d..bf00dc3 100644 --- a/skins/default/common.css +++ b/skins/default/common.css @@ -2,9 +2,11 @@ body { + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; margin: 8px; background-color: #F6F6F6; - color: #000000; + color: #000; + font-size: 12px; } body.iframe @@ -18,10 +20,10 @@ body.extwin margin: 10px; } -body, td, th, div, p, h3, select, input, textarea +td, th, div, p, select, input, textarea { - font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; font-size: 12px; + font-family: inherit; } th @@ -36,13 +38,13 @@ h3 a, a:active, a:visited { - color: #000000; + color: #000; outline: none; } a.button, a.button:visited, a.tab, a.tab:visited, a.axislist { - color: #000000; + color: #000; text-decoration: none; } @@ -56,7 +58,7 @@ a.tab hr { height: 1px; - background-color: #666666; + background-color: #666; border-style: none; } @@ -65,9 +67,9 @@ input[type="button"], input[type="password"], textarea { - border: 1px solid #666666; - color: #333333; - background-color: #ffffff; + border: 1px solid #666; + color: #333; + background-color: #FFF; } input, textarea @@ -230,7 +232,7 @@ img } #message div.notice, -#remote-objects-message +#message-objects div.notice { background: url(images/display/icons.png) 6px 3px no-repeat; background-color: #F7FDCB; @@ -238,21 +240,25 @@ img } #message div.error, -#message div.warning +#message div.warning, +#message-objects div.warning, +#message-objects div.error { background: url(images/display/icons.png) 6px -97px no-repeat; background-color: #EF9398; border: 1px solid #DC5757; } -#message div.confirmation +#message div.confirmation, +#message-objects div.confirmation { background: url(images/display/icons.png) 6px -47px no-repeat; background-color: #A6EF7B; border: 1px solid #76C83F; } -#message div.loading +#message div.loading, +#message-objects div.loading { background: url(images/display/loading.gif) 6px 3px no-repeat; background-color: #EBEBEB; @@ -279,6 +285,9 @@ img font-size: 11px; font-weight: bold; overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + white-space: nowrap; background: url(images/listheader.gif) top left repeat-x #CCC; } @@ -738,7 +747,7 @@ a.rcmContactAddress:hover margin: auto; } -#rcmloginuser, #rcmloginpwd, #rcmloginhost +#login-form table td.input input { width: 200px; } diff --git a/skins/default/editor_content.css b/skins/default/editor_content.css index 2ddc87f..aabed07 100644 --- a/skins/default/editor_content.css +++ b/skins/default/editor_content.css @@ -1,5 +1,4 @@ /* This file contains the CSS data for the editable area(iframe) of TinyMCE */ -/* You can extend this CSS by adding your own CSS file with the the content_css option */ body, td, pre { font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; @@ -25,8 +24,8 @@ pre blockquote { - padding-left:5px; - border-left:#1010ff 2px solid; - margin-left:5px; - width:100%; + padding-left: 5px; + border-left: #1010ff 2px solid; + margin-left: 5px; + width: 100%; } diff --git a/skins/default/functions.js b/skins/default/functions.js index 32c0a73..8482e37 100644 --- a/skins/default/functions.js +++ b/skins/default/functions.js @@ -108,8 +108,13 @@ function rcube_mail_ui() rcube_mail_ui.prototype = { -show_popup: function(popup, show) +show_popup: function(popup, show, config) { + var obj; + // auto-register menu object + if (!this.popups[popup] && (obj = $('#'+popup)) && obj.length) + this.popups[popup] = $.extend(config, {id: popup, obj: obj}); + if (typeof this[popup] == 'function') return this[popup](show); else @@ -141,7 +146,7 @@ show_popupmenu: function(popup, show) } obj[show?'show':'hide'](); - + if (bw.ie6 && this.popups[popup].overlap) { $('select').css('visibility', show?'hidden':'inherit'); $('select', obj).css('visibility', 'inherit'); @@ -187,29 +192,32 @@ searchmenu: function(show) if (show && ref) { var pos = $(ref).offset(); - obj.css({ left:pos.left, top:(pos.top + ref.offsetHeight + 2)}) - .find(':checked').prop('checked', false); + obj.css({left:pos.left, top:(pos.top + ref.offsetHeight + 2)}); if (rcmail.env.search_mods) { - var n, mbox = rcmail.env.mailbox, mods = rcmail.env.search_mods; + var n, all, + list = $('input:checkbox[name="s_mods[]"]', obj), + mbox = rcmail.env.mailbox, + mods = rcmail.env.search_mods; - if (rcmail.env.task != 'addressbook') { + if (rcmail.env.task == 'mail') { mods = mods[mbox] ? mods[mbox] : mods['*']; + all = 'text'; + } + else { + all = '*'; + } + if (mods[all]) + list.map(function() { + this.checked = true; + this.disabled = this.value != all; + }); + else { + list.prop('disabled', false).prop('checked', false); for (n in mods) $('#s_mod_' + n).prop('checked', true); } - else { - if (mods['*']) - $('input:checkbox[name="s_mods[]"]').map(function() { - this.checked = true; - this.disabled = this.value != '*'; - }); - else { - for (n in mods) - $('#s_mod_' + n).prop('checked', true); - } - } } } obj[show?'show':'hide'](); @@ -217,7 +225,7 @@ searchmenu: function(show) set_searchmod: function(elem) { - var task = rcmail.env.task, + var all, m, task = rcmail.env.task, mods = rcmail.env.search_mods, mbox = rcmail.env.mailbox; @@ -227,36 +235,37 @@ set_searchmod: function(elem) if (task == 'mail') { if (!mods[mbox]) mods[mbox] = rcube_clone_object(mods['*']); - if (!elem.checked) - delete(mods[mbox][elem.value]); - else - mods[mbox][elem.value] = 1; + m = mods[mbox]; + all = 'text'; } else { //addressbook - if (!elem.checked) - delete(mods[elem.value]); - else - mods[elem.value] = 1; + m = mods; + all = '*'; + } - // mark all fields - if (elem.value == '*') { - $('input:checkbox[name="s_mods[]"]').map(function() { - if (this == elem) - return; + if (!elem.checked) + delete(m[elem.value]); + else + m[elem.value] = 1; - if (elem.checked) { - mods[this.value] = 1; - this.checked = true; - this.disabled = true; - } - else { - this.disabled = false; - } - }); - } - } + // mark all fields + if (elem.value != all) + return; + + $('input:checkbox[name="s_mods[]"]').map(function() { + if (this == elem) + return; - rcmail.env.search_mods = mods; + this.checked = true; + if (elem.checked) { + this.disabled = true; + delete m[this.value]; + } + else { + this.disabled = false; + m[this.value] = 1; + } + }); }, listmenu: function(show) @@ -561,7 +570,6 @@ function rcube_init_mail_ui() rcmail.addEventListener('responseaftergetunread', rcube_render_mailboxlist); rcmail.addEventListener('responseaftercheck-recent', rcube_render_mailboxlist); rcmail.addEventListener('aftercollapse-folder', rcube_render_mailboxlist); - rcube_render_mailboxlist(); } if (rcmail.env.action == 'compose') @@ -583,12 +591,16 @@ function iframe_events() // Abbreviate mailbox names to fit width of the container function rcube_render_mailboxlist() { - if (bw.ie6) // doesn't work well on IE6 + var list = $('#mailboxlist > li a, #mailboxlist ul:visible > li a'); + + // it's too slow with really big number of folders, especially on IE + if (list.length > 500 * (bw.ie ? 0.2 : 1)) return; - $('#mailboxlist > li a, #mailboxlist ul:visible > li a').each(function(){ - var elem = $(this); - var text = elem.data('text'); + list.each(function(){ + var elem = $(this), + text = elem.data('text'); + if (!text) { text = elem.text().replace(/\s+\(.+$/, ''); elem.data('text', text); @@ -606,34 +618,45 @@ function rcube_render_mailboxlist() // inspired by https://gist.github.com/24261/7fdb113f1e26111bd78c0c6fe515f6c0bf418af5 function fit_string_to_size(str, elem, len) { - var result = str; - var ellip = '...'; - var span = $('<b>').css({ visibility:'hidden', padding:'0px' }).appendTo(elem).get(0); - - // on first run, check if string fits into the length already. - span.innerHTML = result; - if (span.offsetWidth > len) { - var cut = Math.max(1, Math.floor(str.length * ((span.offsetWidth - len) / span.offsetWidth) / 2)), - mid = Math.floor(str.length / 2); - var offLeft = mid, offRight = mid; - while (true) { - offLeft = mid - cut; - offRight = mid + cut; - span.innerHTML = str.substring(0,offLeft) + ellip + str.substring(offRight); - - // break loop if string fits size - if (span.offsetWidth <= len || offLeft < 3) - break; - - cut++; - } - - // build resulting string - result = str.substring(0,offLeft) + ellip + str.substring(offRight); + var w, span, result = str, ellip = '...'; + + if (!rcmail.env.tmp_span) { + // it should be appended to elem to use the same css style + // but for performance reasons we'll append it to body (once) + span = $('<b>').css({visibility: 'hidden', padding: '0px'}) + .appendTo($('body', document)).get(0); + rcmail.env.tmp_span = span; + } + else { + span = rcmail.env.tmp_span; + } + span.innerHTML = result; + + // on first run, check if string fits into the length already. + w = span.offsetWidth; + if (w > len) { + var cut = Math.max(1, Math.floor(str.length * ((w - len) / w) / 2)), + mid = Math.floor(str.length / 2), + offLeft = mid, + offRight = mid; + + while (true) { + offLeft = mid - cut; + offRight = mid + cut; + span.innerHTML = str.substring(0,offLeft) + ellip + str.substring(offRight); + + // break loop if string fits size + if (offLeft < 3 || span.offsetWidth) + break; + + cut++; } - - span.parentNode.removeChild(span); - return result; + + // build resulting string + result = str.substring(0,offLeft) + ellip + str.substring(offRight); + } + + return result; } // Optional parameters used by TinyMCE diff --git a/skins/default/ie6hacks.css b/skins/default/ie6hacks.css index bfdb6f0..dc7f24a 100644 --- a/skins/default/ie6hacks.css +++ b/skins/default/ie6hacks.css @@ -20,7 +20,10 @@ img #message div.error, #message div.warning, #message div.confirmation, -#remote-objects-message +#message-objects div.notice, +#message-objects div.error, +#message-objects div.warning, +#message-objects div.confirmation { background-image: url(images/display/icons.gif); } @@ -131,6 +134,12 @@ ul.toolbarmenu li.separator_below #messagelist tr td.threads div.listmenu, #messagelist tr td.attachment span.attachment, #messagelist tr td.attachment span.report, +#messagelist tr td.priority span.priority, +#messagelist tr td.priority span.prio1, +#messagelist tr td.priority span.prio2, +#messagelist tr td.priority span.prio3, +#messagelist tr td.priority span.prio4, +#messagelist tr td.priority span.prio5, #messagelist tr td.flag span.flagged, #messagelist tr td.flag span.unflagged:hover, #messagelist tr td.status span.status, diff --git a/skins/default/images/icons/folders.gif b/skins/default/images/icons/folders.gif index 0fccb2c18a1d19c7d537552a7c3713123c3726d3..eb06bd8c10d560461a89af7eabe9214f1f93e897 100644 GIT binary patch literal 2568 zcmV+j3itI#Nk%w1VGsbc0Qdg@P&#)zJ3HRr-*R$vNl8j|fQr)6)3mj=LPA35sb|Q^ z$>^G2#l^;wla#QqvDn$!^78Z5)z*4@eC6fk&CSkWVPm$pxoK)^fr5jChKHe|qFiLJ zq@||q?d@G%UE$&3Q&UrBW@c<`Y^<)XY;JIQM+}OKjJ>|T>FMdo%FKR$fs~b)HBumV zczgZ*{Z?04j*gJalUn)u`c6+!K1NN)$jK`$FrJ>Drm(t2Pgka>t1?o2b#{2;<mJ}u z{b#2}nVFf$j8}k<p25MvmYACW005__sMFNd*PmURoSkWAU)7ph&d<@;*xBai>FK0l zwu@Q6v5f!wzo*yv)8@(NwM_c(zr~tBX^^&ljGFtziO1FD#m35-uEL<9rcGr#yVtE| zXK9|GqukuyxZnGswaS^AoMV~asj94Zgp-WZXzJ_hW2ruTxLx-5_&7aBv4>fQh>7O( z{&=kCK4++y$?l(kSkYvv@9*-z!Nj`B*ovTfWs*x(d$ehu=2o0BKW8R^w(5+(?Ut*( z($v_2ij(H?;Hm9}`~Lr{x4`10V_|wxxVgG;e21yL)V;pK!TbO1{r~H&XM#RvyM|bF zXJN$U{85kST%kAG+uW<c)}Pw_o#J`m;p9eThae**r@h9kzo5|4)@`QpT7^VWkafL^ zS%;9DQ<*N`pkTVXy}`r9@Um^2#D#IC<HXV6PJA_k!u0RBa=wCBl-q5;QID6n(Kv2b zpSZn_XV`M6RKJl}byBU9zkG(cZTa%)f_HSLxzDwOR`s=aN`la;s;W<cF;#&*LP&i` zdM{FWJ9kjSvAxQDhLHHefbOtv*Z%+a`}LE6fdBpS;=GaY;^NfNq<x~d>6F5WskyPx z+slE0#ixYKwY7|vq35}|L0B@C%l3lITe;2Xy_ZLDr}~Gw>brNF%hSe}tA?Pm#^&kn zPFcK|k$SgcVtbQlyNXtZqRF1K$b6>4qokzR(8z_sr+&s+Xmozj+vR0cRI8$mQC`Js zbj$z$|NsC0A^8LW00930EC2ui01yDQ000R80RIUbNU)&6g9kAvRESXEh#vm@$#`(1 zVH^Pw45VOCqXiEh0|pQraN>Xi2P00XR9RslC|rqf4a#;6i_JcL==2c?3Id{^h$2OT z2B~N)EIijmk|W254@+dGY}zyj=|4^Rm^y_zWlFeBXW|Leq^;@GsC5Jdibc$pKs~m6 zpjA7^)tOOrGzr`?k4&Akf$I9XOJ~bKEK>xT3+!qzVS=6_@0d)Pa>L7*Gi%<=x${2~ zphJr;cmRWp)2L5lI6$z0hE-m498l#zOdbsl2=YjQW`*zHI#Tc$iGqlZ<H(6P5h<{= z03u?%NcSR!NT$^SU2|!$!pw~uNr<ffxSjjoZXzTyz~J7%1PK_z1!i#L!i9+nVJ?Kh zKp#R2`Gkl<hz#}B=f)!z9Pr;i83f1#1u1aBMIMi+lHh`7WT4?fDs(7;1TDbe*@z^T zXrg8(V8B3TCrI-R3>I8=LOb15vyDCtjSz(tJpkiQB?tkrqZL)e0pvkKN<rimN(4D% z6-+v*B$Q1e`DBy_jj)e3OICT13DeX=4weU<FvKs^*x}_tD*VDtB^Y2f12C+eXeVbE z<f-SLdkS;`3QnLP=%9pN;3o=P)KEhM6;#lGqBWpEf<PpoP=f*~Trk227o_0n8q5u_ z1_h)Nfgcb|JlH{~9WY^lC`ZKqdIW@A^e~)x9UKt>6E&=|$|EZ^v0w`wR8YjR$R1n4 z0}==%!2>qDZ~z(&RO`SCpQNCIKq@q0L=pl}V1WfEjIlxz2E_S~3KTIRLnlo%Apis^ z+%Sf^7(8GC3U2h^gcIXjGKUFcWFSz!JVX#tL_S>N#{dGvAzua+ykN1#Gi3aN2@>Dw z@y7^pV1fx5NU&{=<y;aG2`_}vLJ|gz;0G~I_#*)WnXGWKKzpzt#u}XvvIYqp)L_B@ zU+f_e3&}_@f)O{2FoOg@gfYV+EC{p+Cx>)>2q&DVA+|Ved?C;m%J9JlDQq8e3@orD z0|+=;^U=oLzJ!8K8$a~_ZOkG(>p}}HY8XOAG*qymxH0btlnx(i+|vpbzVt!`7?}J4 zh|>RrqD<e07}9quVEmzZC<6ha_~nNC1Hm7tWIYfIm|*e)>AirV3o5Y_^aTsR2QR$Y zAQ!LM0ZFuA!VMbS00bIC6vXliHyj{<3}c+ofCTCa^g^RH5MYB1GY~KU43iE7!wDu> zOaK9mY9K(210|6HMiD?HksBu%K@bN-s6hsb!H5w!fC5c8!3YTA03D0~4JN>V0wPd@ z6I72N+GBzVjBo%kZ~%c0h~7Zz<p4COU;vCbfdh<?ffWtp2pCXB3tVFY7%-v+D>wo{ zK7au;XrKiHumA)94p5Bl4P*tG$bcC{wgLsLVSxqVm;oqY02K6K2<<Tl12iCk3y@#{ z5`X~*TxgI8P(T3+pg;tShZ!2U@r`h#0YO$kf@a|0j(EJ|B+fAq7YLvLLJ&e0202I^ z)M63?(ZDAP(TD;#vJs8IhanN^kO~x{8J#dd0}SxTMBIUr|L|iovVejiykQ7VNJAoc z0f2#Azy_xfLMdl3gdQ{k2g_)sK#V|uLZqPwGaz3NRGG^@3ZNNj2&6L8zzlXEV;~rS z<siC1%`OaL5X|7mGad4VQ>dd1;4FhYx}XO-yup}-2!<op>4;#IK@X+4#XuZj18=-y z3;5i^D_)`hhg+0_AUO!AKnE&EHX8IGG$?^W7s}8%k^l}1c)|iEI?*ST02{`%0~9C$ z1t`El7!WPN9TNEoVVGhTvoHlmp<vOGRuT$9h-nOBN{N<cbO}gU!V+S@Q%RJ77p}Cy zE^x}znVQ0)xflp9;ZW3~2EnIE6^I}0fKwz`HK(j7!3Lly)Kn<qtEouE60+KlfsEh{ z@JPTD5+I2LBtQ|vD8Wvo`T;md;u*4#1uLE*iMal=IW`D_76waLXE>t-_5dhD7h8gZ zI(9@H*py@^%YlNxU;>!UY-V>R5ED!wvXiCkKr%3a%W77$J5#{~JPX>;ZmO~^m;h;E zu&~<YMnpsdn1E_c;EyqwK>!L!0u1Qk4-<T*0<q12KN#=^2H@ejc<_h81d>}7_#+Q9 zcmyLjz+Hdrj0DK_M=)oQf&`_&9}61D0Bl=Z<_ttM@CD6d=erqtcmM$im_f%9^1cv+ zfB*<+i9t93zZ5_K0uc~F0H#Zj3J}1+2Zq2HW)J{_5I_VGb^{7NAb|=O<iZ`8fB{?; z0TXzbATIy`0}OD4CS*bY9yqc32p|C_jNt=4h(iEGa1ap?;04^N00MT55FP*+zXPa1 e00K}a%q*G7nK{6do7@m72LJ)b!?I%o0suSPjFfHw literal 2430 zcmV-^34!)UNk%w1VGsbK0Qdg@tgfzXZg6==4CUqJfr5i+YHPi|zKV;Ca&mO(>FI=q zhqSe}$;!;$-`|pxlwe_Fet&^AQXrI-n0I)4q@||){ry%~So!+;j*gJalUhzsP(DUY z$H>Xe&CV+=FnW7@p`xOuu)3a}pG8ksu&}YFsH@}T<#l#=GE#iVj90<I!2kdNfRCPM zr$*N6{h67W)z#LPn471ksMVTV)6~_QoSo9r(`ja3*PmU^&(YV|*~OYb*xA|o@W1J# zVYZ7|)8@(l`@hJ^$*0%(`^1SzNJ{4C>1mL*=e10JjGDi(jK|gG#>U3m+}@y}rnukx z_V@U;x4MUjiA`lY#m35YfQn{kX+CGDsj958hgqSu%ATO3e7Id>sXljvlbM>FW0~JL zJx7|Z!n@b4=Jft}tmll=XzJ_hy2;q)@!)}qlUAHDWs*z3!Ng&DQI@N{xVgH~WU6VN z=5Tz6n91(%@ABfLV~U`9tGB@N^7H%t|GmD#($v_WfLN*Rg{i#MKW8S4zwLpx>gb$b z?d|PVd$j1OXNEy%x3{=)rQ^MdS#75B#O3_${r|!H|E#~D@Um@DkaefM#&l<4o5Y1s zI(O==X+~v-y1Km}BPCOrE{Bkt!NbM7hFG84{lvt@+S}Z#!Pe)OU*O^7-=JWf;(1)5 zH^kB4T7^W=($-Or=!3%al-q4eg3$QFfO4o*@3?Y(gpH18*f?%im$=cNxV`nYcZRra z`SR&VdM|y5l23s#PJA_!zkGL4!>X#PvAxQ_kyz}lWwnD=;o;$ecXV}9t){upLP&kT zQIA!DJ?^k>zJga$c{_WPXt!cw=IQRa&FE-!e#_IwTx73sr~06>#z9yz@Z#dDqK&(E zn~avB(c9&I##x2Ir`P`fm#c<-qPM$>R_D37mCN>m%v=Bc^1YWwWmHtmwYB&A^-*5M ze5S&fk$UNr!fSNPp0mi4fPjXg$xd0kiK)5byphGHgonE7vC!LfG-Jzwfz;8Yqok$S z(8&M)|M~g(A^8LW00930EC2ui01yD8000R80RIUbNU)&6g9iyHRESU@02BWFUEm?2 zp_B$NY%pNLVZw<M2oMlNU|<0W5&#USRQX__q*{1ty`dNGh|NNUt`rg|DUY6?dKxwQ z=BVhZBRrusB16W73r0_dc=A*R>Az6im^y_zWC%G=VB`r5g|F$;sB{7eTGfh{Ks2;m zpjBHY5tv0+LJ3^L?g^c=g6hh-du7SMBSQk+3!G>$VS<+;qnJ#Ya>L7*Gi%<=x%0mO zphJr;xPZWg)2L4qSU}JL2u@B)EWku!OB)al2%cboMS}0&B^aC-nIJ}q<H%ze5h<{A zgBV+!NO!U&2B_5nT~l!&;fn|nHDXBrxSjjo?ic|SVBqfHKmZKF1uB42p~8U&Rti`l zKtIm}`Fy0p#|8D(2gM#yEb!ky3Iv!#2Mka_MH_oylHh`0D4^j&5Ony#2NPi6*@z^T zXrg8Y5Wqxc2E;QC28di{Ks)JRqYpX_0iZ+>CKU6`BnZ8*V-HA30pvkK20`QwHv~B( z5==U&B$Q1e`DBy_0g%l;OICT%0p|2`4weTQpaL%S^x@?}5a43ZBm`ilK{2eIXeVa{ z<f-SLdkR!Q0!Abt=%9oa;Aa9<aKM2B4?N(2q8ua;fItBxz=0496aWAK1u)?08O$MY zMhB$EfZq!_JV;2WgydjDDm29ZN&|#cm@u4qgwOy(4jgd8$sQ}|u;2uQJg~yC$R7Iu z4<88h0S_KnumBbgR7-*dnJ@r>KoIC4Lk$gd5JeOQG$BC^HpKZ41Qg|P!6-WD&_Esx zh|q+(1n_V`0#KM>gb~rGQpN#IC?HV2C%_O<L@uZz2LcU9A)f*dSYWZm8f0w20TSQo z@y7^JaKHfye6Vef)u<9t02Wv=K@A20AV(`k`11i1ph$4CKzBs2#TldUaYg_XaBu(u zQ`{j?1i5?wfD9r4puq<(SfPO%5eVc)DSmYAM=7P4A$B=jOd-$|&9K1+Dr_sG3@^Oo z0?0L5v%$sPw>&Zp7cKPvy^9+>zrqSDW~2dxIzV)x_%6-}1P&W!bVCUcxAX$U7^bWN zh|>Q&(oElJq|rAeW2~Y1BLe}V_~nNClgApGWIa#>rkK(K>Aj5ciYBoWG(`l!2QR$Y zAQ!LM0yRu<fCwOn@B$Vp6vVOxA}r9r1x*;>zz6CIWI>}I6ybpf8We#529pkifdL0t zTtpF#g3v&W1J%F)Mle7m5flc<KoA8n;D7>t0S5q(paVKE000O=f)W4#3kM*85MaOo z15}S7+RMQKWUzoOPym4>h~7ZzMFK2900D3?010HEfE5jd1_Z#w1YC0f48VZ{5}*M= zh(UlafM5a$K*T5i7VwMi4MYN<P{0>NCIKOwVSxqVm<>8$g9MmB1?@2i6F~5R0t5g7 zAHV<wTxbv&bU+9~=l~3ihnWqy@r`iY06`=W09}OOj(EJ|A+#}&3N)Y!EMP$r206$O zB;ybR0YN6zFo!BQat?Elh9ME@kO!zi7o)I&18nd|Jj5X%eQZE1l8^uugh2&H@B$u; zQHg;Rzyq6LK`Aw$0u#(31iomcKx9w^HF&`U8X%tuRGG_A#=;AMOr{rrF%M)6gaEL7 zgBYeMhBv$c80&DRL&C5LYiQw{T7ZWb&~Sw?gi;O1_=7tCa11S=Ari9~2njr}jZ-Y) zo=Z5zDbO(gi%1Y;1ON@FK;_8Bf*xc80!XMr7dpoPWML3K5QRhs0Z{?CBb0skK_`Cj zgDec=p#q3QA~P`zMKFUIirDB6d=S!s0N?>XNP$c<Ak$8;RHOp&V;^RKgBi>q13(pq z0F2>E4+Mj!K&7c7SSpKw@G=WYO==2++SHsjV5d09YF1|e2?0>!nMNgr9mYxuQgBrO z?{H}t#9;^@7{U^UFoYd!A%LCalo(mC#4=z33rH-(5_I)vb3Bj&A{h3tu5g6_yz$S4 zI#vJ%jqHdhu&K&gmI4LAzyLPOS<dcEAO{!#Wi5Nzfhb@An(b_7cLsq0gm$!~-4tdg zFo4rrVqjsojfjX4Fo4z`z#mQcLIZ?Q0}SxP9|!o%18A!Ne|#bgpQwX$>);QA352&0 w@JAaoum?C$;Jg0VSpb&nk6>zm0SRJ&KNd6)1mqUC%o&Ji<_j9hZYCfAJBmPH^8f$< diff --git a/skins/default/images/icons/folders.png b/skins/default/images/icons/folders.png index 5013318f8584a6c7d9661d2d3d7ffa245e0b4475..2580fd1be79a1ed4dc127a343ba7c7f487ed082b 100644 GIT binary patch delta 4943 zcmV-V6R_-~CEX^F7Yeip1^@s6oqnvDks&C5|4BqaRA}DqS_za?<(0m#UR76hRrOBq zdqX$SERAf+BAa56#WOAef(phcjyaC8qsPHfgP<l%WRZxt24d9FX+$%wi5W#iw3|TF z$krS5zE@Q*wQuju_y6^(x~jVcbmpAN$)OHE_4?Jj-+%A@@4f%M_kTqH-yb1(v3>i0 z_M5C$>;9n+#Ky+1EG;eFcTuF*Uw^&1t*uQCemowJTvJmcZ`rb?>Oyqt;01`YK}2WH zoFSjjN9@|`_0oa`3rZe&<Pq8L_Y-hKW81cELIglhPY*RVHj>R|BT16@U_?ntNp#(H z*YRf<A-nhX+iyqeV9zI?wyV_YbfZLnG~koS?vcsik;vx8aQVsM@RJ?G?F1K?v#qt8 zdhFsi^<{U><{bF^YTL>=Gs$Q)-~l!j{sG!Sfzgj)#TfA5zDRVq+(vKg+Gh!gV0V+n z;l!_61G)Xghsy_IpG-C{05I%cnLS5hH2yX@Ne~1Rqg8PLkE*-V<{+OWlM4@jy1f!P zy<nS(f#C$A1MIsze)0me-)w{Ms_sD!Tyjf`)k*1?*#Wtoewoj11yg2+k9w^>Ji~w_ z(nf2ktF@h}uO|fHbV{vly>@bfs1-b0K-A~-(SQwv4iG|tPAJm_F0{sYviDga0(FD{ z9B$!Ud&dBs&GS*a*+m|2U^W1MlN;=N80#25KRA$8<a0X!Ahrhqgr4@cR<$~b`ki2# zEf<JA9*KW50JkE$9|N-E+e7YwPBWur0IILwc_wPgwJWKyx|&>eJB&rbY?#p(FdUzs z5lbXX0;zO*^0{o(@l9DQqZJfmio(z;9Er*hMlgM5CVpi&F<f-{^M4qB(jI&KiK%^k zy~i$vC_X-6+EY(HQ5g|Xu--pTPEMu`8y>zO@s=&mkjv#-jmt;?uh+AnXlx;smmi_? z4b7y}YRMQALmG_+0mVV!j`H(!DK9UFPM$n<^{|+T_&1?={CI@5W`s2>A11RYV)l-X zP8v6E9932xpAfvK3d%2ks8lg|xw&Mv^ipDCA|+vrLOe`LN(_v|1aQ$$*;!e{o@F#4 z4w(E2@o-bHipa@iBvGY;hJ}EdVZf3s@!xFlm4x_&kRDV)`Ezn}IE!wCb2}b#xtUvg zd1z<%Ty8gau(tLNt_RRu9pWG;|FL70bgsURQq$5XS{F@fC{P7|PFRR{xtxf`Er<&) znmcz+NDmw!B_$=MWb$O1K5Z(G{ad#`OJ~oXB2iQTz<zpqIz98-Ex4yfbaIhSr;CYL zh1$AC{-7wTsPuvRp#xFz-oVG_^V8vPj(`&nMDY#Z+QOETPMoaffkXn4Uy?Y1gune^ zgb@HbU3AL_@4uISE%WUQ+nUVP&c%`VkOG?x`;Fg6Y}9JcUycNSFCX#yJiKn*x;rLL zoVWun-H%kL`g;K|;_3PMdmmW7JkP4tu7*oD)z{ZosV;?h?b@|>%$l0Hch-y<6b+}F zZM9M&(T)*Kd4!ptSa;*3jSH7vL2cb*>BZ-sqY@-!cDK8KF%*$5K)iR|O^kRdc@b;G z6Za4$B+yHZjaA()*TRd<y!XI=ZIxy30ol{{x!m#5GWqLQ7RXDkoqPPMtFDT_IPv@2 z6ygIQUM?SgnGw(V9>l&MOboVtUtBV=Dr~8qSbojqJCbwL$ZHeGe0Uq3Z?n;pW!|bj zn}1<>d3oP|1p&qt<^JN9Tkj^dJcbUv_3KL_4%xw~RjclpJ$FI8$L=J(se(?m80eED zwu=&n0Fd6Vn>BSJ9sTGP`uOl!`r>%k9}p8uFGd{N-dC(xAtxF&Rju9qJ5$oqYtvIx zI*|+O0OChn^s-pXzHyIT`|$0<Ug5(%-#<!<bMMc8?~{KB@e8|m2_bjh_^ZeHMkWZ~ zkwk^1s_ef_Pd+)gjDkXS{(J+H2c8wsv7^VRs_HnuKV`}knm&C-sPM`!$R|-y4O$}G zff=ES5esaHbo%ru`q7f>`8a+0G`}Zc!&R|?8AP>ukONV~k3eJzRUj)7XmUvj{pHV} z@ZYX~xZ(<miV`WXcLpXL0RVp}K&&R1GiNRmiMfNjHnJ3$6?ShQws<$VPz?ewwiqEx z9+)T|57HW>G)Q9<Vi=qt^VyjWtSC-d9udZYimP_Vj_tH(&+jj|bhqEWmL7fVQO<RQ z2qu#WNoEDzdfV;vlhvz`jk&11yDLPPlaqyi0{sp8>Z?OE&_56fz(io|Jq}y2+w3&H zcmi_50g8#`X%G|`MR~~L7A;ytOO`BQ`O#1Sfh*DJbkelx(<mz|n^a;aMe7X;fQFJs zCDF{8GwH;M6S%MED={bnOQ?WgGFvDE*%&Lj*aLBKvHYP^?Gly#$wreivMAR4Ik%O6 z2oAXMKm-$Z9F`xaq$E>LR(eSOKFJG$e(H62$<^Jh7@H6#0#@Oj{qItHdprGV;}d}g z!o0x4mJ<`S;aU&&_rJ401Q2|R39Dhh5Ah#HlR0E1nQ^#TH{f!1G(y06<IVq&TibYB z0QG^>XS3SfPN&22{Bt{VE(zeBci)qLzj805whj}Ol?LqK{s(?ZW|NsWXc7{6`BVGw zLl2Jq&TQQQbGF(Y)ZW=c8EMI6Fz9K`>Xp2o^yz<p#%yKuu&r(W&kA33^m*?Y7#N_Z zmb(F>BeU5|8d$3xVCT*^al>IvDyPFK-f;JPxnF93>EQ3{{+R=~tp0V0MKM%=TU$ei zVvGnT=$$wnlo%gNO-&7CG#JQc?W1~>L(JS$$L3MX>4tS64FF_kXGlxe&m&{JktC`m zHJnNB_tF50kEPQK$!WEaL++u`v%Hk!)sx*~rT8v`FC;=wbHD3@7rxXdq{VQ(dR*R6 zp&_A4@ymW*wfLpLwYA$x_Aa-7GXxMj%4kl_jZaJ+o5%yI*Y2el%_tg|FrBgtqv?Zl zuae2t6)1h+nI>&NiEeSQj})6^Xw}C?6(;A#1#G|})0%<@sLS3;<C029m%N^Kez}2U zm7m8A@Iz60;r!snLQ=ES>Lw5Rh}}IVN_1vXM{hHIT=f>c^wnk(Bo(cHDS3dLh?BMf z8`;oH^Y}asAr4$VceSG(B2{}(sY!It;?;=z0yUfK5i3NBRvRfTHk(&)yoy6tOCzf4 zLjYE5-w8JwPjN2Zmm;UfPR*8DdVJ}NWU+VCq|7VP8Z*=DN1jD5i2=wIWe{pY0DaxI zGl*H}R(W~k+49N#G&6sH5ijv-yS^o}y^G#I`35KEITbjtyZqHbUtoI3pSnEzV?nJd z8r;W+qzqyEKE$j${$b1YxNNu_kA?)4wQJXvjv6&;9vU!Ha&vPN)6&um*ntF8^sfE^ zYcE#l^nkVhv(1|}{dO3@%9X2X;PXYSTd{QM^#mY7iAR~4nbg#O+)ORaEv)@RUD&bF zj5)je`R9rwA`<fDJfks&L%#g-%fzm`x;l9v$<EH^ZIH2J$5AG_IOr)A4hw11rcJfX zyz;8F<CRrtzB)m`I+|XJj*h0()KvaV$rV%R>bY0bnbW6iyPtnP5<sn1TViA5({8%u zX1ad)GFX>P@p18gl#!7Z<d8S)%PT5ax5qS$10)&d%F1IrCp_@^XH-y7fTmkKeN$1+ z9V;g%hx7<-EV%-Ay~8RNaL^N%5Jzb6(wH%YTyYf@f1_+Dv8bq!_f|UF+o++Tf#naK z!vL^c9cILW{DRRukg}H7^chpp4yvIlWF;)k$v}dUkeGyj{z+8NFcCBwb%$0PO-+pr zl#`p!GgUjn_~ONjDGE7JYilbx(BW!mIL{K&>R|wGx2K^89AshU^3Oh_jLZzKhm)sH z^89gp@pwv2Nu}Q2UWhANhKT?f&oP&61P8?vilK{kI$n94CQg_{GiFRjbe6bi>?8ym z%;{kqBqSt%)a%_ITDWi#m6iP`6^t&xwr1dowk}$SY<(JlW`O-D)<<d`$rrL7ee|(I zMx!xr*|KF^>n!<ZM#OA@?Mlp)k$kpn-n@A>o^Krn0OHK`>(}3pcHk@!r6QryYqdHi z*#OR)`T=@$_wL=#AggT|34kSjF-pRvS9<N5po)}##EKoc*p(v}|KDLinfId=@?d2Z zS!fL{zP|kQ10ft>#nVqey{)~Yt1v0E0Cq4ziRyA>gqH(Qy*oc5y;u0tPY*wPW6%yt zHf-2X*bE1H<&R}lbFL{6|D^!P;29fHabX^fPspYB&K{T&Zi(mMOluY_UP93ZBbmE9 z$<}XwA^U&@o2i9g_xGF0)ZI2Lj}CIs^VCyM-Bn#%&m&PxTpX=mb0hWjTIk@H2Wi3l z`Dl~J(eBswkxDI6tU8xOO+soo2jg)hxa!GG8_9>L!^~By)$o4$+i$(a9Vi+HRJ_Xz z$NGcSPe+|<Q#gPLBJ5hS;-AQ1j6>8BDOg8;AhdJ&nK{E_c|{i&ok}{j!5<DF-h1!8 zl#kvz>u5V%Zte>>l!On|qng_hh#6>BM}a%LA8C*vq=hfzdNeCuVym#{&3Eym7H4V( z3KX#d59w?*oOT<{zH%n*-D{_s)BBrhzI`DtsKiEy@Nb0^ru_QO_5VT%Y56=eVMVBa z3=|oe8N-l}`l-QzsF47ymcv)UaP!SKdpb?MJgsB?FQ5!!1@|BT(mtOE05v(ZCX#fH z)Np{bva+(ROoTs{eLzuKrtv7A@(FVAtknn6M9zVC`d8$(RCiIuAi#Nuu)Mfr#)o&_ zb06iVkK(0%u(V^I%g)+ZyPOr@*19%-(in6#;du)?Yn!rY*-aI^5LXT-f|VI>l@mLx zlesADh~Us)Kb*z-6hfF+G7wf+WGKN!HN**JWk^aj*Q8W%|4=E;yd^itbL7u2iSRdn zu?>$%9f(Nt(@iul75dacV*}8<N~w|g;VN{f5oqTd`{{1u?_Mp~f9Ku9BGSQs*B_(G zJ~UZy{_a;J&0xI~<&e}5u$iL*k-pDuojfceEks00M#oQ!iK1|Hti_414mJ>lzttL< zG%$ZvbY#^YibxRQt}``t<kz{#0J9bGpdYhKTKEEzYd?I$i!5EG7?(p#DGCP|4-r;1 zH8oNBn~zdK5}Zg6Q^q;G7q0<-pnXJc*0sRXf;K?1$K+}q9+7UikuqY@{?NdbVQ+41 zXsEwHtYSS)1R4RUexQk&l~Cdc=YU6~#^!eFcL;>Zu_;1%qCi@IAf)@?A4cdw)CWks zT3v()`dzzr-N#npYpjA%t0F7_NlK?i20Q%38ekgc=J*^OI1(WOk4V>lEx(b{WBsU+ zRHQ}g#}K6kHyYAQBI%%jXi3H0oPA<q^W4KCQisVxe$-A{eH5vD0uN~v4TbswjVhmr z)u8|fV!D_g5s~)o+s7l)w{QI`*wm1S*#!{umoaeW#&RSTJG@s145=k%S9>_XIW(S@ zAR_&F&$?WSOUYu1V}M<MwuZ1u*#JG@Jq=0i<pjntndRXI#dKj@dduzoCD!*Y)tOkC zYZZnx>b1%cE<h_Qk;tV)r^{7auz#dOX>+j;D}`>mb&W8ri__WFO+Q)n<BI~k^vbIv zpKt_Ea}RuRkS@f@WSmX2W>q*R9KhoV0Q?Y6l%sPG{ZLNSO0`0NLpgb{^cNT9WZRCN z3I`q!jl{`0B%Gh41ia?jYj~w{^5jY04jY9QF?7J+1_<Z?3Dx5pH&JqON(3hzogMVr zYkR2}^-?iPpRq;bA`UTFBE|uB{cZ=p^~(nzmLoZlC<PS@OYJI-l#>MwI!VcwZ(Fm9 zSF#ZYmO)N}I@!8^_1~$!u8y|v*oK-ak>c>?18OTO8WU)>c--HS9xzTW<x`61M)dpp z?k|;t=?x2p{3)3wJu=VQ0{`S;b;ae+|019ShZ?2+MttAK@<rtp!+vC^AELwiAZlon z5{2cV0L+*)I6K*orCY`bVPTc*o3(}5egTkE@P)<I)zv+JLqV7+t3kX8o9i+V*5M_` zpVigX@z*L*c;}&qunR@_JXj#BI)19`33B*mqG9<F`vVyYBR-_m#@4Q`u9LWTH@NA< zGpi>|m@sB&3d{k(YBoHpvbMH1{Dn?E8Z#+)nF%i9Js4<{Xhsh`@K+DH5e2XeJeY*$ zLlkQRv3HYy@V8YtDilTnU_T6Cwj#W+Gl{XzJT5pG0K{0pY6bKaT1Se?5?K5zX1RIN zq)87!-mM@EfmBshJ%kCy0H6XDT=URnWciAkEgQObi;yGCh6qal5`)k+y``n)A^bL< zzmp?L?KmPkY_V7(mQql*b3+EYOvS~;uRz-~gYT(-vH|Y?hVNK_k5z2s=SPnoWk-T6 z?n#2eMU>L^(2p52rU1Q^EH*379IY^(YTTQM3U+@Glz~)MR&o#_%o^1SP*m9KB|&+$ zB_$<mu`*AGgFrv8hQEg*DUFq2!^IQ!?SoNOV_7ZesV!pML8Pm3T(U#_j-tvRHl*O_ z?(SwfASNvNOjPtMq0m<061_GkVzi<wQOS{P!uN1}l|raduGuPh{|6TmGTGpVU1I<M N002ovPDHLkV1m4ccd`Hg delta 4755 zcmV;E5^U|=CZi>g7Yd>X1^@s6NbyY{ks&C5MM*?KRCwC#T6dUKRhIv~%Bib!&L|ma zXo3=ypzOAQ%$h(^LH!ih@0)RC9A|M56YAhd7)E4G11dVYjSMQr*-=Cc4J!>SG_j#` zb*iea>dIBG-rI9;g|4ETr2EHwv->_S_3G6-zkANPC*IqFEX(*Qm++GTVmE8ouD!v3 z<#KI1^98fnJb&rZrCZMnuw~1Z=9x2R78ev0@b95e2n`Jl*uH)HL8sF>CL9ifaT^<J z)~w<0sbT<aZEeNDU=T-+9Dyi`VD}7U`t<1)AAInEe74E?f15u2E9(CCxjc97T)5qC zNRq?{n>8~tGfu%~X3ySz_g(CAO%m#VtM7?(V7aVn4s1agy$U@%q6}|Pf;&LN?t#}E zhKEMLM`933n>3Npd`Dw42N1(5_xvdnVKN!Pd8Pkk;?0Z5aMEzm=nc|yCGc&H8*gpc zYLDx{6M)_8qhGZ~1j69MFA_0v;tml24NpjB??I`j?^YiKL9jAf1qTQ!x;or{UWk$m zKfM?TN$`b;Z6*c{A0c{)eSa{F5P>>vZqlBjtB(V}+|uImA)jXUlH9(q%x8BIQ#P-N z9+yb(Fdzw9y%wFV7N-C1IDpS5wYK$m;3J||;@M6_4xfl#HxYV?kQC_i69>eF)|3X1 z!%iZgJr3Xv2&XLVy*OGX!eaA(BN&RzM!*OV`$5J!4KYj{$O?!7F99emF#w_4($=a{ zWy0wrw%KwKaWE+HPX-W(${wacveRb}f!+=qqh$b!@7{Y}Gv=E4XgqcdevgNYMWWeg zMloVIVwe$2kR<^ModKfXjrQ-W&5TxvTBC-BHp-DQI)nktmzha8I(#&L{P?L?e3nO7 zJOPKJ=YojR($ewt$|sV&k;$5!osDJ7esfOZRjZzd-`~f193T`5V#v_JsHxeD(+$ng zX|*t=q(H4!lQVfacje`!C@U+$p+koU0tjKm@Zo4|Y$lg>@nN-DlV)#k@4&EO!%$nh zKUoJ%e!41YmVFnfgK_kKQOoq8ipfvc%@?7ATNprG1SUUS(=S2?S0?Fz$xqkFi_pQy zB!H9@bEVtkPAMxb#lG5u$jHdx%Aue^rYFY&B5~nFaZwSugCfObG*vP&Vmi1vJ&oLy zSY<D=byg}A1R_M#Oc;_Z@!#C!E9qoNF+C`vI+$KkTEbZjP&oI0&`bURbL$Wnk3I7T z0^GscEbUwmL~~`L4!HdL_SNE4{Ym8J<w390Lq!Ty5GO3e`~5z&wYE@P@MG%KDRDh; zfSjD1l#0=#F@9VnkNvCH{sBji9)?mG1t9kG^Yiii?^n??6-6gMbUIy1k|mxv*~nj1 zDiv7z-~*%sWz>6rBbO+K@$L6}iIX6SBK9}sM3X*v=omLHiHO3I#0ez&9!?-k0?_I7 zEjvEkUM%y~qO>M+wR3SKKBP#pVZZU`6dSeL(>P1i;n#C_PsZ%~Zo;UES0NnAMCT7L zA?WEQVv!Py1FdasxbES7k;F34HFoxuM9gwvE*vLzP$ag0bB*{tezbSAqq|r0zf__8 z9|B;Wxp?v7JE{CxOy$q|ty{Og&uCQ_Iuj!vUtYfXrb&}fT~{}qN};>x@#~5h`nd)p zo>W=5dD4Ul(38_mcDaxNtQ*jj2blSZ#n)f<_>9?O(bhE-FTL;rD!RL=S_w49E0l8( zZ(e)@Bd$b$h+>WM;C(=PI$myUJkaI$&xn_9XCvPE!D?9!?UaL#FXi@+=g8l^I$f^1 zX6pVcuDBvCR&Wjoz==Ox6D8hB#B=3uUtz>kIB{&^0RiH~;@OGM3J@VCw#Bc`Nt_4} zSK^{Yi=LQ!_2@gZOY;zN3$T5=2B+KHSXmu9;Bbe3XVlcxI0n*H9AMax(qG<m+r3c9 zmtyxj&t4F5+zu8jSa9d$sngSf9v=+WJviKA#HV}R=OvB<F#DcVISM~~{3<^A_9(vE z-}ySl#HHsWjyu!5dGq89llnkwmveniUjB*v+?)<FVI6^l>35bmL+q2Dv3rp|MamT- zJrjk0zmKNt*AFk_g+)8%J%LKcV36`5<-%y)K<P|mQz2$IMMZ^p{q;BS+^T1z)w;(m zuUPTek76M1&W}H~f`@HEI7=a!P^z;3o?N-IZyALs)#=j>Tm<%Q-w*q6;6S7r8#87M z#*d#6H{tR@<xmQWK1*a7m=P)zu_&ZOUEN`S{BzZ{eALy|@n-@hTm>66gHomH<3OpT z9|@5aRFSGg!03t!eE!*|{I{`V$3mk~B9c2J6Al1CU!p*)Czvv2Disn_`?5AwDP&f( zG9sn;0CAz{17K`1LRLIn$TGU9Ic0T30tX7N+I8#JV$-HSopaspxMLBPKf0WAog{*P z)oP_8a}RF2{SMrE%L1y#{OIcHj1!iW6j6iz7QXprH+r4D$pB0Q#@-6D1&`Z<;Uh*; zP1uVRGcSWkff|%i6-V7Ys;a73eRL*(z?JCp`7mz$I5O2@D3l%08;nr^HL|lZF_G$p zg9i`Na|2(AJ`q?!MF>`#9R*a4v8IcEy^xw}<}V$#NLc#58>0(~V77h9Z6%2VZagG{ zl`;;ik8^UeQBss2m){|Uh`@;+ZwUUbu6WAp6M<IYy={Mi#bUu@k3SK4A;AlRY&mIy zHo7+u``g~z76*u3Ojs7S+5SgiY;0~_j>PZLk<GSNX52Nr&)KHkd>JyzQ<0v3m%<+f z{h@eyCsAz}mczVO3`>!FSC<bSO91;nX^e<q&N3mlG!3~!Gq@RtJRzj0voI`uJc^8$ zV8^M~VD)!K3Qp38RqKQ@kf20!rV$3S2HB;l{Gs0~W8t6&(dlW$u*?eRvX@}}*UKO) z!hE%eA7~6hf;)pcbyomEQAAgNw-p(_BDD83<C6pL;N@?gf*>idu;M}Z$U5D<Zn&*J zdN<g|fnN;3Yw=-9?QL?ftsQJ@Vn<-N=ys(BEIzMYKmYTRJaaLxn|bZ*4?~^kOfHv$ znhFWJN<BJ?e}T4kE2<yPXTPZ)c<@)oT`!%KO(qM<GOCc7nQ>yf|HYwy8e@VTIJ(@- zqxb_anX}8|g{7k#1$o&p8Vy)@%Y43{^w+<A!EEIc#(~El?gP-8H7|J`q5FD!d-3#K z633^5&1NGuS;Y3@)afQ}IBb*3=k+P`)5>J0WO<oL|23imS9o#8kQAIaaU8o-OcYE+ zczj-Dq?ysw)Buyw2sep;Sx@Z{Gxyw~WoW5uSR4l^E-sK}FS!b)G!w1I38=`K4B-%Z zsri^aelV?&9bUN`mrM$wBxHcc?m}9pQH+bw-R$)5`1h|37iEc^0bidXWtnVbi5VAZ ziQS2o*h-c-_#!RwbfP6T{|HNLNVLRb%o1@dNS&I5`)1ujabG}xv#p+Dg%Wy|2?JPS zeWE2EWR{rf=lfFd1wClCpTLUQFTw8V!exb*!{M`G%icdg<^VFt5|1ZZ;t^(vAu+@w z&#F%!z{K*Iyu~}w`QNa4I`QG5w>UAcsUntmEEZ6h9?C1{7JnkB6hjg!$um2S_$`Tf za{osy*V1hR<AA|`p1OC=Z-;8NdMd`#C<cl=JA24<XU&=g4dnqBnYov``i6$nJPGgr z=;7qnHxLM-n^vHxs0cM*e1U?(0t^~72!{?I;yH8ph~dc1$wg034^%2;|4Nl_gAkjI zjSUzvas(`G7VNLxk5MBp!-NUr$s#507v1Cw%&Gb{-|5tUNEnEV88c?0y81sb=#oL? z%0^yX==3_OP{t9^1Y%#qd*=a5phb%oFU`uzy2|Z#jVUcH&B)8kGg1Z;h&#Wt*VRKS zRM+cre(}_kPyW6i!2J0Oj+4(1VY?NxXI~2f!l+TBP*_-qrsig}G`H|AuujU@4u|vT z#ur~0kt70t)yrijQwoQC<&{^!?mIg>cpxb*F6P@HLx&DSAt~A6=o#Ek2jj+7+9zIq zMc)3}1MpK=lO(pI8G>G~M{aH|f2U&X7+g8^N*t*>?B4j|i^%{gmC9~5r{&#n(~Y=x z?i^Yk8EL6$C@9E_amY99YxeA6yFJ!^98i&AtF7IC$7{l!Uw*-DAT2Eo-|wm6j#W}p z0t2lIE3SyUo_=;f9CW9qr_%bj;?he8bH(l1^Is??B@P)fnA=H*rH!9CQ2o%+4}g}d z-A0yJKIjr|Fl@_f{DevzJ$f7ms48J)P5~7d=^2^OYBk;cL{O_$?aUXN$P!CR%lr94 zYinzNqAwil2SC2ia1p*>AIKL@U4$>x4de^;7vT%71NlPH^5u{2HknLibLPz9T4#RG zjELC)%Sz0YsrYPp>ZzwD)BCOc0EoD7$&w`xcs!m-M3hSfl|if3G0A$(X0ww(f7rNj z<MUM2whRQoqC`rx;4(z_+SM@?F+E3*Ts+Z#BbV^s;Wp5;s(Er>XO-M&o!NZt`usy7 z4nRJC-80WTv&PciIXJU$5ZS@VXjGSzBfK1e>RJCW3?bqDJHJ_XeGK4HYLizslLNi_ zW;InTk>jyQ9+49c>3|V~%aHeG9kw6c+4#q!AC|`~@f11J!s)ZBpf{Re>*|2pX@{qO z*G|dQ&hMR08?0Sz{p#qLC3Zjk^wakoJ5kRgQA%nmmMpv;jvhO9eZ33Qr%i(?B^4Xr z*a`*Z1hc9XN_Bc}qAv`8<dH`ftbFouh!l00xoWj)zMuZ?JMVA@((AR6U0!mm*Ii-! z;8R%>0jwm#hN|oS1x8aUMIB{)1CBy}JC~oCGs|AAqf6E2LZ>o@69JU>-+w>KOH28V zw$~rvzQ9g3>+9>On_Cx&89F^Q#GNNhWso4`B`)I<T7{R{Dr|cDFZ81pTD=jGCRX4f zovnt?<HqF6Ct~wv502MuYdUstV_8gzjU>Wv2ag={?A=R#L489xuS{4IO7J9qLYOb9 zM5UjKI8dr30#?b1t6;qG#v6kj)*fEgG5;5+m}U)k9{`noqLKhq@M^7)bl%)VfV}GJ z>eWnyH>-C*qh%V`@RCoEV`r@*iKgTngvNh^fc;o!BEV@9VeW{E2_M~k-_KE+pT%4K zSZl{Tmz}k-?Q+(9yH2)2ZPc-UTq?wr$aa~>%$#$>9^QyY4<}-s8Q&@gJFJtrDC~$} z_kVsgiS1Lw0AdGrCDG1J8C_!G45yT%B@ycYn^;HqkG3&A?b@HoQ{*o%i169ZT>T?b zJ4K{v`Bq$&OZwE2#(GKf3ZZYuNkNmT1+0H-8}2pz@wM{z?z%T-2NlbImMt613~ASv zM^WntKoKP4QBj$}_D-UQq+tS^m=%fij(}@)qBru0G=m~iwh)4rCenl?XaiyBh(is1 zSE*&F$@~?1At|NBBNB;l&ynLN5!U%(B(qi0i(#5w(vmMwaUCY#2vL=;h#HqynKL92 zU^t1epsA?|HE%D+piFXqA_JLnh^$T~AmSjvb}i^_K^r02Wc9aB?iZ2fU5^5@1cjPR znd~h<361(MB37_HO$syumHLsRqN4N)Zz2agA~iN!;PeWh$tfw4@{|I!;Ydgq$v;e_ z2c;oG64L6DL@;dFu;J%y6~3cYFliN_1%MRYsga2teqv2vYGveqbZ1xZUdqnH<09~g z^iOlIN4_~sJ(2=ijT%Ocinvk3ASt0E1?VLOcXNJ5X)X)&i%9KOJHpgEX$=}EM1hAi z=t-esWTQ${(&`|>fihoNo@fVoTeogq{pU9}!xt8aO*Qp}I%v`j&`@~O($Hu%RIO27 zP(=)>C1rypk%Loz3WcJIBGPA@7MCJ5r-*L{aCX@ml2yt^(u0rMLKQ!sh3V45nnYh< zoS0_cbceITwf%ye>35&IS)1#Mdt($t8y&(qXc+<9K=Bi;^#5mVQGmDq{En=n*5-T{ zYlUuGc&pIwfTE+b3%4$~`Mdxxzxvw1CmgZU+?`+T!nrtq89jP5wrzi3PUM6G1cMQP zAHzxF-yi%aPE@hZ{Y*|CTKdcLa<XRK`X~p%AO_;()Tt(XNiE>j*Idmzl|zRP@y<Of zD-*ZhwvhidKtu;rP_20UNn~f|Byqydm){^4A3^=n2x@(X4jGnoh`|am4)DVIwfxaT zzy3ElnG*?qIn=SR(r(Y*8rW^NXssaN_Js?0C!2I&8RI0Tlhv!AL;cB<Si5cw^;8*1 zO-twd3_~uBY_$a0dx?MT78}2M=r{6(TubS_0nc0+Cl5UMP`t#K`QKr%qDSUcTjZb2 hBf~#{JO7UW0|14N;5wE;4wnD`002ovPDHLkV1gk(7D503 diff --git a/skins/default/images/messageicons.gif b/skins/default/images/messageicons.gif index 60526f1f32df297cb9b4297e0c6d713b75d1705a..80423dd1e50f2fe04b9fc64aa7262c851e83af8f 100644 GIT binary patch delta 1737 zcmV;)1~&PZ4bBgLM@dFFIbja~b^+(@0A2t9VE_VT0RU(K0Br#PbpQZ&004gg0*C+s zg8~4U0052y0GR>+p#TD;0RX800IUE3tpEYA0{}BLGBr0eI5{^tIygEzIXgW%JU%-; zKRiA_JwHG`K|e!0K|?=7MMOeHMMFkGMMp+NM?ywOM@310Lq|zPN=!>hO-4&iM@vpj zN=`{lPdHrwOi)reUH~&-08&s?O;S`aWB^W6Ra8<|C20UHXaG@GSSV}&B5(jBaR63Y zTpM)+0e%1yc>o-C1{Qk&T3%ond;noyVqaliWn*V&Woc??Y-?$4W@~LHdEsqwbZ&BW zb#r(APf~S%cXV`le0O<vdU$+!dw73+fqH*}`(0c7UR->Egv5FZgN1_oWo5&I0RL!b zhlz&!ZEn1Y6U2%LjgO3wj*`oY4v&$Jj*^x9b#nc7c$Soyl$Mi{mzmR%8Izcr{Cs<s zn3b2AmUgoMn3|XWe|^xI9nqQ}%$y$lgoV<ZAex_lp@6pno}iu2o+18*hkUvQprW7A zpd<T=hyIO_%%>)zr>do=q}Qb?rl_UZrYnlT7}lvFr>w84tf|$mB;%?vkHsIVud&>& zDA%wj<*YQ}t~27VG?U3C*0n0*ur}PZEaI~+*tad~wHxTPI_$O`=(rs0wkhSeJKei7 z=(#F?>$@SE(KzV3KJC0B>bo}KzBcQ;IOo1M>cAxIy+NMUJ>$VR?7=4QzdP!|JL$ng z?!zhY#2xL!J;B4j?88Ow$RF>;Kcw43@5V{%$VlwTN$AT#^2{dk&OPzYM)c1#?9WZI z;Y;(+KJ(8<v*Jwi&`|HvNbb^5@6%E3)k*SM)l;_TSoGIb_SjDM*-!V{V7%;J_1;?c z-&^nT?(OpR_VDlU^6&HU_44%b_4D`m^YQfe^Y-}k{rC3w`S$qw_xbzy|N8m*{Q39& z|Ni{{`2PR=|NH*`{F5;PIg<?o4-9qz00{m7{|OxU4;Pat15Fi-6DJ~5rVpPsjXG7S z)vH*ouBo_YlZpdW2TLNRUhQy+ljQ?Ne<oBBn4^fQnyGp?X&JR&ixP4grK(soVZ+cO z$sv6Vgo!iPSR)NFw#0IaEUsiy$3U7eGfgnM)PhPUt9X*fL6bCdOoO0&a*7=Zv7$^Y z8<LWVLbD*VOD?N~LWvj%-Qi0wq8w6*Cy#W2P#>EFGEf<9XpvAD>NQD_9%sm)e^3nq zF|xuxB$$AZ8&&+%hzkRWaF802{F8+d1dTut8-@Ji0uKLN`A-T2SwY4>O&swL4FY{| z5EK8L5W_z#2;>1mJO~s*35F&l#6cY>gn|kJIpJqR9*95!2u^l-*jJuS23cNjjpf*= znw{F2WCWo#m|XszRkrG=ZH4-of2X)Yq3f=@9s~tDzy=#E6a@V$tgyrmWGp-C2%Ao_ z0zrXJIp&;GPC3?|1MNRhh(ivqP>}O&vEYDnEI8q83xzk`u-i?$-*lrcH`;8IjlJ7w zla0FA^y{y`+j0wTueho=Fu}?mi)^t956dvH>MZ+gvC~!y1-96#>n*tAf2vz9u*RaR zF1zeP0k6Ep(rYg}_v*{<zyAh&u&xEyoDdN>=dANVM4aREIX(MK1kXAb&GXMd|2#B7 zOAFL=(@qm~&OlQ$&2-UE=lst(N+98N5>;>gvq0xeAw?8nD|F5mX*bli%?cGE_uO(P zRKz%V<6Q*)97P~>x7>Qef5G=bcjrCM-h%f%(BFX5t++si8=m*$|1j?O;RHo4Ip&KW z?)cxCZ$5eGpM&1H=$u1d`rL3Q#YaT1$L<gxw9~Fo?YP^HQ0}@D#Cz_$^PbS}y&nX8 zL$bgAkn*iJkB|fsK`;me4?W<=^$#@E03F<O-#|hPgrCOv;WMDne*#{lzkovsVBtOj z4ju5s{0BHx!2S2HG{FA*I~2hG|8t%I1p>W@NRN6BaeyEe=zxYW01ps^p!pE8fC|3h zf)!j}LK1+64ko}M1^|Ny4d4(0aN&dmaEJh|z(N5y1OPCE;Q)2Q0f}q?5gT|&1^~gs z3^e2duTqJ_1rkz$e<F_Ih()Y`LMX6>CQ`s56QF_=C!mldn&F5RC}Kh|Fo&nW!2%7@ z01x>vM2Bp^5E`)I3~}OvHn!0rLx6@Hhv1MO7~_sVa7Yh$!N(prWCx}Q<PH>)gF;^7 zkcG@aLT;dlMmF*W4Vl3oCOLzLz(5W#kVp&G$VtVx@r?}`D?&9!Nymf$;grcp<tc%X f5FNbYm9Nx6LvjF#S}M{ZGuT5VBl3cp1q1*)uD3T8 delta 1273 zcmZ{XeLT|%9LH@VPsvc{>X3Qp=QT@uaW1;E-|Rt~u?LjYOViVZx}-QR+Qh3?7srj^ z4)f}2$-^wII22|IR~d)mUOkM~!#1-mtL@dyZTJ6u-rvu|_lawb3p18T*b$lTYJ-5h z?X*FI7&I7z2C*0{AqI<&!4j}oJQhd5;$m_5SR5f1PuPVg5O)#dh$J$R6i<q?Tmm_s zl0cy)Q0Y{f<&tRhM0(=x#N<7DQ}^#rV;ne;&R{SO9sd5v(Tt3Ytjvt8jLfX;Q#qjp zuTJHhVV*vno0pfDpI=arZ=s;5h*@-w#bliq|Ku=q-i6I(_p#RxUve)muN=L+p|bMV zsw!?Zw}#8*R@c-{Rc@-St*xu88?W=3_|5xKy-!19)8D^u=J9yaMufD{Z<6Q#h!0%n z-<aVC&GL~`H-lQ+ENY)_M=i8Ov<o_(F*{Jt1>2qqLl)Y?W$j_}g75`l_%l)H+?`OF zC~USX?EM`t#hp!WL{V==(TckP@4I}Icel&CzJ1>NwW2#z(Th;_M7-<4s`>&K?nlY` zBUOD-s{R0ZfAqq@PUSuP;$Wa^5VhEkQ4HeVi81OSKrI2pVzGJ{P!FLOhnTVI2hmF- zNYz8q;zP1x46Pa^Y9DXaKKV}jn4}wz(v4$uPsr-=1ocF`R!UJ%Qni!2)zk61>D|ju zll8MS{TyBY4@3VVRsV{i(P*?<ozCL_uuRLd{Ncm06^pF#(V|Zu4F-eJY9nAY8b4cQ zGFih~CX;Dp#cW=&VrlC#n>jKlilc#g|BvAu7nti>1jNR{Y_sa<WmsCr34+CMcs=Ov zm&kYJMU+J)-<)nuX`gRqAL3kwCD{k~@zWM7N;z^Eo*6;cQaJ3)P1g&8>}UZX$vt!9 z!kY?zOvxiRJ9pgLGj{%*T{;IuzNGS^*U6NLAuuHfO7tz9qOI{fdd5wHp`z$)@8c}( z@W$wXDS}^i(=EG=$w9b_h_ml*5xz_uVM$$!3<!dIQoc;$?BG&~cY{qdl{h;NH@)E4 zLTF5^om09m+{4ZE#{kqpE)=8V$e~h*{j5fU-kJ}>p|;PnCFu2sH5BgZ4iN4fW=a&> zukQDi+Sr$AD6lU~{>31~_gXQyCX{t7<}0rNR*Wm?Tj6NC!*&4TxZXy7<6@C~_Hcz< zKa)~k-Lki(fk=R-noCCIdylkp=VqAAyy6z6W8cR)B?cJrQwfI}L8?&Vo}~f-3H0aS zwgKp0!2(fd8wk`NbV9b&9wZ_8%{hx`;0pb62T&C=)(x<rq|T;NaR|_mts4azvpX*V zs<eZSTdI%IiCefy;*dZGpkCAc`s(Lafg;irdV3Uk_W1Cyj}j#UnB;w1d*^b_io0Z; zSs^`&PNhIN@?hu5d%XIJrTZ)9eV0%$&qATtDGar}18&~{x5s&&SjKp@U0p^JgC9dC z39)6%ljLnH;g~(nRk<^%9-=Yuz@f6-sePU+<48YNQ=UUQ@16*3z19SEIuR^#TATY# zRo9PFr`%VcUY-L^O%(@~db}81=j|Kb{qn*R%YZ5I3>lM^1JTm?E3hB_1S{jx3~yE$ z0^@7jTy^C88j8R;f1PJ8P`2J~>`^wK_WAs>5D3KKdOxWv-~+G@sz&1c3sw8TqqI=_ Y(4QyOjc%3{V(%}REA%~UY;AV_3kms+CIA2c diff --git a/skins/default/images/messageicons.png b/skins/default/images/messageicons.png index 3dd37606ef47683abc6924942580314a981dee47..d45f065ea2b62f50594339a85e1372593e671122 100644 GIT binary patch literal 4062 zcmV<44<Yc0P)<h;3K|Lk000e1NJLTq000jF00DLg1^@s6v5dm^00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipi1 z4mbh=AoUXf01sYCL_t(|+U=ZsbX3*7$3JIYNr(X=U<g8quV6vD@Y;1Dq6t=|R$IM# zeNqXTLLE519|ciBDpVe7saNj6*fhgSP!Orsx7I2c!d(|6R*Q(VB%)q0#E@iWGOu&? z{UduOXP!Bs>*~5XzqL-zoHOTpetZA+@Auum{g^-&*|u$);2V*g=5IoCrgKhmk_*Wk z8Hk*<zdM>OIU34o&S}nR&dIk&JRXnmcsv=~TFC}9Ub|c_<?HJ)dMkELa`Fv}+wFd= z&rxLn3*cFxT2<AqtYEj>?Evlot^&>mPLN-{16-}D>Q}L6ZE2Kwfyrs^R{?8*pQepx zx7&Sr1|Yz@Ky@}UIA5M$0)D8fYOGq%0+WnIPFHNJJU^nU>TdaYg{rEznMqvVkmtBn zGXXPMdp<B4__?a8TDE3XGPLcb!0Es<K$ohjzFfF`_edaPNV?tb0vUSO0QZ>oFt^)% zBJiAyT>u~O0k9Q#TvgR@HqC1dKqQM)$YU(<^K4O7ErULtOqOJk9xQ`>k_>(%8T?R^ zgOM!KrxmKIcB!g*EwDmf?*<-8B8%)fNfHTkC6R?`-nIfy0ee+deaIBp?RK946ad!) z2UJykH5WSn@8UQms`?Vg2~J`rj@@qeW2&m&lg_s@#ql!P*#q3|cDpyr5~gT=J~`wJ z5(M&-(+f+MI5zrnewy?mZ5R851iqLhy|^;2IZYhLieE3!lhUOZnaCi<7$M+6RaM`R z>BY6iTujLj$Cm<|fjd=IeZ0>ZpqcbS>BUuZ=|yicc21Mk@cF8A_p|jFH;<juG(<i; zUjl~$GtGe8f!Bd6fU#reG+hGx8Td49JCB{y<N$644g-6EzX4&uA<tIe2Qu>?0<3IY zT&5|8It`H;&dy?z-N2;A#bt?s(YUy*1(+i>rIRo)HwH8o`+8}d(Iy&XuYAc?C8?P% zmvm&!p!p|_i_6|h2@KgBf9^$lqpWjFvbCoGEx^aXKA8;^7_5D!H0FuGy2iz2VI_@+ zO$P1;9+W(G5%4?U!N$d9TYGbo0g|&`1sY`?F9L@4)weIr=G)&z$u^}`BAd+Xa=G@I z8A}@FdSD`OQ=c?@Jf8l*`@k=N4Zv8J%XP%8=3fJiE|=>sz#oCfGivsDJeL7C$lSUV zcni4E<#L7P_bY)LfiGonyySAZ*2FZ=10uj8V1f}S=l^B`<0V<N0QVV-T?Lc_LtQS{ zUL(-(f_*Yq83$Yt2g`?l3S8~+cy7yJ#Hqk7z~wHN>u7?(TrO8T;0C68Jf2}mK!<Fy z7mZd=w)SwKQ*t*RkLO<vC2IppvW=_Cq(yJ=csw%!hsWd5W&iw@WRZ;E5?~ZC68HnK z2N)wKUP^(3*}yMJr+C%na<#~NJ3SuHGqU?B$k9Otsjod{_^u73p4#z;Q^%SfxyPh< zNYTFyE-jwia;UXQMv^%)IJ~2xAQa+I@kt{FwIBH`fCvp6anbH}Q)JNgrGH`3iGv4O z9sMXM9MG@*sQ<}~ns;wJ^O_R|7G7<$S<ZLZ9fJ!83@UKs=b?2S22n)F7pAkdB^U~Z zz6uA!yZpYc*CyQlKW+tJ--}}po^;BHvb@4UpobySg%&tMG|-A3wPUdiLPRa-x{Y9G z8%K|PdGs9Dr$a0Nd$#W%ceLrye}_7bK{QCzcK|JP40O=Lexe<pphx^fy8Ik#Y1x0U zx%GksgMIP#xPBdN{`%6>Mvqmr7NY(y&?6dJFpMG`=(dp@Y1+TPz+oL%Uek0e!C=EC z{#PIz2>r&_dN?YS{s>J6O#xj8%L#;i?V>9Xekuk`Y3FDtT5h#kt%|Op*h|4ufR#=} zxC=!`(L#~o8J$GewKHt?0wofHV7rd5?NCR4UO|6HUJ>X)^ibraj9{C^I?&&Gg!YzW zpM(N|NAn%_`nJPgo~uNa+Y9sT=Zat?FC#eM550Nx!{+xpI)j^AT6`b5o<#TD%-;U} z?C%uWm8o`3|0);t{}*Y6QI;-y^z^}l2S4NM>=^Txx8MFiQLMk%`rPIZ(lW`Tk1g-N zV@Jb^L4ya~a`stgl?*E#+EC|R^U8-G{`HsTqek7Xp!^9aPa%Uj_s=UT=vUA%X7u+@ z?(As)L1}48!`gN0pL_YG7nXe5+;rs4*I%2i>-x!sClrlN0N-`@y#*%^E8RJ?q@;b< z?p;eqjXLwWS6_W&OH)(Rn-^d5<4b|hpZtC8y`X&V_jUHv`Hnm9DJU;Leb>N&13Ol& zS~<V?#KCLrcKaWjo13<uG^E6xm+!dmM-wj`@bW9K+}GZIZ0e5sclXDW(Mgkj{F>e7 zh^}1ezJJ1m^PhIu9b5N({L%Ii!-ucP%g<YIw56r^<NXKj^ZR`@JL=y(2pm)ZuDR}p zGl!o%?7b~pwu~Dy=B)ej^9zbT`~1+;LraFPu-R-2T3e3}uvo13hC-p5oelMW2Mz!M z3xF1ljyiJW%Y%nLZB`r(M}22UdsXqk6IUq~%day5<4ht1?^$iOveMFFc`rP_)g6vR zF8p}k-YeT$Tl-rqwzR+mC;7=`KYLkGC_C@G^KLt9%$WV#w{QQ|p2o)NKp@~u2Tbv> zs)-kRY&QE9ilP+iy4c&=+A`<;#yzd+fSKI01Q;ZV!VetEGRn)vvtfR>pPb5SPo7cF zG%atF*8V<lF7Q1$dG?V^;QXqpiWIP1*gFfD22=urfjl`McmP;0$CfRz7uY1w0-OTe zDRb|q<PhHii~xQFxTK!VGP#ZSlKo}AJsNmIrp{Y|ZE`B}B$?q)0m|I&?xY|FE(ZQZ zPG`IUd?AbdtjvU?z?;CS@~|aqK3RfWBybCG8t`|z7dZDwcO4m<P_!841N^{1nHn2` z|1Mux02IljJz@lR$l?ANV6L1%ivf?y7oH~-d=?9o7`O#^Th7Ro13RVVEpndVCZI;P z`2kf`bz}b=k>E$=7;89in=IlPz%V(Ju~JR}rS-4@a?EszoShf|Gy@I5E5JWgRgGjy zTs!29)O)h|?9#(pfX-NPbMntJ$*ftkeg?c?0&~T(Wy}7QaA(%6S;CCWnl($9nXNFt zj?vxW2|yqKgo2`UD-kH&e}$46tZ91uQDmwew~PQq$)Z`;qM#_un>R0|hzl1kL}V+r zCRHt6x-<pc)zy{4@=2O?gaUq_-|(OS5i55#u-;u~T><oNg9)L4B2a{gStA2j=y7Er z5F(~o-b$*q5q!nN4?k?m!*YR{BLmZ7NhSj!babJk>w?*{XUl7WE_8%0%#%U<-tm&b z0}niKd}J_t_U!oQ<01pU-<OdLEXiabG!0E?XqwK_rAyH?fhKfxT}RV|c`|5kZ|`BE z92w-8Wa?C>sg1B})_79~HB+ZLMKl^sIFj!rEBNL#Cq$LaW>btu^1Y13NmuM>G%B)P zC)7E)KH2QBW{p?LXs|VFyh=106}R1fM?x4Yz<)gPI5wND2b^4_SRJF$sF*i*UYv;* zEm}y{`lqY=k|j$-vVuOnAQzAZC#k8a$!d_*t5+*o^X*luR;7Su%$ULW@#6tR@(V2K z9-c8{M#@XZj~|~>x|G?+blQzCFqXiUPIK~$cJADn@Jvljjb-)f)w=P92nK__9>$_) z)!bW^`c&s$7k<8LnzL!mNe1zHy;j5LtJ2-i*i^vHUa$9Ax|fXS16#db?@&1-w<0SU zkhJN@>-A>ebmaAV`@HGM>2&sNI`VqGrZ*iqozBEfM^2~H)TW~t&{*s~Z#r^1or#-{ zyk2jwn~t1LXX>US*&L=e9my&tSi4V~j+{<s>ZT*F*PC(Ek<;ny+omH~M{}Ewl6?Ep zY`&e7Bze9sgKwj3NjjSbZ!`?%ldiLaR~vwr|Ms`>7p(3LZ0Kmjl}naDILwtxmc(DM z%0#inwF?$NFc?3sU9cc^{F??Wf<Wzp1rP|tkJ<$b2$DL0PVDGph%N_#uV*7|7jRda zMWVC|xk11P4w~)UW15mRXU#p0@~bq)dBkk7+f6QNXW9lM%#_lWiQRMZ-Qcjz(pfh5 z6}&EqhSr${%S}<@s%6U{8s(~G%K*fay@8iY;EjtGK{y;gZd|koKrHW#hWx-2bLS>- z*b{T-;_r=yVpOvb1i>Eu@B#D8MwK5hg8hAo=YI;^l?3h+huxHhN!F)%))ZH5*ncrm zO=tFsx5#sJLz<S0%v<@=G^rxb7MYg?zK!ubapJ_|o6@POsuCMFZWL8jRek%f0vB9x zftWshdi=V!wwCSNxA)%86DCX$)z#H0FI>BJE%o*FN=9%+MMb=b*IjpA{Qjm*o8q4v z8XA<e@!ZhRpja#xMbk9=et-PXG!2Wzq8NcG;EIY0biI4>KM)ASkJ!D6ii-46RaseS zi$o$3K(pKJl$4ZouPz9I!{I=5FVu!G{MIV2dE2&aQM=uqZ?#&jPN$Rn{CxWL>qlW> zA=TB@D2fsw@kd%c;L6HMB9Ta_fB*ir_3PJ@pPx^Dem)L|gLUiHA%rN*$e!D_ZNqN2 z)6vnPH8(d~>+0%+-EPP0^=eb5Oi>g?p`oE6eLG9d6c-oc^ZA%IZ5nlTb<vud8e45` ztz2p);RPwA-`3Vfb8|Cwb#=I0E}Pfum5bWFxMyW$CAzLtU0sb3f(;usFnRK1gb=J< zyOte0c4T+Y%PzYtUTo-I463cIrM|x2Tttl=Ig+ZXDmHA`KxJhm#~YUBrY?;#aK4ga zp<@pTbKQ+qhxNDI*u&%hxzT)&VbvfQ4kTQg2HT_174juq_X!;6>g*f1{8rgVMFfFh z57-eA@$dGp=rMAN1;@-lOu1o1YLfHxA^x@srPro9XFB4FYm4L8FKljOPc7#DCrewA zqP)DZjZiqi%NyHhD^iqRQ>pS>yAMZ1FlFXw<(*9-rpz3z$U0MgYcC!)W(H)bbD}>a zKh&}dT5TPiHp)s=3lr7CJooew{`#cJ^zri{3dTBrK14B}d)lLL*Zmjs&ZZD|-G8xZ zC+QyDNDrHK?>GWoo!Fy2-|b(~i+eiKc$lep{@SdacE0EEdl0Y%`Q9kO>zjP+t~(A6 ztC+&q%waYSp1!LletpC8)xEd#uvt=L1pHm?hNkNI?u%t2GZ~zEry}P6GW7@85B>gK z{_#7}I~k0giI{%V89k}g`cK%q67ws9=S)M)e`SC;XBx+s1&*)g+qfe5znpF%KMJ)y Qt^fc407*qoM6N<$g1+h93;+NC literal 2354 zcmV-23C;G2P)<h;3K|Lk000e1NJLTq000jF00AKg1^@s6pa=T600004XF*Lt006O% z3;baP000Q-Nkl<Zc-rlm2~ZSQ8pl!0R8Y|rB_2c}Bv`O`p%@ZDZU(twI1?&~By7xL zTs0aG+{IW{5|1((Bp`TUSp~#|D=E|@hM=N|ilXRvu$7HUd4Y}$mrx*Y|8IQ6rk(ET z8Qr*B>96Wn-Tn3ZzwdkR>-VN<%*;gW@ZrP6?3tJx`B_93I?5)Syd>q#fXK5gN0ui{ zjx0x(Bg^)GXgN7KgkrMLqz;}){6uNXCfgrlSy@?MJc*cqZ-IrB#tN_mRDo6|rW^!T zhQxUs0iQB4VW^0(QZzDduIY;aT#Xtt8mwoHy*a)NsWYo&VmDJuvl4s_%uVee2+RZ4 zV5q!Q<V}DtvS15=7%Q}5i@t9ewz5ruZVn1V;xdu-oF^r6rAP;%Mva+n3Y?7ANF9F$ z=iHl#*PBuSHzrmZD>P@D!%AaBL)m6PH-#X1*~shI;5rt}NXj}E{Hc|&j_-@UUg%lJ z`;C6RpzHW)y<QyYTgRrnUX=H(V@a<UY#qlk@dEkv;(yj$Qm>eE&Q<#SV&W8FO&fz+ z<{J&>Nf9Sf5seB6Py#iG5E3Y8&ma~!Gf@}k*u(q@terW(1Da|b69`cQtb{TM<wWE| z{XzOf32a<M0%~p*_>p@=BKrxYJX%6@S_Nx;vz<)K0UTMw4&H1#u=3G%3b8uZupv;f zAFF~&>Jw(gd%|cLQ;dDKgN%B%|K#7oMuBy}$rSN?a2$MUtZ*3k4fukaGz(+In?MOW z-vYiCYa9Z0gA3puC;|%3ecC}Ys0ZJG*<A54umdClXReUb#tFoLOmLBVLjfwmA_K#j z4Qjv${*B?_2>82*@Py#xv9xK=HatJg>;PCPmex{G0fw+^H_kmeQJG@mEU*V8vkdCM z8ITIHL4lZ<mgqdF1}Wfm)=@bt<6bfGd*E$g&GQds^N}pCdI3AS-F|FMzGGh1j+b4G z7GL;o^1Q|q-b7tA@iU`@x2k4XT&<XKr$rr48h&waZzy*iE?IoBbn*tx*>KYSuOxEk zcrZD?$7zpX<5LArv6uI|=Kp%&)oTq0JvubC5v1*69MPWkB-&FUr14My`L%e;{R{a{ z*U#*H`MaZ=$ISg*e5uUkH;o#Rt|XE6e<zam%PP`R>rOOB9m$<T6N#qMo7}DNB~9f@ z(oi~`)aKYW{Vpz8Hh5(HUY8S^x+v0KAB|{}$h~T3h#X1d0ejN8*M>Cx<VJ3kxs!9- z>@F9t7}9?`zH#ui!Iw%V)@tkG5!IJyjv#7<1G&B5mNf2jAh&+<Cug^gyIjBPr5E&$ zy)JKj?DYz-Zta;!a`(`9a_8sq<o4dNr11wAa;<oJZ}pd>gg1lJJMCB8I_%rqaypD? zs=UbE%30{Zoiy#6N*W5MlcVdbwhD@Cw%g|3ITk|h9t$Ja_s=Ak^PRO<i(JXgGB48b zjT@<4ZCNTPKC{!l<Z78Ksmpz({$%EuIp?<7PN?2E;+^B`t!vJw+mOR6p5HGhuFA0a z@aMH7Ru%ta=!Bd(W&?E_!5p&z1q+|ED_f#i`QxHN^W;_k-?nw@H#qFrx$9JV`sU6k zRrE<!blfDt#v8uaG%PwMe)szyq*!jw$aE+yENTh~jo58#_tLb0z*)PLfk9W$?D6-{ z)D>x#nOm~eX=$I7zwu_G$G3%rO%ai*9NcmSFM>h-0fF5^hFbRD+df+KvBg(kWvPpb zOR9oHLIXcpwfc7QUq8s6JY{NJfO3}Zw|nch?aTcGX3@xx#0wTKw#dxdqRz`NIOgf) zrHqJ*z8Mpjuw}a2Yl%p?Srrrew~UO;Wx*j~_uM^Z(!X>bt?9IttI9WSOh4)}b(#+{ zXncQ8icYACj?u)%CoJ&t_W7r;f1uXg!!ruaCxgK{VQl;xP76O;)G^N1Zc<QiXkL^m z_IoM}3y;)9sbc1PdU>aL`}k>JpW&hEC#0r|j*WaX@hvsIfytTc@2}J<1A|+_BUKAT zh13vf+*|J?wT~HN^D4de^zxZzYis8_bEX%B{=&jO3l0h27ZMtN;nUC7_?MP`KW_2j zC7b>HmCXi)edg`sn}ZtOL|Iz=`~$0}xJ>nxB;?pA_CQe4D|(+K+4O$jwPYVx6jDWl zz>6RNECZP!9!z52j0Ok^=|A?SF~K=-6KKFS@C$ekjC`yEI0gboup3+jpMw|>2Ntn! zgvVJ2mVEIGU@@oxAA_;1!%^%j<O$Y61slQuuGpUaOR*SCVZxE@lidy0!9tc*BzTT1 zp2EH=ehF-N!b+9_{jPrj%<q>vF8%`cf?e#t2VCJumI?hf)&SlH&vV7JJR8ADP{L-K zE2Q^VgG<1d`uJsv0B3=kbwD#1&4#p$l`IF0<Ina0FpQ;C&oZDx*u-Y}G{^-m{U(do z$#4(`(!r0Q8th>+?I<YZWT0R(K7mDYV4V(>SN+qnrAwEF10sQNePSZTXuGE`?(OXb z56A<`gNNr2uX}aAUibvX-Q7K)oAgk6x^?F|*g5qHin}^HNmo~w-if0APIgbPxTB*( zhd$HYyWb%!Zfk8Lt!-_(V_RDvtq-qTTXpAx;udWS&=PG6py%wUZDD?#3yPbYn++l) zHvI{cP2LPl+6*50Oxz3}`kuvRz?}!9Hv^r|)XjjJycx*$bZqwQcZn1P#XUVe{owmV z#m_FXA)irV8cpolU}Q;S*LRafN}2m1NlAIcT<};1{K?|_Q<tZb<*5Ki!PJF}3f8V& zYrN3lWc^t!DJhAFVNl$OA38qNpPij8-a((ZFA`rY+JT|Sq8;!f>$~PKP*P-lnMjJv z$Dmk_Y(!+K$U6bYa&vRdIp->Uelc+hu%?YcE%S{A^Q4Fqsfb1e1So+TL<k8Kv}X_t zoSCSLbL?UM1lG=+-vLdvjtPXQ0aij8gmNPCq5dF!q69WBA^|nG3jD}DB9Z-sQXVZK zI<11WzS&Nu<p7SXVFz!v9a#BjJB3)CYuFH|*pF2~CG`oj;yq!sj48%G+d)P>+kcq- Y2g+4l(_=2VXaE2J07*qoM6N<$f}rSvD*ylh diff --git a/skins/default/includes/messagetoolbar.html b/skins/default/includes/messagetoolbar.html index f670182..57bed8a 100644 --- a/skins/default/includes/messagetoolbar.html +++ b/skins/default/includes/messagetoolbar.html @@ -19,7 +19,7 @@ <roundcube:if condition="template:name == 'mail'" /> <roundcube:button name="markmenulink" id="markmenulink" type="link" class="button markmessage" title="markmessages" onclick="rcmail_ui.show_popup('markmenu');return false" content=" " /> <roundcube:endif /> -<roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button messagemenu" title="messageactions" onclick="rcmail_ui.show_popup('messagemenu');return false" content=" " /> +<roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button messagemenu" title="moreactions" onclick="rcmail_ui.show_popup('messagemenu');return false" content=" " /> <roundcube:if condition="template:name == 'message'" /> <roundcube:object name="mailboxlist" type="select" noSelection="moveto" maxlength="25" onchange="rcmail.command('moveto', this.options[this.selectedIndex].value)" class="mboxlist" folder_filter="mail" /> <roundcube:endif /> diff --git a/skins/default/mail.css b/skins/default/mail.css index a4ae57d..4dfc206 100644 --- a/skins/default/mail.css +++ b/skins/default/mail.css @@ -435,6 +435,7 @@ padding-top: 2px; padding-bottom: 2px; text-decoration: none; + height: 15px; } #mailboxlist li.unread @@ -701,7 +702,8 @@ body.messagelist #messagelist tr td.flag span, #messagelist tr td.status span, -#messagelist tr td.attachment span +#messagelist tr td.attachment span, +#messagelist tr td.priority span { display: block; width: 15px; @@ -712,6 +714,12 @@ body.messagelist #messagelist tr td.threads div.listmenu, #messagelist tr td.attachment span.attachment, #messagelist tr td.attachment span.report, +#messagelist tr td.priority span.priority, +#messagelist tr td.priority span.prio1, +#messagelist tr td.priority span.prio2, +#messagelist tr td.priority span.prio3, +#messagelist tr td.priority span.prio4, +#messagelist tr td.priority span.prio5, #messagelist tr td.flag span.flagged, #messagelist tr td.flag span.unflagged, #messagelist tr td.flag span.unflagged:hover, @@ -744,6 +752,36 @@ body.messagelist background-position: 0 -255px; } +#messagelist tr td.priority span.priority +{ + background-position: 0 -309px; +} + +#messagelist tr td.priority span.prio5 +{ + background-position: 0 -358px; +} + +#messagelist tr td.priority span.prio4 +{ + background-position: 0 -340px; +} + +#messagelist tr td.priority span.prio3 +{ + background-position: 0 -324px; +} + +#messagelist tr td.priority span.prio2 +{ + background-position: 0 -309px; +} + +#messagelist tr td.priority span.prio1 +{ + background-position: 0 -290px; +} + #messagelist tr td.flag span.flagged { background-position: 0 -153px; @@ -839,7 +877,8 @@ body.messagelist #messagelist tr td.attachment, #messagelist tr td.threads, #messagelist tr td.status, -#messagelist tr td.flag +#messagelist tr td.flag, +#messagelist tr td.priority { width: 17px; padding: 0 0 0 2px; @@ -872,13 +911,6 @@ body.messagelist background-color: #FFF; } -/* -#messagelist tr.odd -{ - background-color: #F9F9F9; -} -*/ - #messagelist tr.unread { font-weight: bold; @@ -1166,21 +1198,20 @@ div.message-htmlpart div.rcmBody margin: 8px; } -#remote-objects-message +#message-objects div { - display: none; margin: 8px; min-height: 20px; padding: 10px 10px 6px 46px; } -#remote-objects-message a +#message-objects div a { color: #666666; padding-left: 10px; } -#remote-objects-message a:hover +#message-objects div a:hover { color: #333333; } diff --git a/skins/default/print.css b/skins/default/print.css index 76c3e0c..afdf674 100644 --- a/skins/default/print.css +++ b/skins/default/print.css @@ -2,14 +2,14 @@ body { + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff; color: #000000; margin: 2mm; } -body, td, th, span, div, p, h3 +body, td, th, span, div, p { - font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; font-size: 9pt; color: #000000; } diff --git a/skins/default/templates/addressbook.html b/skins/default/templates/addressbook.html index a85c889..1930deb 100644 --- a/skins/default/templates/addressbook.html +++ b/skins/default/templates/addressbook.html @@ -58,7 +58,7 @@ </div> <div class="boxfooter"> <roundcube:button command="group-create" type="link" title="newcontactgroup" class="buttonPas addgroup" classAct="button addgroup" content=" " /> - <roundcube:button name="groupmenulink" id="groupmenulink" type="link" title="groupactions" class="button groupactions" onclick="rcmail_ui.show_popup('groupmenu');return false" content=" " /> + <roundcube:button name="groupmenulink" id="groupmenulink" type="link" title="moreactions" class="button groupactions" onclick="rcmail_ui.show_popup('groupmenu');return false" content=" " /> </div> </div> @@ -99,6 +99,8 @@ <ul> <li><roundcube:button command="group-rename" label="grouprename" classAct="active" /></li> <li><roundcube:button command="group-delete" label="groupdelete" classAct="active" /></li> + <li class="separator_above"><roundcube:button command="search-create" label="searchsave" classAct="active" /></li> + <li><roundcube:button command="search-delete" label="searchdelete" classAct="active" /></li> <roundcube:container name="groupoptions" id="groupoptionsmenu" /> </ul> </div> diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html index ea6a2f7..30b56aa 100644 --- a/skins/default/templates/mail.html +++ b/skins/default/templates/mail.html @@ -166,6 +166,7 @@ <li><input type="checkbox" name="list_col[]" value="status" id="cols_status" /><label for="cols_status"><roundcube:label name="readstatus" /></label></li> <li><input type="checkbox" name="list_col[]" value="attachment" id="cols_attachment" /><label for="cols_attachment"><roundcube:label name="attachment" /></label></li> <li><input type="checkbox" name="list_col[]" value="flag" id="cols_flag" /><label for="cols_flag"><roundcube:label name="flag" /></label></li> + <li><input type="checkbox" name="list_col[]" value="priority" id="cols_priority" /><label for="cols_priority"><roundcube:label name="priority" /></label></li> </ul> </fieldset> <roundcube:endif /> diff --git a/skins/default/templates/message.html b/skins/default/templates/message.html index 8e2bb2c..714540b 100644 --- a/skins/default/templates/message.html +++ b/skins/default/templates/message.html @@ -36,8 +36,7 @@ <roundcube:object name="messageHeaders" class="headers-table" cellspacing="0" cellpadding="2" addicon="/images/icons/silhouette.png" summary="Message headers" /> <roundcube:object name="messageFullHeaders" id="full-headers" /> <roundcube:object name="messageAttachments" id="attachment-list" /> - -<roundcube:object name="blockedObjects" id="remote-objects-message" /> +<roundcube:object name="messageObjects" id="message-objects" /> <roundcube:object name="messageBody" id="messagebody" /> </div> <div class="boxfooter"> diff --git a/skins/default/templates/messagepreview.html b/skins/default/templates/messagepreview.html index bfd7d7d..a606311 100644 --- a/skins/default/templates/messagepreview.html +++ b/skins/default/templates/messagepreview.html @@ -13,7 +13,7 @@ <roundcube:object name="messageAttachments" id="attachment-list" /> </div> -<roundcube:object name="blockedObjects" id="remote-objects-message" /> +<roundcube:object name="messageObjects" id="message-objects" /> <roundcube:object name="messageBody" id="messagebody" /> </body> -- 2.39.5