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)
+
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)
--- /dev/null
+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")
+}
+
+
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
GO\r
\r
+CREATE TABLE [dbo].[cache_index] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[cache_thread] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[cache_messages] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [uid] [int] NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+ [flags] [int](1) NOT NULL ,\r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
CREATE TABLE [dbo].[contacts] (\r
[contact_id] [int] IDENTITY (1, 1) NOT NULL ,\r
[user_id] [int] NOT NULL ,\r
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
GO\r
\r
-CREATE TABLE [dbo].[messages] (\r
- [message_id] [int] IDENTITY (1, 1) NOT NULL ,\r
- [user_id] [int] NOT NULL ,\r
- [del] [tinyint] NOT NULL ,\r
- [cache_key] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [created] [datetime] NOT NULL ,\r
- [idx] [int] NOT NULL ,\r
- [uid] [int] NOT NULL ,\r
- [subject] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [from] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [to] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [cc] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [date] [datetime] NOT NULL ,\r
- [size] [int] NOT NULL ,\r
- [headers] [text] COLLATE Latin1_General_CI_AI NOT NULL ,\r
- [structure] [text] COLLATE Latin1_General_CI_AI NULL \r
-) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
-GO\r
-\r
CREATE TABLE [dbo].[session] (\r
- [sess_id] [varchar] (32) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
[created] [datetime] NOT NULL ,\r
[changed] [datetime] NULL ,\r
[ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL ,\r
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
GO\r
\r
+CREATE TABLE [dbo].[dictionary] (\r
+ [user_id] [int] ,\r
+ [language] [varchar] (5) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[searches] (\r
+ [search_id] [int] IDENTITY (1, 1) NOT NULL ,\r
+ [user_id] [int] NOT NULL ,\r
+ [type] [tinyint] NOT NULL ,\r
+ [name] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
ALTER TABLE [dbo].[cache] WITH NOCHECK ADD \r
PRIMARY KEY CLUSTERED \r
(\r
) ON [PRIMARY] \r
GO\r
\r
+ALTER TABLE [dbo].[cache_index] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox],[uid]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
ALTER TABLE [dbo].[contacts] WITH NOCHECK ADD \r
CONSTRAINT [PK_contacts_contact_id] PRIMARY KEY CLUSTERED \r
(\r
) ON [PRIMARY] \r
GO\r
\r
-ALTER TABLE [dbo].[messages] WITH NOCHECK ADD \r
- PRIMARY KEY CLUSTERED \r
- (\r
- [message_id]\r
- ) ON [PRIMARY] \r
-GO\r
-\r
ALTER TABLE [dbo].[session] WITH NOCHECK ADD \r
CONSTRAINT [PK_session_sess_id] PRIMARY KEY CLUSTERED \r
(\r
) ON [PRIMARY] \r
GO\r
\r
+ALTER TABLE [dbo].[searches] WITH NOCHECK ADD \r
+ CONSTRAINT [PK_searches_search_id] PRIMARY KEY CLUSTERED \r
+ (\r
+ [search_id]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
ALTER TABLE [dbo].[cache] ADD \r
CONSTRAINT [DF_cache_user_id] DEFAULT ('0') FOR [user_id],\r
CONSTRAINT [DF_cache_cache_key] DEFAULT ('') FOR [cache_key],\r
CREATE INDEX [IX_cache_created] ON [dbo].[cache]([created]) ON [PRIMARY]\r
GO\r
\r
+ALTER TABLE [dbo].[cache_index] ADD \r
+ CONSTRAINT [DF_cache_index_changed] DEFAULT (getdate()) FOR [changed],\r
+ CONSTRAINT [DF_cache_index_valid] DEFAULT ('0') FOR [valid]\r
+GO\r
+\r
+CREATE INDEX [IX_cache_index_user_id] ON [dbo].[cache_index]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] ADD \r
+ CONSTRAINT [DF_cache_thread_changed] DEFAULT (getdate()) FOR [changed]\r
+GO\r
+\r
+CREATE INDEX [IX_cache_thread_user_id] ON [dbo].[cache_thread]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] ADD \r
+ CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed],\r
+ CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags],\r
+GO\r
+\r
+CREATE INDEX [IX_cache_messages_user_id] ON [dbo].[cache_messages]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
ALTER TABLE [dbo].[contacts] ADD \r
CONSTRAINT [DF_contacts_user_id] DEFAULT (0) FOR [user_id],\r
CONSTRAINT [DF_contacts_changed] DEFAULT (getdate()) FOR [changed],\r
CREATE INDEX [IX_identities_user_id] ON [dbo].[identities]([user_id]) ON [PRIMARY]\r
GO\r
\r
-ALTER TABLE [dbo].[messages] ADD \r
- CONSTRAINT [DF_messages_user_id] DEFAULT (0) FOR [user_id],\r
- CONSTRAINT [DF_messages_del] DEFAULT (0) FOR [del],\r
- CONSTRAINT [DF_messages_cache_key] DEFAULT ('') FOR [cache_key],\r
- CONSTRAINT [DF_messages_created] DEFAULT (getdate()) FOR [created],\r
- CONSTRAINT [DF_messages_idx] DEFAULT (0) FOR [idx],\r
- CONSTRAINT [DF_messages_uid] DEFAULT (0) FOR [uid],\r
- CONSTRAINT [DF_messages_subject] DEFAULT ('') FOR [subject],\r
- CONSTRAINT [DF_messages_from] DEFAULT ('') FOR [from],\r
- CONSTRAINT [DF_messages_to] DEFAULT ('') FOR [to],\r
- CONSTRAINT [DF_messages_cc] DEFAULT ('') FOR [cc],\r
- CONSTRAINT [DF_messages_date] DEFAULT (getdate()) FOR [date],\r
- CONSTRAINT [DF_messages_size] DEFAULT (0) FOR [size]\r
-GO\r
-\r
-CREATE INDEX [IX_messages_user_id] ON [dbo].[messages]([user_id]) ON [PRIMARY]\r
-GO\r
-\r
-CREATE INDEX [IX_messages_cache_key] ON [dbo].[messages]([cache_key]) ON [PRIMARY]\r
-GO\r
-\r
-CREATE INDEX [IX_messages_uid] ON [dbo].[messages]([uid]) ON [PRIMARY]\r
-GO\r
-\r
-CREATE INDEX [IX_messages_created] ON [dbo].[messages]([created]) ON [PRIMARY]\r
-GO\r
-\r
ALTER TABLE [dbo].[session] ADD \r
CONSTRAINT [DF_session_sess_id] DEFAULT ('') FOR [sess_id],\r
CONSTRAINT [DF_session_created] DEFAULT (getdate()) FOR [created],\r
CREATE INDEX [IX_users_alias] ON [dbo].[users]([alias]) ON [PRIMARY]\r
GO\r
\r
+CREATE UNIQUE INDEX [IX_dictionary_user_language] ON [dbo].[dictionary]([user_id],[language]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[searches] ADD \r
+ CONSTRAINT [DF_searches_user] DEFAULT (0) FOR [user_id],\r
+ CONSTRAINT [DF_searches_type] DEFAULT (0) FOR [type],\r
+GO\r
+\r
+CREATE UNIQUE INDEX [IX_searches_user_type_name] ON [dbo].[searches]([user_id],[type],[name]) ON [PRIMARY]\r
+GO\r
+\r
ALTER TABLE [dbo].[identities] ADD CONSTRAINT [FK_identities_user_id] \r
FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
ON DELETE CASCADE ON UPDATE CASCADE\r
ON DELETE CASCADE ON UPDATE CASCADE\r
GO\r
\r
-ALTER TABLE [dbo].[messages] ADD CONSTRAINT [FK_messages_user_id]\r
+ALTER TABLE [dbo].[cache_index] ADD CONSTRAINT [FK_cache_index_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] ADD CONSTRAINT [FK_cache_thread_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] ADD CONSTRAINT [FK_cache_messages_user_id]\r
FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
ON DELETE CASCADE ON UPDATE CASCADE\r
GO\r
ON DELETE CASCADE ON UPDATE CASCADE\r
GO\r
\r
+ALTER TABLE [dbo].[searches] ADD CONSTRAINT [FK_searches_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
-- Use trigger instead of foreign key (#1487112)\r
-- "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths."\r
CREATE TRIGGER [contact_delete_member] ON [dbo].[contacts]\r
GO\r
DELETE FROM [dbo].[cache]\r
GO\r
+\r
+-- Updates from version 0.6\r
+\r
+CREATE TABLE [dbo].[dictionary] (\r
+ [user_id] [int] ,\r
+ [language] [varchar] (5) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+CREATE UNIQUE INDEX [IX_dictionary_user_language] ON [dbo].[dictionary]([user_id],[language]) ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[searches] (\r
+ [search_id] [int] IDENTITY (1, 1) NOT NULL ,\r
+ [user_id] [int] NOT NULL ,\r
+ [type] [tinyint] NOT NULL ,\r
+ [name] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[searches] WITH NOCHECK ADD \r
+ CONSTRAINT [PK_searches_search_id] PRIMARY KEY CLUSTERED \r
+ (\r
+ [search_id]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[searches] ADD \r
+ CONSTRAINT [DF_searches_user] DEFAULT (0) FOR [user_id],\r
+ CONSTRAINT [DF_searches_type] DEFAULT (0) FOR [type],\r
+GO\r
+\r
+CREATE UNIQUE INDEX [IX_searches_user_type_name] ON [dbo].[searches]([user_id],[type],[name]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[searches] ADD CONSTRAINT [FK_searches_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+DROP TABLE [dbo].[messages]\r
+GO\r
+CREATE TABLE [dbo].[cache_index] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[cache_thread] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+CREATE TABLE [dbo].[cache_messages] (\r
+ [user_id] [int] NOT NULL ,\r
+ [mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,\r
+ [uid] [int] NOT NULL ,\r
+ [changed] [datetime] NOT NULL ,\r
+ [data] [text] COLLATE Latin1_General_CI_AI NOT NULL \r
+ [flags] [int] NOT NULL ,\r
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_index] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] WITH NOCHECK ADD \r
+ PRIMARY KEY CLUSTERED \r
+ (\r
+ [user_id],[mailbox],[uid]\r
+ ) ON [PRIMARY] \r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_index] ADD \r
+ CONSTRAINT [DF_cache_index_changed] DEFAULT (getdate()) FOR [changed],\r
+ CONSTRAINT [DF_cache_index_valid] DEFAULT ('0') FOR [valid]\r
+GO\r
+\r
+CREATE INDEX [IX_cache_index_user_id] ON [dbo].[cache_index]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] ADD \r
+ CONSTRAINT [DF_cache_thread_changed] DEFAULT (getdate()) FOR [changed]\r
+GO\r
+\r
+CREATE INDEX [IX_cache_thread_user_id] ON [dbo].[cache_thread]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] ADD \r
+ CONSTRAINT [DF_cache_messages_changed] DEFAULT (getdate()) FOR [changed],\r
+ CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags]\r
+GO\r
+\r
+CREATE INDEX [IX_cache_messages_user_id] ON [dbo].[cache_messages]([user_id]) ON [PRIMARY]\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_index] ADD CONSTRAINT [FK_cache_index_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_thread] ADD CONSTRAINT [FK_cache_thread_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+ALTER TABLE [dbo].[cache_messages] ADD CONSTRAINT [FK_cache_messages_user_id]\r
+ FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])\r
+ ON DELETE CASCADE ON UPDATE CASCADE\r
+GO\r
+\r
+-- Updates from version 0.7-beta
+
+ALTER TABLE [dbo].[session] ALTER COLUMN [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL
+GO
+
-- 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,
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),
) /*!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` (
) /*!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` (
) /*!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 */;
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;
--
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,
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,
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
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);
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);
-- Roundcube Webmail initial database structure
--
--- Table structure for table `cache`
+-- Table structure for table cache
--
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);
--
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 '',
-- --------------------------------------------------------
---
--- 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);
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);
| 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();
unset($row['words']);
$contacts->update($row['ID'], $row);
}
-
+
echo "done.\n";
}
| 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 $
*/
$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;
}
#!/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
exit 1
fi
+if [ ! -w "$JAR_DIR" ]; then
+ JAR_DIR=`dirname "$0"`
+fi
+
if java -version >/dev/null 2>&1; then
:
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
// 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
| 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 |
| |
+-----------------------------------------------------------------------+
// 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
$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
// 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
// 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';
// 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;
// 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
'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)
'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
),
);
*/
// 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
// ----------------------------------
// 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;
// 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
/*
+-------------------------------------------------------------------------+
| Roundcube Webmail IMAP Client |
- | Version 0.6 |
+ | Version 0.7 |
| |
| Copyright (C) 2005-2011, The Roundcube Dev Team |
| |
| 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 $
*/
// 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();
)
);
}
-
+
if ($session_error || $_REQUEST['_err'] == 'session')
$OUTPUT->show_message('sessionerror', 'error', null, true, -1);
// 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");
}
}
}
}
+// 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();
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']);
}
$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;
// 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);
}
$current = $this->config;
$this->config = array();
$this->load_defaults();
-
+
foreach ($this->replaced_config as $prop => $replacement) {
if (isset($current[$prop])) {
if ($prop == 'skin_path')
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];
}
}
- 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()';
<?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);
/**
* ACL plugin script
*
- * @version 0.6.1
+ * @version 0.6.3
* @author Aleksander Machniak <alec@alec.pl>
*/
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
/**
* Folders Access Control Lists Management (RFC4314, RFC2086)
*
- * @version 0.6.1
+ * @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*
*
$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'];
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();
}
'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),
$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];
background-color: #CC3333;
}
+#acltable tr.unfocused td
+{
+ color: #FFFFFF;
+ background-color: #929292;
+}
+
#acladvswitch
{
position: absolute;
// 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 + ')');
})
}
// 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();
$labels = array();
$labels['buttontitle'] = 'Archiver ce message';
-$labels['archived'] = 'Message archivé avec success';
+$labels['archived'] = 'Message archivé avec success';
$labels['archivefolder'] = 'Archive';
?>
<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>
<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>
- 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
+++ /dev/null
-<?php
-
-// Enigma Plugin options
-// --------------------
-
-// A driver to use for PGP. Default: "gnupg".
-$rcmail_config['enigma_pgp_driver'] = 'gnupg';
-
-// A driver to use for S/MIME. Default: "phpssl".
-$rcmail_config['enigma_smime_driver'] = 'phpssl';
-
-// Keys directory for all users. Default 'enigma/home'.
-// Must be writeable by PHP process
-$rcmail_config['enigma_pgp_homedir'] = null;
--- /dev/null
+<?php
+
+// Enigma Plugin options
+// --------------------
+
+// A driver to use for PGP. Default: "gnupg".
+$rcmail_config['enigma_pgp_driver'] = 'gnupg';
+
+// A driver to use for S/MIME. Default: "phpssl".
+$rcmail_config['enigma_smime_driver'] = 'phpssl';
+
+// Keys directory for all users. Default 'enigma/home'.
+// Must be writeable by PHP process
+$rcmail_config['enigma_pgp_homedir'] = null;
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(
return $args;
}
-
+
function logout($args)
{
// redirect to configured URL in order to clear HTTP auth credentials
+- 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]
-----------------------------------------------------------
// 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
// 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();
+
?>
<?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
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
}
$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() {
{
if ($this->exts)
return $this->exts;
-
+
if (!$this->sieve)
return $this->_set_error(SIEVE_ERROR_INTERNAL);
*/
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');
+ }
}
}
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;
<?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
'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);
}
/**
*
* @param string Rule name
* @param array Rule content (as array)
+ *
+ * @return int The index of the new rule
*/
public function add_rule($content)
{
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;
}
/**
*/
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));
$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];
$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));
}
// ...and actions block
- if ($tests) {
- $actions = $this->_parse_actions($content);
- }
+ $actions = $this->_parse_actions($content);
if ($tests && $actions) {
$result = array(
/**
* 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;
'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
* @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
*/
$str = substr($str, 1);
if ($num === true) {
$result[] = $sep;
- break 2;
+ break 2;
}
break;
// String atom
default:
// empty or one character
- if ($str === '') {
+ if ($str === '' || $str === null) {
break 2;
}
if (strlen($str) < 2) {
<?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';
$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';
$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';
-
-?>
<?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';
$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';
$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';
$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'
-
-?>
$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';
$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!';
?>
$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';
$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';
?>
--- /dev/null
+<?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'
+
+?>
$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';
$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';
$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.';
?>
$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';
-/* 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)
};
/*********************************************************/
-/********* Managesieve filters methods *********/
+/********* Managesieve UI methods *********/
/*********************************************************/
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)
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);
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);
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);
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)
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),
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 (!?)
+}
* 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
* 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;
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
$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];
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();
}
$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;
}
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))
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);
$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'])) {
// 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',
show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
}
else {
- $error = 'fileuploaderror';
+ $this->errors['file'] = $this->gettext('fileuploaderror');
}
}
}
$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');
}
}
$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)
}
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;
$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++;
}
}
$i++;
}
- if (!$this->errors) {
+ if (!$this->errors && !$error) {
// zapis skryptu
if (!isset($this->script[$fid])) {
$fid = $this->sieve->script->add_rule($this->form);
$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');
$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');
}
// 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;
}
$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>';
// 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>';
$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;
}
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';
$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');
$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').'
. ($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" : '';
$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');
// 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";
// 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>';
$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>';
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;
+ }
}
--- /dev/null
+<?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>
-/***** 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
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;
}
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
{
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
input.radio
{
border: 0;
+ margin-top: 0;
}
+select.operator_selector
+{
+ width: 200px;
+}
+
+td.rowtargets span,
span.label
{
color: #666666;
padding-top: 5px;
width: 100%;
}
-
+
#footer .footerleft
{
padding-left: 2px;
{
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;
+}
--- /dev/null
+#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;
+}
<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" />
<input type="checkbox" id="disabled" name="_disabled" value="1" />
</div>
</div>
+<roundcube:endif />
</form>
</div>
-
</body>
</html>
<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>
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")
{
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 */ {
}
# 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"
{
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
{
{
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;
}
--- /dev/null
+--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";
+}
--- /dev/null
+--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"];
+}
--- /dev/null
+--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";
+}
--- /dev/null
+--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
--- /dev/null
+--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";
--- /dev/null
+--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";
+}
--- /dev/null
+--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;
+}
--- /dev/null
+--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*";
--- /dev/null
+--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;
+}
--- /dev/null
+<?php
+
+$labels = array();
+$labels['identitydialogtitle'] = 'Моля попълнете Вашите данни.';
+$labels['identitydialoghint'] = 'Това съобщение се появява само при първото влизане.';
+
+?>
\ No newline at end of file
// Enables sound notification
$rcmail_config['newmail_notifier_sound'] = false;
+// Enables desktop notification
+$rcmail_config['newmail_notifier_desktop'] = false;
+
?>
--- /dev/null
+<?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.';
+
+?>
--- /dev/null
+<?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.';
+
+?>
<?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.';
?>
--- /dev/null
+<?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.';
+
+?>
<?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.';
?>
--- /dev/null
+<?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';
+
+?>
--- /dev/null
+<?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
/**
* New Mail Notifier plugin script
*
- * @version 0.2
+ * @version 0.3
* @author Aleksander Machniak <alec@alec.pl>
*/
newmail_notifier_basic();
if (prop.sound)
newmail_notifier_sound();
+ if (prop.desktop)
+ newmail_notifier_desktop(rcmail.gettext('body', 'newmail_notifier'));
}
// Stops notification
// 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);
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();
+}
* 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>
*
*
public $task = 'mail|settings';
private $rc;
+ private $notified;
/**
* Plugin initialization
$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');
}
}
// 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;
$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;
*/
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;
// 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';
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;
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;
*
* Driver for passwords stored in SQL database
*
- * @version 1.3
+ * @version 1.4
* @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl>
*
*/
// 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);
}
$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;
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);
}
}
}
+ $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);
<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>
</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="/">
<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>
- 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>
{
$config = rcmail::get_instance()->config;
$driver = $this->home.'/drivers/'.$config->get('password_driver', 'sql').'.php';
-
+
if (!is_readable($driver)) {
raise_error(array(
'code' => 600,
), true, false);
return $this->gettext('internalerror');
}
-
+
include($driver);
if (!function_exists('password_save')) {
}
return $reason;
- }
+ }
}
--- /dev/null
+<?php
+
+$labels = array();
+$labels['userinfo'] = 'Info utilisateur';
+$labels['created'] = 'Date de création';
+$labels['lastlogin'] = 'Dernière connexion';
+$labels['defaultidentity'] = 'Identité principale';
+
+?>
--- /dev/null
+<?php
+
+$labels = array();
+$labels['userinfo'] = 'Informatii utilisator';
+$labels['created'] = 'Data creatiei';
+$labels['lastlogin'] = 'Ultima conectare';
+$labels['defaultidentity'] = 'Identitate principala';
+
+?>
| 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 $
*/
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
| 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 $
*/
}
// 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));
| 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 $
*/
*
* @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);
}
// 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));
}
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);
}
/**
* 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
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;
}
/**
* @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;
}
/**
* 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, '_');
}
/**
* @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);
- }
+}
/**
* @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;
}
{
$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;
}
* 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);
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
$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();
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;
}
$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'),
$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 {
}
// 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)
}
$out .= "</li>\n";
- $idx++;
}
return $out;
* @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;
$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);
$hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode));
if ($hook['abort'])
- return;
+ return;
$lang = strtolower($_SESSION['language']);
$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');
}
$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');
}
| |
| 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: |
| 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 $
*/
}
// 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;
}
'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'),
);
}
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
// 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),
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');
$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'));
}
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();
}
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(
// 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_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);
/**
* 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)
$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 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;
}
/**
// before closing the database connection, write session data
if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {
- $this->session->cleanup();
session_write_close();
}
{
$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'];
}
// use strtr behaviour of going through source string once
$cmd = strtr($cmd, $replacements);
-
+
return (string)shell_exec($cmd);
}
}
}
}
-
+
/**
* Returns current action filename
*
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
--- /dev/null
+<?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();
+ }
+
+}
| 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 $
*/
/** 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;
public $primary_key;
public $groups = false;
public $readonly = true;
+ public $searchonly = false;
public $undelete = false;
public $ready = false;
public $group_id = null;
*
* @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
* 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;
}
}
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
*
{
$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);
}
| 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 $
*/
$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);
| 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 $
*/
* @package Cache
* @author Thomas Bruederli <roundcube@gmail.com>
* @author Aleksander Machniak <alec@alec.pl>
- * @version 1.0
+ * @version 1.1
*/
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.
*/
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').
$this->cache_sums[$key] = $md5sum;
$this->cache_keys[$key] = $sql_arr['cache_id'];
}
+ else {
+ $this->cache[$key] = null;
+ }
}
return $this->cache[$key];
| 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 $
*/
// 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;
}
{
$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(
$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']);
}
}
/**
- * 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'));
}
/**
| 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 $
*/
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',
// public properties
public $primary_key = 'contact_id';
+ public $name;
public $readonly = false;
public $groups = true;
public $undelete = true;
}
+ /**
+ * 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
*
*
* @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);
$required = array($required);
$where = $and_where = array();
+ $mode = intval($mode);
foreach ($fields as $idx => $col) {
// direct ID search
// 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))
$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;
+ }
}
}
}
* 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;
}
$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;
$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;
| 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 $
*/
| 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: |
| 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 $
*/
*/
class rcube_imap
{
- public $debug_level = 1;
public $skip_deleted = false;
public $page_size = 10;
public $list_page = 1;
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
* @var rcube_cache
*/
private $cache;
+
+ /**
+ * Internal (in-memory) cache
+ *
+ * @var array
+ */
+ private $icache = array();
+
private $mailbox = 'INBOX';
private $delimiter = NULL;
private $namespace = NULL;
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;
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
'MESSAGE-ID',
'CONTENT-TRANSFER-ENCODING',
'REFERENCES',
- 'X-PRIORITY',
'X-DRAFT-INFO',
'MAIL-FOLLOWUP-TO',
'MAIL-REPLY-TO',
$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'];
function close()
{
$this->conn->closeConnection();
+ if ($this->mcache)
+ $this->mcache->close();
}
}
+ /**
+ * 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
*
*/
function get_mailbox_name()
{
- return $this->conn->connected() ? $this->mailbox : '';
+ return $this->mailbox;
}
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
$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);
$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);
}
}
}
'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]),
$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);
}
* @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();
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);
}
// 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);
$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);
* @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);
/**
- * 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,
* @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);
}
// 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))
// 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
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);
$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);
$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);
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))
$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);
/**
- * 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;
}
$this->_messagecount($mailbox, 'ALL', true);
$result = 0;
+
+ if (empty($old)) {
+ return $result;
+ }
+
$new = $this->get_folder_stats($mailbox);
// got new messages
}
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")
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();
}
// 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);
* 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
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);
}
- /**
- * @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
*
* @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)
{
* @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)
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
);
}
$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');
}
if ($orig_criteria == 'ALL') {
- $max = $this->_messagecount($mailbox);
+ $max = $this->_messagecount($mailbox, 'ALL', true, false);
$a_messages = $max ? range(1, $max) : array();
}
else {
* @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)
{
$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))
* @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);
}
}
/**
* 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)
{
{
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();
}
/**
* 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;
/**
- * 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)
$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;
}
// 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();
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))
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;
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();
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();
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();
// 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
$filename_charset = $fmatches[1];
$filename_encoded = $fmatches[2];
}
+
$part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset);
}
}
*/
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;
}
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);
}
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
* @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)
{
// 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;
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;
// 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
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;
$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);
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
}
// 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);
}
$mailbox = $this->mailbox;
}
- return $this->_uid2id($uid, $mailbox);
+ return $this->uid2id($uid, $mailbox);
}
$mailbox = $this->mailbox;
}
- return $this->_id2uid($id, $mailbox);
+ return $this->id2uid($id, $mailbox);
}
/**
* 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
$a_folders = $data['folders'];
}
else if (!$this->conn->connected()) {
- return array();
+ return null;
}
else {
// Server supports LIST-EXTENDED, we can use selection options
$a_folders = array();
}
- // write mailboxlist to cache
- $this->update_cache($cache_key, $a_folders);
-
return $a_folders;
}
/**
* 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'));
}
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)) {
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
$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);
}
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);
}
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;
/**
- * 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
*
}
}
- $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;
}
}
}
+ /**
+ * 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)
*
else {
if ($this->cache)
$this->cache->close();
- $this->cache = null;
+ $this->cache = null;
$this->caching = false;
}
}
* 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
$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)) {
/**
- * @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;
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;
*/
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;
}
/**
*/
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"));
}
/**
$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;
--- /dev/null
+<?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;
+ }
+}
| |
| 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: |
| 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 $
*/
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)
public $errornum;
public $result;
public $resultcode;
+ public $selected;
public $data = array();
public $flags = array(
'SEEN' => '\\Seen',
'*' => '\\*',
);
- private $selected;
private $fp;
private $host;
private $logged = false;
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)
$out .= $line;
}
- $line = $a[1][0] . ($escape ? $this->escape($out) : $out);
+ $line = $str . ($escape ? $this->escape($out) : $out);
}
return $line;
}
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;
$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';
}
// initialize connection
$this->error = '';
$this->errornum = self::ERROR_OK;
- $this->selected = '';
+ $this->selected = null;
$this->user = $user;
$this->host = $host;
$this->logged = false;
/**
* 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;
}
/*
}
}
*/
- 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);
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;
}
}
* in RFC3501: UIDNEXT, UIDVALIDITY, RECENT
*
* @return array Status item-value hash
- * @access public
* @since 0.5-beta
*/
function status($mailbox, $items=array())
}
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;
* @param string $messages Message UIDs to expunge
*
* @return boolean True on success, False on error
- * @access public
*/
function expunge($mailbox, $messages=NULL)
{
$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;
}
* Executes CLOSE command
*
* @return boolean True on success, False on error
- * @access public
* @since 0.5
*/
function close()
$result = $this->execute('CLOSE', NULL, self::COMMAND_NORESPONSE);
if ($result == self::ERROR_OK) {
- $this->selected = '';
+ $this->selected = null;
return true;
}
* @param string $mailbox Mailbox name
*
* @return boolean True on success, False on error
- * @access public
*/
function subscribe($mailbox)
{
* @param string $mailbox Mailbox name
*
* @return boolean True on success, False on error
- * @access public
*/
function unsubscribe($mailbox)
{
* @param string $mailbox Mailbox name
*
* @return boolean True on success, False on error
- * @access public
*/
function deleteFolder($mailbox)
{
* @param string $mailbox Mailbox name
*
* @return boolean True on success, False on error
- * @access public
*/
function clearFolder($mailbox)
{
}
if ($res) {
- if ($this->selected == $mailbox)
+ if ($this->selected === $mailbox)
$res = $this->close();
else
$res = $this->expunge($mailbox);
* @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'];
}
* @param string $mailbox Mailbox name
*
* @return int Number of messages, False on error
- * @access public
*/
function countRecent($mailbox)
{
$this->select($mailbox);
- if ($this->selected == $mailbox) {
+ if ($this->selected === $mailbox) {
return $this->data['RECENT'];
}
* @param string $mailbox Mailbox name
*
* @return int Number of messages, False on error
- * @access public
*/
function countUnseen($mailbox)
{
* @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())
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);
* @param int $uid Message unique identifier (UID)
*
* @return int Message sequence identifier
- * @access public
*/
function UID2ID($mailbox, $uid)
{
* @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)) {
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]);
$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);
$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);
}
$params .= 'RETURN (' . implode(' ', $items) . ')';
}
if (!empty($criteria)) {
+ $modseq = stripos($criteria, 'MODSEQ') !== false;
$params .= ($params ? ' ' : '') . $criteria;
}
else {
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;
*
* @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())
{
*
* @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())
{
*
* @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())
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) {
}
// 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;
return false;
}
- function fetchMIMEHeaders($mailbox, $id, $parts, $mime=true)
+ function fetchMIMEHeaders($mailbox, $uid, $parts, $mime=true)
{
if (!$this->select($mailbox)) {
return false;
$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)) {
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));
$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
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;
}
// 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");
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;
}
// 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");
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()
{
/*
*
* @return boolean True on success, False on failure
*
- * @access public
* @since 0.5-beta
*/
function setACL($mailbox, $user, $acl)
*
* @return boolean True on success, False on failure
*
- * @access public
* @since 0.5-beta
*/
function deleteACL($mailbox, $user)
* @param string $mailbox Mailbox name
*
* @return array User-rights array on success, NULL on error
- * @access public
* @since 0.5-beta
*/
function getACL($mailbox)
* @param string $user User name
*
* @return array List of user rights
- * @access public
* @since 0.5-beta
*/
function listRights($mailbox, $user)
* @param string $mailbox Mailbox name
*
* @return array MYRIGHTS response on success, NULL on error
- * @access public
* @since 0.5-beta
*/
function myRights($mailbox)
* @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)
*
* @return boolean True on success, False on failure
*
- * @access public
* @since 0.5-beta
*/
function deleteMetadata($mailbox, $entries)
*
* @return array GETMETADATA result on success, NULL on error
*
- * @access public
* @since 0.5-beta
*/
function getMetadata($mailbox, $entries, $options=array())
* 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)
*
* @return boolean True on success, False on failure
*
- * @access public
* @since 0.5-beta
*/
function deleteAnnotation($mailbox, $data)
*
* @return array Annotations result on success, NULL on error
*
- * @access public
* @since 0.5-beta
*/
function getAnnotation($mailbox, $entries, $attribs)
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()
* @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)
$response = $noresp ? null : '';
if (!empty($arguments)) {
- $query .= ' ' . implode(' ', $arguments);
+ foreach ($arguments as $arg) {
+ $query .= ' ' . self::r_implode($arg);
+ }
}
// Send command
* @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)
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;
// 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]));
}
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 = '';
*
* @param boolean $debug New value for the debugging flag.
*
- * @access public
* @since 0.5-stable
*/
function setDebug($debug, $handler = null)
*
* @param string $message Debug mesage text.
*
- * @access private
* @since 0.5-stable
*/
private function debug($message)
| 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 $
*/
| 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 $
*/
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;
{
$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;
$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
$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();
}
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;
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;
}
*
* @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;
*
* @return boolean True on success, False on error
*/
- private function _bind($dn, $pass)
+ public function bind($dn, $pass)
{
if (!$this->conn) {
return false;
*/
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]);
}
*
* @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)
{
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 == '*')
{
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)";
}
}
}
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)";
}
}
}
$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);
}
* 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);
}
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;
// 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;
}
$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;
$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
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];
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));
}
}
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));
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')))
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;
}
+ /**
+ * 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)
*/
}
+ /**
+ * 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
*
{
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;
+ }
}
/**
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));
$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
*
*/
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));
}
$this->_debug("S: OK");
+ $this->cache->remove('groups');
return array('id' => $new_gid, 'name' => $group_name);
}
*/
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]");
}
$this->_debug("S: OK");
+ $this->cache->remove('groups');
return true;
}
*/
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);
}
$this->_debug("S: OK");
+ $this->cache->remove('groups');
return $new_name;
}
*/
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));
}
$this->_debug("S: OK");
+ $this->cache->remove('groups');
return count($new_attrs['member']);
}
*/
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();
}
$this->_debug("S: OK");
+ $this->cache->remove('groups');
return count($del_attrs['member']);
}
$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));
$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;
}
* @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
# 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');
| 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 $
*/
*/
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;
*/
function __construct($db_dsnw, $db_dsnr='', $pconn=false)
{
- if ($db_dsnr == '')
+ if (empty($db_dsnr))
$db_dsnr = $db_dsnw;
$this->db_dsnw = $db_dsnw;
$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);
*/
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;
}
// 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
raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $this->db_error_msg), true, false);
-
+
$result = false;
}
else {
}
}
- // 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);
}
if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) {
return $result;
}
-
+
return null;
}
*/
function now()
{
- switch($this->db_provider) {
+ switch ($this->db_provider) {
case 'mssql':
case 'sqlsrv':
return "getdate()";
| 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 $
*/
public $uid = null;
public $headers;
- public $structure;
public $parts = array();
public $mime_parts = array();
public $attachments = array();
$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;
'_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);
* @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;
}
$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;
$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) {
-<?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';
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];
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 '';
return '';
}
- function getPartArray($a, $part)
+ function getStructurePartArray($a, $part)
{
if (!is_array($a)) {
return false;
else
return $a;
}
- else if (($part==0) || (empty($part))) {
+ else if (($part == 0) || (empty($part))) {
return $a;
}
}
-
-}
| 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 $
*/
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();
| 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 $
*/
}
+ /**
+ * 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
*
| 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: |
| 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 $
*/
var $count = 0;
var $first = 0;
var $current = 0;
+ var $searchonly = false;
var $records = array();
| |
| 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: |
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);
}
}
+ /**
+ * 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
*/
| 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
*/
}
-/**
- * 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
*
foreach ($haystack as $value)
if ($needle===mb_strtolower($value))
return true;
-
+
return false;
}
{
$host_url = $base_url;
$abs_path = $path;
-
+
// check if path is an absolute URL
if (preg_match('/^[fhtps]+:\/\//', $path))
return $path;
}
return $hdrs[$key];
- }
+}
/**
{
return preg_replace('/\/$/', '', $str);
}
-
+
/**
* Delete all files within a folder
* @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];
$amount = (int)$offset_str;
$unit = 's';
}
-
+
$ts = mktime();
switch ($unit)
{
function abbreviate_string($str, $maxlength, $place_holder='...', $ending=false)
{
$length = mb_strlen($str);
-
+
if ($length > $maxlength)
{
if ($ending)
return $str;
}
+
/**
* A method to guess the mime_type of an attachment.
*
$input[$idx] = rc_utf8_clean($val);
return $input;
}
-
+
if (!is_string($input) || $input == '')
return $input;
'|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.// UTF8-4
'|\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]'. // UTF8-4
')$/';
-
+
$seq = '';
$out = '';
$p = $i + 1;
}
}
-
+
$result[] = substr($string, $p);
return $result;
}
function array_keys_recursive($array)
{
$keys = array();
-
+
if (!empty($array))
foreach ($array as $key => $child) {
$keys[] = $key;
| 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 $
*/
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
$from = $addresses[0];
// Reject envelope From: addresses with spaces.
- if (strstr($from, ' '))
+ if (strpos($from, ' ') !== false)
return false;
$lines[] = $key . ': ' . $value;
| 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 $
*/
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';
*/
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(
'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'),
+ );
}
*
* @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) {
return $this->_pspell_suggestions($word);
}
- return $this->_googie_suggestions($word);
+ return $this->_googie_suggestions($word);
}
-
+
/**
* Returns mispelled words
$result[$word] = is_array($item[4]) ? implode("\t", $item[4]) : $item[4];
}
- return $out;
+ return $result;
}
// 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)
*/
private function _pspell_words($text = null, $is_html=false)
{
+ $result = array();
+
if ($text) {
// init spellchecker
$this->_pspell_init();
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;
}
}
return $result;
}
- $result = array();
-
foreach ($this->matches as $m) {
$result[] = $m[0];
}
}
// 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))
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;
}
$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;
+ }
+
}
| 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 $
*/
// 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 = "/("
| 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 $
*/
//$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']);
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;
}
$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')))
$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)) {
$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;
// 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']);
$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);
$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();
| 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 $
*/
*/
private $rc;
+ const SEARCH_ADDRESSBOOK = 1;
+ const SEARCH_MAIL = 2;
/**
* Object constructor
{
$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
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');
+ }
+
}
| 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 $
*/
-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;
| 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 |
| |
+-----------------------------------------------------------------------+
| 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 = {};
// webmail client settings
this.dblclick_time = 500;
- this.message_time = 2000;
+ this.message_time = 4000;
this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
if (over) button_prop.over = over;
this.buttons[command].push(button_prop);
-
+
if (this.loaded)
init_button(command, button_prop);
};
// initialize webmail client
this.init = function()
{
- var p = this;
+ var n, p = this;
this.task = this.env.task;
// check browser
}
// 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();
}
// 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);
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) {
'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'));
}
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,
}
this.update_group_commands();
+ this.command('list');
}
this.set_page_buttons();
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);
$('#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 () {
// 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();
}
// 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) {
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;
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;
// 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);
}
}
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');
}
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;
if (props && !props._row)
break;
- var uid, flag = 'read';
+ flag = 'read';
if (props._row.uid) {
uid = props._row.uid;
if (props && !props._row)
break;
- var uid, flag = 'flagged';
+ flag = 'flagged';
if (props._row.uid) {
uid = props._row.uid;
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
}
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;
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
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');
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))
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) {
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)
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;
break;
case 'listgroup':
+ this.reset_qsearch();
this.list_contacts(props.source, props.id);
break;
// 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') {
}
// push array elements into commands array
else {
- for (var i in cmd)
+ for (i in cmd)
args.push(cmd[i]);
}
}
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 *********/
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) {
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) {
}
// 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]);
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;
}
};
- 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) {
}
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();
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');
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,
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;
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';
// 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))
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>';
}
// 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();
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';
}
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];
// 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
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
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);
}
};
// 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();
// 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();
}
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']"),
// 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
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);
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) {
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>';
}
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)
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()
{
this.env.qsearch = null;
this.env.search_request = null;
+ this.env.search_id = null;
};
this.sent_successfully = function(type, msg)
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
// 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;
}
// 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;
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;
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
}
// 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;
}
}
- 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();
}
}
};
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;
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 *********/
}
}
- 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);
this.list_contacts = function(src, group, page)
{
- var add_url = '',
+ var folder, add_url = '',
target = window;
if (!src)
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;
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);
{
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
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 = '';
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;
};
{
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]) {
// 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);
// 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()
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()
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);
.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;
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;
{
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) {
.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 = [];
// 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);
};
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);
// 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));
// 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;
}
}
}
// 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;
}
// 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;
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();
};
// 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);
}
};
// 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
{
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');
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];
}
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
$.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);
};
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);
}
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 });
}
}
};
+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;
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}}}();
| 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
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;
},
/**
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');
};
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)
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;
+})();
*/
// 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: '',
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',
});
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'
});
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;
+ }
}
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"}};
/*
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
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');
this.lang_rsm_edt = "Resume editing";
this.lang_no_error_found = "No spelling errors found";
this.lang_no_suggestions = "No suggestions";
+ this.lang_learn_word = "Add to dictionary";
this.show_spell_img = false; // roundcube mod.
this.decoration = true;
this.extra_menu_items = [];
this.custom_spellcheck_starter = null;
this.main_controller = true;
+ this.has_dictionary = has_dict;
// Observers
this.lang_state_observer = null;
});
-this.decorateTextarea = function(id) {
+this.decorateTextarea = function(id)
+{
this.text_area = typeof id === 'string' ? document.getElementById(id) : id;
if (this.text_area) {
//////
// 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
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();
//////
// 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;
};
//////
// 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);
});
};
+this.learnWord = function(word, id)
+{
+ word = this.escapeSpecial(word.innerHTML);
+
+ var ref = this,
+ req_text = '<?xml version="1.0" encoding="utf-8" ?><learnword><text>' + word + '</text></learnword>';
+
+ $.ajax({ type: 'POST', url: this.getUrl(), data: req_text, dataType: 'text',
+ error: function(o) {
+ if (ref.custom_ajax_error)
+ ref.custom_ajax_error(ref);
+ else
+ alert('An error was encountered on the server. Please try again later.');
+ },
+ success: function(data) {
+ }
+ });
+};
+
//////
// Spell checking functions
this.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,
//////
// 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;
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'];
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);
break;
}
}
+
if (!changed) {
// Build up the result list
var suggestions = this.results[id]['suggestions'],
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'),
row.appendChild(item);
list.appendChild(row);
}
-
+*/
for (var i=0, len=suggestions.length; i < len; i++) {
row = document.createElement('tr'),
item = document.createElement('td'),
$(dummy).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'),
$(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();
});
$(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);
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);
//////
// 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);
}
};
-this.resumeEditing = function() {
+this.resumeEditing = function()
+{
this.setStateChanged('ready');
if (this.edit_layer)
this.checkSpellingState(false);
};
-this.createErrorLink = function(text, id) {
+this.createErrorLink = function(text, id)
+{
var elm = document.createElement('span'),
ref = this,
d = function (e) {
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(" ");
return span;
};
-this.showErrorsInIframe = function() {
+this.showErrorsInIframe = function()
+{
var output = document.createElement('div'),
pointer = 0,
results = this.results;
//////
// 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');
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);
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++) {
}
};
-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');
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);
//////
// State functions
/////
-this.flashNoSpellingErrorState = function(on_finish) {
+this.flashNoSpellingErrorState = function(on_finish)
+{
this.setStateChanged('no_error_found');
var ref = this;
}
};
-this.resumeEditingState = function() {
+this.resumeEditingState = function()
+{
this.setStateChanged('resume_editing');
//Change link text to resume
catch (e) {};
};
-this.checkSpellingState = function(fire) {
+this.checkSpellingState = function(fire)
+{
if (fire)
this.setStateChanged('ready');
//////
// 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();
}
};
-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;
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');
*/
}
-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
-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;
| 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 $
*/
this.colcount = 0;
this.subject_col = -1;
- this.shiftkey = false;
+ this.modkey = 0;
this.multiselect = false;
this.multiexpand = false;
this.multi_selecting = false;
case CONTROL_KEY:
if (!with_mouse)
this.highlight_row(id, true);
- break;
+ break;
case CONTROL_SHIFT_KEY:
this.shift_select(id, true);
*/
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),
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
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);
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);
*/
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:
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);
}
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>
'/(<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
);
/**
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>
"\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
'£',
'EUR', // Euro sign. \80 ?
'|+|amp|+|', // Ampersand: see _converter()
- ' ' // Runs of spaces, post-handling
+ ' ', // Runs of spaces, post-handling
);
/**
* @see _build_link_list()
*/
var $_link_list = '';
-
+
/**
* Number of valid links detected in the text, used for plain text
* display (rendered similar to footnotes).
*/
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.
*
// 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);
// 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
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 . ']';
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;
/* Registered callback functions for tags */
private $handlers = array();
-
+
/* Allowed HTML elements */
private $_html_elements = array();
/* Allowed HTML attributes */
private $_html_attribs = array();
-
+
/* Constructor */
public function __construct($p = array()) {
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 = '';
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
$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)
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])) {
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);
return $this->dumpHtml($node);
}
+ /**
+ * Getter for config parameters
+ */
+ public function get_config($prop)
+ {
+ return $this->config[$prop];
+ }
+
}
?>
| 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 $
*/
$labels['markunread'] = 'كغير مقروءة';
$labels['markflagged'] = 'كموْسومة';
$labels['markunflagged'] = 'كغير موْسومة';
-$labels['messageactions'] = 'إجراءات إضافية...';
+$labels['moreactions'] = 'إجراءات إضافية...';
$labels['select'] = 'تحديد';
$labels['all'] = 'الكل';
$labels['none'] = 'لا شيء';
$labels['editortype'] = 'نوع المُحرّر';
$labels['returnreceipt'] = 'ايصال استلام';
$labels['dsn'] = 'تنويه حالة التوصيل';
+$labels['mailreplyintro'] = 'كتب $sender في $date:';
+$labels['originalmessage'] = 'الرسالة الأساسية';
$labels['editidents'] = 'تعديل الهويات';
$labels['checkspelling'] = 'التدقيق الإملائي';
$labels['resumeediting'] = 'متابعة التحرير';
$labels['nosubject'] = '(دون موضوع)';
$labels['showimages'] = 'إظهار الصور';
$labels['alwaysshow'] = 'دائماً أظهر الصّور القادمة من $sender';
+$labels['isdraft'] = 'هذه مسودّة رسالة';
$labels['htmltoggle'] = 'HTML';
$labels['plaintoggle'] = 'نص مجرد';
$labels['savesentmessagein'] = 'احفظ الرسالة المُرسلة في';
$labels['typevideo'] = 'الفيديو';
$labels['typeassistant'] = 'المساعد';
$labels['typehomepage'] = 'الرئيسية';
+$labels['typeblog'] = 'المدوّنة';
+$labels['typeprofile'] = 'الملف الشخصي';
$labels['addfield'] = 'إضافة حقل...';
$labels['addcontact'] = 'إضافة المراسل المحدد إلى دفتر عناويني';
$labels['editcontact'] = 'تحرير بيانات المراسل';
$labels['export'] = 'تصدير';
$labels['exportvcards'] = 'صدّر المراسلين بنسق vCard';
$labels['newcontactgroup'] = 'إنشاء مجموعة مراسلين جديدة';
-$labels['groupactions'] = 'إجراءات مجموعات المراسلين...';
$labels['grouprename'] = 'تغيير اسم المجموعة';
$labels['groupdelete'] = 'حذف المجموعة';
$labels['previouspage'] = 'عرض المجموعة السابقة';
$labels['group'] = 'مجموعة';
$labels['groups'] = 'المجموعات';
$labels['personaladrbook'] = 'العناوين الشخصية';
+$labels['searchsave'] = 'حفظ البحث';
+$labels['searchdelete'] = 'حذف البحث';
$labels['import'] = 'استورد';
$labels['importcontacts'] = 'استورد المراسلين';
$labels['importfromfile'] = 'استورد من ملف:';
$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'] = 'تحرير تفضيلات المستخدم';
$labels['preferhtml'] = 'تفضيل صيغة HTML';
$labels['defaultcharset'] = 'ترميز المحارف الافتراضي';
$labels['htmlmessage'] = 'رسالة بنسق HTML';
+$labels['dateformat'] = 'نسق التاريخ';
+$labels['timeformat'] = 'نسق الوقت';
$labels['prettydate'] = 'تواريخ منمقة';
$labels['setdefault'] = 'تعيين كإفتراضي';
$labels['autodetect'] = 'آلي';
$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'] = 'اسم المجلد';
$labels['sortasc'] = 'ترتيب تصاعدي';
$labels['sortdesc'] = 'ترتيب تنازلي';
$labels['undo'] = 'تراجع';
+$labels['plugin'] = 'إضافة';
+$labels['version'] = 'النسخة';
+$labels['source'] = 'المصدر';
+$labels['license'] = 'الترخيص';
+$labels['support'] = 'احصل على الدعم الفني';
$labels['B'] = 'ب';
$labels['KB'] = 'ك.ب';
$labels['MB'] = 'م.ب';
| 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 $
*/
$messages['imaperror'] = 'فشل الاتصال بخادم IMAP';
$messages['servererror'] = 'خطأ في الخادم!';
$messages['servererrormsg'] = 'خطأ خادم: $msg';
-$messages['databaserror'] = 'خطأ في قاعدة البيانات!';
+$messages['dberror'] = 'خطأ في قاعدة البيانات!';
$messages['errorreadonly'] = 'تعذر تنفيذ العملية. المجلد للقراءة فقط.';
$messages['errornoperm'] = 'تعذر تنفيذ العملية. ليست لديك الصلاحية.';
$messages['invalidrequest'] = 'طلب غير صالح! لم تحفظ أية بيانات.';
$messages['encryptedmessage'] = 'هذه الرسالة مشفرة ولا يمكن عرضها. عذراً!';
$messages['nocontactsfound'] = 'لم يعثر على أي مراسل';
$messages['contactnotfound'] = 'تعذر العثور على المراسل المطلوب';
+$messages['contactsearchonly'] = 'اكتب بعض كلمات البحث للعثور على المُراسلين';
$messages['sendingfailed'] = 'فشل إرسال الرسالة';
$messages['senttooquickly'] = 'رجاء انتظر $sec ثوان قبل إرسال هذه الرسالة';
$messages['errorsavingsent'] = 'حدث خطأ أثناء حفظ الرسالة المُرسلة';
$messages['deletemessagesconfirm'] = 'هل تريد حذف الرسائل المحددة؟';
$messages['deletefolderconfirm'] = 'هل تريد حقاً حذف هذا المجلد؟';
$messages['purgefolderconfirm'] = 'هل تريد حقاً حذف جميع الرسائل في هذا المجلد؟';
+$messages['contactdeleting'] = 'جاري حذف المُراسلين...';
$messages['groupdeleting'] = 'جاري حذف المجموعة...';
$messages['folderdeleting'] = 'جاري حذف المجلد...';
$messages['foldermoving'] = 'جاري نقل المجلد...';
$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'] = 'جاري التحقق...';
$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.';
$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['invalidimageformat'] = 'ليست صيغة صورة صحيحة';
$messages['mispellingsfound'] = 'عُثر على أخطاء إملائية في الرسالة';
$messages['parentnotwritable'] = 'تعذر إنشاء/نقل المجلد إلى المجلد المحدد. ليست لديك الصلاحية.';
+$messages['messagetoobig'] = 'جزء الرسالة أكبر بكثير مما يمكن معالجته.';
?>
| 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 $
*/
$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'] = 'Маркирай писмата';
$labels['markunread'] = 'Като нови';
$labels['markflagged'] = 'Като отбелязани';
$labels['markunflagged'] = 'Като неотбелязани';
-$labels['messageactions'] = 'Още действия';
+$labels['moreactions'] = 'Повече действия...';
$labels['select'] = 'Избери';
$labels['all'] = 'Всички';
$labels['none'] = 'Нищо';
$labels['listsorting'] = 'Колона за сортиране';
$labels['listorder'] = 'Режим на сортиране';
$labels['listmode'] = 'Кратък списък';
-$labels['folderactions'] = 'Десйтвия за папки...';
+$labels['folderactions'] = 'Действия за папки...';
$labels['compact'] = 'Свий';
$labels['empty'] = 'Изпразни';
$labels['quota'] = 'Използвано място';
$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'] = 'Нисък';
$labels['nosubject'] = '(няма заглавие)';
$labels['showimages'] = 'Показвай изображения';
$labels['alwaysshow'] = 'Винаги показвай изображения от $ ';
+$labels['isdraft'] = 'Това съобщение е чернова';
$labels['htmltoggle'] = 'HTML';
$labels['plaintoggle'] = 'текстов';
$labels['savesentmessagein'] = 'Запази съобщението в';
$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['export'] = 'Изнасяне';
$labels['exportvcards'] = 'Изнасяне във vCard формат';
$labels['newcontactgroup'] = 'Създаване на нова група';
-$labels['groupactions'] = 'Действия за групи от контакти...';
+$labels['grouprename'] = 'Преименувай група';
+$labels['groupdelete'] = 'Изтриване на група';
$labels['previouspage'] = 'Предна страница';
$labels['firstpage'] = 'Първа страница';
$labels['nextpage'] = 'Следваща страница';
$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'] = 'Извършено';
$labels['preferhtml'] = 'Показвай първо HTML версия';
$labels['defaultcharset'] = 'Подразбиращо се кодиране';
$labels['htmlmessage'] = 'HTML съобщение';
+$labels['dateformat'] = 'Формат на датата';
+$labels['timeformat'] = 'Формат на времето';
$labels['prettydate'] = 'Кратки дати';
$labels['setdefault'] = 'По подразбиране';
$labels['autodetect'] = 'Автоматично';
$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'] = 'Име на папката';
$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'] = 'МБ';
| 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 $
*/
$messages['imaperror'] = 'Неуспешно свързване към IMAP сървъра';
$messages['servererror'] = 'Грешка!';
$messages['servererrormsg'] = 'Сървърна грешка: $msg';
+$messages['dberror'] = 'Грешка с базата данни!';
$messages['errorreadonly'] = 'Операцията не може да бъде изпълнена. Папката е с права само за четене';
$messages['errornoperm'] = 'Операцията не може да бъде изпълнена. Отказани права за достъп';
$messages['invalidrequest'] = 'Невалидна заявка! Данните не са съхранени.';
$messages['mailboxempty'] = 'Кутията е празна';
$messages['loading'] = 'Зареждане...';
$messages['uploading'] = 'Качване на файла...';
+$messages['uploadingmany'] = 'Качване на файлове...';
$messages['loadingdata'] = 'Зареждане на данни...';
$messages['checkingmail'] = 'Проверка за нови писма...';
$messages['sendingmessage'] = 'Изпращане на писмото...';
$messages['successfullysaved'] = 'Записано';
$messages['addedsuccessfully'] = 'Контакта е добавен в адресната книга';
$messages['contactexists'] = 'Контакт с този e-mail адрес вече същестува';
+$messages['contactnameexists'] = 'Контакт със същото име вече съществува';
$messages['blockedimages'] = 'С оглед на Вашата сигурност, изображенията в това писмо са блокирани.';
$messages['encryptedmessage'] = 'Това е кодирано писмо и не може да бъде показано. Съжаляваме!';
-$messages['nocontactsfound'] = 'Няма контакти';
+$messages['nocontactsfound'] = 'Ð\9dÑ\8fма намеÑ\80ени конÑ\82акÑ\82и';
$messages['contactnotfound'] = 'Исканият контакт не е намерен';
+$messages['contactsearchonly'] = 'Въведете нещо в полето за търсене за да търсите контакти';
$messages['sendingfailed'] = 'Изпращането неуспешно';
$messages['senttooquickly'] = 'Моля, изчакайте $sec секунда(и) преди да изпратите съобщението';
$messages['errorsavingsent'] = 'Възникна грешка при записването на съобщението';
$messages['errordeleting'] = 'Писмото не може да бъде изтрито';
$messages['errormarking'] = 'Съобщението не може да бъде маркирано';
$messages['deletecontactconfirm'] = 'Искате ли да изтриете маркираните контакти?';
+$messages['deletegroupconfirm'] = 'Искате ли да изтриете избраната група?';
$messages['deletemessagesconfirm'] = 'Искате ли да изтриете маркираните съобщения?';
$messages['deletefolderconfirm'] = 'Искате ли да изтриете тази папка?';
$messages['purgefolderconfirm'] = 'Искате ли да изтриете всички писма в тази папка?';
+$messages['contactdeleting'] = 'Изтриване на контакт(и)...';
+$messages['groupdeleting'] = 'Изтриване на група...';
$messages['folderdeleting'] = 'Изтриване на папка...';
$messages['foldermoving'] = 'Преместване на папка...';
$messages['foldersubscribing'] = 'Абониране...';
$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'] = 'Проверка...';
$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'] = 'Не можете да изтриете тази самоличност, трябва да имате поне една.';
$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'] = 'Превключването на редактора в текстов режим ще доведе до загуба на форматирането на текса. Сигурни ли сте, че искате да продължите?';
$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).';
$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'] = 'Създаването/преместването на папка в избраната родителска папка е неуспешно. Няма права за достъп.';
?>
| 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 $
*/
| 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 $
*/
| 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 $
*/
$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';
$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';
$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á';
$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í';
$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';
$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ší';
$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';
$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';
$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';
$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';
| 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 $
*/
$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.';
$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...';
$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';
$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...';
$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...';
$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.';
$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?';
$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.';
?>
$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';
$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';
$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';
$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:';
$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';
$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';
$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';
$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';
$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';
$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...';
$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...';
$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';
$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';
$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.';
?>
| 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';
$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';
$labels['thu'] = 'Tor';
$labels['fri'] = 'Fre';
$labels['sat'] = 'Lør';
+
+// weekdays long
$labels['sunday'] = 'Søndag';
$labels['monday'] = 'Mandag';
$labels['tuesday'] = 'Tirsdag';
$labels['thursday'] = 'Torsdag';
$labels['friday'] = 'Fredag';
$labels['saturday'] = 'Lørdag';
+
+// month short
$labels['jan'] = 'Jan';
$labels['feb'] = 'Feb';
$labels['mar'] = 'Mar';
$labels['oct'] = 'Okt';
$labels['nov'] = 'Nov';
$labels['dec'] = 'Dec';
+
+//months long
$labels['longjan'] = 'Januar';
$labels['longfeb'] = 'Februar';
$labels['longmar'] = 'Marts';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
| 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();
$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.';
$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...';
$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';
$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...';
$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.';
$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?';
$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';
$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.';
?>
| 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 $
*/
$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';
$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';
$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';
| 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 $
*/
$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.';
$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';
+-----------------------------------------------------------------------+
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
+-----------------------------------------------------------------------+
| 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 $
*/
$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.';
$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';
$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...';
$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.';
$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';
| |
+-----------------------------------------------------------------------+
| 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 $
*/
$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';
$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';
| |
+-----------------------------------------------------------------------+
| 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 $
*/
| 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 $
*/
// 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';
$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';
$labels['deleted'] = 'Deleted';
$labels['invert'] = 'Invert';
$labels['filter'] = 'Filter';
-
$labels['list'] = 'List';
$labels['threads'] = 'Threads';
$labels['expand-all'] = 'Expand All';
$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';
$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';
$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';
$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';
$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:';
// settings
$labels['settingsfor'] = 'Settings for';
-
+$labels['about'] = 'About';
$labels['preferences'] = 'Preferences';
$labels['userpreferences'] = 'User preferences';
$labels['editpreferences'] = 'Edit user preferences';
$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';
$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';
$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';
$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';
| 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 $
*/
$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.';
$messages['encryptedmessage'] = 'This is an encrypted message and can not be displayed. Sorry!';
$messages['nocontactsfound'] = 'No contacts found.';
$messages['contactnotfound'] = 'The requested contact was not found.';
+$messages['contactsearchonly'] = 'Enter some search terms to find contacts';
$messages['sendingfailed'] = 'Failed to send message.';
$messages['senttooquickly'] = 'Please wait $sec sec(s). before sending this message.';
$messages['errorsavingsent'] = 'An error occured while saving sent message.';
$messages['deletemessagesconfirm'] = 'Do you really want to delete selected message(s)?';
$messages['deletefolderconfirm'] = 'Do you really want to delete this folder?';
$messages['purgefolderconfirm'] = 'Do you really want to delete all messages in this folder?';
+$messages['contactdeleting'] = 'Deleting contact(s)...';
$messages['groupdeleting'] = 'Deleting group...';
$messages['folderdeleting'] = 'Deleting folder...';
$messages['foldermoving'] = 'Moving folder...';
$messages['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...';
$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.';
$messages['groupdeleted'] = 'Group deleted successfully.';
$messages['grouprenamed'] = 'Group renamed successfully.';
$messages['groupcreated'] = 'Group created successfully.';
+$messages['savedsearchdeleted'] = 'Saved search deleted successfully.';
+$messages['savedsearchdeleteerror'] = 'Could not delete saved search.';
+$messages['savedsearchcreated'] = 'Saved search created successfully.';
+$messages['savedsearchcreateerror'] = 'Could not create saved search.';
$messages['messagedeleted'] = 'Message(s) deleted successfully.';
$messages['messagemoved'] = 'Message(s) moved successfully.';
$messages['messagecopied'] = 'Message(s) copied successfully.';
$messages['messagemarked'] = 'Message(s) marked successfully.';
$messages['autocompletechars'] = 'Enter at least $min characters for autocompletion.';
+$messages['autocompletemore'] = 'More matching entries found. Please type more characters.';
$messages['namecannotbeempty'] = 'Name cannot be empty.';
$messages['nametoolong'] = 'Name is too long.';
$messages['folderupdated'] = 'Folder updated successfully.';
$messages['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.';
?>
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$labels['sortby'] = 'Ordenar por';
$labels['sortasc'] = 'Orden ascendente';
$labels['sortdesc'] = 'Orden descendente';
+$labels['undo'] = 'Deshacer';
$labels['B'] = 'B';
$labels['KB'] = 'KB';
$labels['MB'] = 'MB';
| 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();
$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.';
$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...';
$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';
$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...';
$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...';
$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.';
$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';
$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.';
?>
| 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 $
*/
$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.';
| 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 |
| |
+-----------------------------------------------------------------------+
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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 :';
$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';
$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';
$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';
$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';
$labels['korean'] = 'Coréen';
$labels['chinese'] = 'Chinois';
-?>
+?>
\ No newline at end of file
| 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 |
| |
+-----------------------------------------------------------------------+
| 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 $
*/
$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é';
$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...';
$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...';
$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';
$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.';
$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';
$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
| 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 |
| |
+-----------------------------------------------------------------------+
$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';
$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';
$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';
$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';
$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';
$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)';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
| 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 |
| |
+-----------------------------------------------------------------------+
*/
$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.';
?>
+-----------------------------------------------------------------------+
| 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 |
+-----------------------------------------------------------------------+
*/
$labels['markunread'] = 'כלא נקראו';
$labels['markflagged'] = 'כמסומן';
$labels['markunflagged'] = 'כלא מסומן';
-$labels['messageactions'] = 'פעולות נוספות';
+$labels['moreactions'] = 'פעולות נוספות...';
$labels['select'] = 'בחירה';
$labels['all'] = 'הכל';
$labels['none'] = 'כלום';
$labels['nosubject'] = '(ללא נושא)';
$labels['showimages'] = 'הצגת תמונות';
$labels['alwaysshow'] = '$sender תמיד להציג תמונות מאת ';
+$labels['isdraft'] = 'זו טיוטה של הודעה';
$labels['htmltoggle'] = 'HTML';
$labels['plaintoggle'] = 'ללא עיצוב';
$labels['savesentmessagein'] = 'היכן לשמור ההודעה?';
$labels['export'] = 'ייצוא';
$labels['exportvcards'] = 'ייצוא אנשי קשר בפורמט vCard ';
$labels['newcontactgroup'] = 'יצירת קבוצה חדשה של אנשי קשר';
-$labels['groupactions'] = 'פעולות על קבוצת אנשי הקשר...';
$labels['grouprename'] = 'שינוי שם קבוצה';
$labels['groupdelete'] = 'מחיקת קבוצה';
$labels['previouspage'] = 'הצגת הקבוצה הקודמת';
$labels['group'] = 'קבוצה';
$labels['groups'] = 'קבוצות';
$labels['personaladrbook'] = 'כתובות פרטיות';
+$labels['searchsave'] = 'שמירת החיפוש';
+$labels['searchdelete'] = 'מחיקת החיפוש';
$labels['import'] = 'ייבוא';
$labels['importcontacts'] = 'ייבוא אנשי קשר';
$labels['importfromfile'] = 'ייבוא מקובץ';
$labels['importtext'] = '<a href="http://en.wikipedia.org/wiki/VCard">vCard</a> ניתן לייבא אנשי קשר מפנקס כתובות קיים. אנו תומכים בפורמט';
$labels['done'] = 'בוצע';
$labels['settingsfor'] = 'הגדרות עבור';
+$labels['about'] = 'אודות';
$labels['preferences'] = 'העדפות';
$labels['userpreferences'] = 'העדפות משתמש';
$labels['editpreferences'] = 'עריכה של העדפות משתמש';
$labels['preferhtml'] = 'הצגת HTML';
$labels['defaultcharset'] = 'ברירת מחדל של תווים';
$labels['htmlmessage'] = 'תוכן HTML';
+$labels['dateformat'] = 'פורמט התאריך';
+$labels['timeformat'] = 'פורמט השעה';
$labels['prettydate'] = 'תאריכים מעוצבים';
$labels['setdefault'] = 'קביעה כברירת מחדל';
$labels['autodetect'] = 'אוטומטי';
$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'] = 'שם תיק';
$labels['sortasc'] = 'מיון בסדר עולה';
$labels['sortdesc'] = 'מיון בסדר יורד';
$labels['undo'] = 'ביטול שינוי';
+$labels['plugin'] = 'תוסף תוכנה';
+$labels['version'] = 'גירסה';
+$labels['source'] = 'מקור';
+$labels['license'] = 'רשיון';
+$labels['support'] = 'קבלת תמיכה';
$labels['B'] = 'בייט';
$labels['KB'] = 'ק"ב';
$labels['MB'] = 'מ"ב';
+-----------------------------------------------------------------------+
| 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 |
+-----------------------------------------------------------------------+
*/
$messages['encryptedmessage'] = 'זו הודעת מוצפנת ולא ניתן להציגה';
$messages['nocontactsfound'] = 'לא נמצאו אנשי קשר';
$messages['contactnotfound'] = 'איש הקשר המבוקש לא נמצא';
+$messages['contactsearchonly'] = 'יש להקיש מפתחות חיפוש כדי למצוא אנשי קשר';
$messages['sendingfailed'] = 'שליחת ההודעה נכשלה';
$messages['senttooquickly'] = 'נא להמתין $sec שניות לפני מסירת הודעה זו';
$messages['errorsavingsent'] = 'נגרמה שגיאה במהלך שמירת ההודעה בתיק הודעות יוצאות';
$messages['deletemessagesconfirm'] = 'האם למחוק את ההודעות המסומנות?';
$messages['deletefolderconfirm'] = 'האם למחוק תיק זה?';
$messages['purgefolderconfirm'] = 'האם למחוק את כל ההודעות בתיק זה?';
+$messages['contactdeleting'] = 'אנשי קשר נמחקים...';
$messages['groupdeleting'] = 'מחיקת קבוצה...';
$messages['folderdeleting'] = 'התיקיה נמחקת...';
$messages['foldermoving'] = 'העברת תיקיה...';
$messages['nobodywarning'] = 'האם לשלוח הודעה ללא תוכן?';
$messages['notsentwarning'] = 'ההודעה לא נשלחה. האם לבטל?';
$messages['noldapserver'] = 'נא לבחור שרת כתובות לחיפוש';
-$messages['nocontactsreturned'] = 'לא נמצאו אנשי קשר';
$messages['nosearchname'] = 'נא להוסיף איש קשר או כתובת דוא\"ל';
$messages['notuploadedwarning'] = 'עדיין לא הועלו כל הקבצים. נא לחכות או לבטל הפעולה.';
$messages['searchsuccessful'] = 'נמצאו $nr הודעות';
+$messages['contactsearchsuccessful'] = 'נמצאו $nr אנשי קשר';
$messages['searchnomatch'] = 'תוצאת החיפוש ריקה';
$messages['searching'] = 'חיפוש...';
$messages['checking'] = 'בדיקה...';
$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';
$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['invalidimageformat'] = 'פורמט תמונה לא חוקי';
$messages['mispellingsfound'] = 'התגלו שגיאות כתיב בהודעה';
$messages['parentnotwritable'] = 'לא ניתן ליצור/להעביר תיקיה לתוך תיקית האב שנבחרה. אין הרשאה לגישה.';
+$messages['messagetoobig'] = 'ההודעה גדולה מעבר ליכולת העיבוד של התוכנה';
?>
| 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 $
*/
$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.';
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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:';
$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';
$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';
$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';
$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';
| 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 $
*/
$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!';
$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';
$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...';
$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';
$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ó';
$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';
$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!';
?>
| 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 $
*/
$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.';
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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';
$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:';
$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';
$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';
$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';
$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';
| 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 $
*/
$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.';
$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';
$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...';
$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...';
$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';
$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';
$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.';
?>
| 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
*/
$labels['deleted'] = '削除済み';
$labels['invert'] = '反転';
$labels['filter'] = 'フィルター';
-
$labels['list'] = '一覧';
$labels['threads'] = 'スレッド';
$labels['expand-all'] = 'すべて展開';
$labels['nosubject'] = '(件名なし)';
$labels['showimages'] = '画像の表示';
$labels['alwaysshow'] = '$sender から届いた画像は常に表示';
+$labels['isdraft'] = 'これは下書きのメッセージです。';
$labels['htmltoggle'] = 'HTML';
$labels['plaintoggle'] = 'テキスト';
// settings
$labels['settingsfor'] = '次の設定:';
-
+$labels['about'] = 'Roundcube Webmail について';
$labels['preferences'] = '設定';
$labels['userpreferences'] = 'ユーザー設定';
$labels['editpreferences'] = 'ユーザー設定の変更';
$labels['reqdsn'] = '常に配送状況の通知を要求する';
$labels['replysamefolder'] = '返信されたメールを返信元メールと同じフォルダに保存';
$labels['defaultaddressbook'] = '次のアドレス帳に新規連絡先を追加する';
+$labels['autocompletesingle'] = '自動補完で代替メールアドレスを飛ばす';
$labels['spellcheckbeforesend'] = 'メールの送信前にスペル チェック';
$labels['spellcheckoptions'] = 'スペルチェックのオプション';
$labels['spellcheckignoresyms'] = '記号の単語を無視する';
$labels['sortdesc'] = '降順で並び替え';
$labels['undo'] = '取り消し';
+$labels['plugin'] = 'プラグイン';
+$labels['version'] = 'バージョン';
+$labels['source'] = 'ソース';
+$labels['license'] = 'ライセンス';
+$labels['support'] = 'ヘルプを受ける';
+
// units
$labels['B'] = 'バイト';
$labels['KB'] = 'KB';
| 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
*/
$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 件以内にしてください。';
$messages['invalidimageformat'] = '画像の形式が正しくありません。';
$messages['mispellingsfound'] = 'メッセージにスペル エラーを見つけました。';
$messages['parentnotwritable'] = '選択した親フォルダーへの作成、移動に失敗しました。アクセス権限がありません。';
+$messages['messagetoobig'] = 'その処理をするにはメッセージ部分が大きすぎます。';
?>
| 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$
$labels['server'] = 'სერვერი';
$labels['login'] = 'შესვლა';
$labels['logout'] = 'გამოსვლა';
-$labels['mail'] = 'ელ–ფოსტა';
+$labels['mail'] = 'ელფოსტა';
$labels['settings'] = 'პარამეტრები';
$labels['addressbook'] = 'მისამართები';
$labels['inbox'] = 'მიღებული';
$labels['drafts'] = 'დროებითი';
-$labels['sent'] = 'á\83\92á\83\90á\83\92á\83\96á\83\90á\83\95á\83\9cá\83\98á\83\9aá\83\94á\83\91á\83\98';
-$labels['trash'] = 'á\83¬á\83\90á\83¨á\83\9aá\83\98á\83\9aá\83\94á\83\91á\83\98';
+$labels['sent'] = 'გაგზავნილი';
+$labels['trash'] = 'წაშლილი';
$labels['junk'] = 'სპამი';
$labels['subject'] = 'სათაური';
$labels['from'] = 'გამგზავნი';
-$labels['to'] = 'á\83\9bá\83\98á\83\9bá\83¦á\83\94á\83\91á\83\98';
-$labels['cc'] = 'á\83\99á\83\9dá\83\9eá\83\98á\83\90';
+$labels['to'] = 'á\83\95á\83\98á\83¡';
+$labels['cc'] = 'á\83\90á\83¡á\83\9aá\83\98';
$labels['bcc'] = 'ფარული';
-$labels['replyto'] = 'á\83\93á\83\90á\83\91á\83 á\83£á\83\9cá\83\94á\83\91á\83\90';
+$labels['replyto'] = 'á\83\9eá\83\90á\83¡á\83£á\83®á\83\98';
$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'] = 'ხუთ';
$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'] = 'მონიშნეთ შეტყობინებები';
$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'] = 'შეუზღუდავი';
$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'] = 'ფოსტის გაგზავნა შერჩეულ ადრესატებთან';
$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'] = 'შემოტანა ფაილიდან:';
$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'] = 'ენა';
$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'] = 'შეამოწმე ყველა საქაღალდე ახალ შეტყობინებაზე';
$labels['belowquote'] = 'ციტატის შემდეგ';
$labels['abovequote'] = 'ციტატამდე';
$labels['insertsignature'] = 'ხელმოცერის ჩასმა';
+$labels['afternseconds'] = '$n წამის შემდეგ';
+$labels['addtodict'] = 'ლექსიკონში დამატება';
$labels['folder'] = 'საქაღალდე';
$labels['folders'] = 'საქაღალდეები';
$labels['foldername'] = 'საქაღალდის დასახელება';
$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'] = 'ჩინური';
?>
| 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$
$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'] = 'შეტყობინების გაგზავნა';
$messages['deletemessagesconfirm'] = 'ნამდვილად გსურთ მონიშნული შეტყობინებების წაშლა?';
$messages['deletefolderconfirm'] = 'ნამდვილად გსურთ ამ საქაღალდის წაშლა?';
$messages['purgefolderconfirm'] = 'ნამდვილად გსურთ ყველა შეტყობინების წაშლა აღნიშნულ საქაღალდეში?';
+$messages['groupdeleting'] = 'ჯგუფის წაშლა...';
$messages['folderdeleting'] = 'საქაღალდის წაშლა...';
$messages['foldermoving'] = 'საქაღალდის გადატანა...';
$messages['formincomplete'] = 'ყველა ველი არ არის შევსებული';
$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'] = 'შემოწმება...';
$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'] = 'გამოსახულების ფორმატი არასწორია.';
?>
| 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 $
*/
$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';
$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';
$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ą';
$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 į';
$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ą';
$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į';
$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:';
$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';
$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';
$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';
$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';
$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';
| 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 $
*/
$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.';
$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.';
$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…';
$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…';
$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.';
$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.';
$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.';
?>
| 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 $
*/
| 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 $
*/
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
$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';
| 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.';
?>
| 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 $
*/
$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)';
$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';
$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';
$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';
$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';
$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.';
$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';
$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';
$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';
$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';
$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';
| 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 $
*/
$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';
$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';
$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';
?>
| 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 $
*/
$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.';
$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ć.';
?>
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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:';
$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';
$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';
| 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 $
*/
$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.';
$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...';
$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...';
$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';
$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.';
$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.';
?>
| 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 $
*/
$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';
$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';
$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';
$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:';
$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';
$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';
$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';
$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';
+-----------------------------------------------------------------------+
| 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 $
*/
$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.';
$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';
$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...';
$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...';
$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.';
$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';
$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.';
?>
| 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 $
*/
| 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 $
*/
| 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 $
*/
$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';
| 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 $
*/
$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é.';
| 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 $
*/
$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';
$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';
$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';
$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';
$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';
$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:';
$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';
$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';
$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';
$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';
$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.';
$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.';
$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...';
$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...';
$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.';
$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';
$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.';
?>
-<?php
+a<?php
/*
| 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 $
*/
$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';
$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';
$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';
$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';
$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:';
$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';
$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';
| 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 $
*/
$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.';
$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';
$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...';
$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...';
$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';
| 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 $
*/
| 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 $
*/
| 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 $
*/
$labels['replytoallmessage'] = 'Відповісти до листа або відправнику та усім отримувачам';
$labels['replyall'] = 'Відповісти усім';
$labels['replylist'] = 'Відповісти до листа';
+$labels['forwardinline'] = 'Переслати у тілі листа';
+$labels['forwardattachment'] = 'Переслати як прикріплення';
$labels['forwardmessage'] = 'Переслати повідомлення';
$labels['deletemessage'] = 'У кошик';
$labels['movemessagetotrash'] = 'Перемістити лист у кошик';
$labels['markunread'] = 'Позначити як непрочитане';
$labels['markflagged'] = 'Додати зірочку';
$labels['markunflagged'] = 'Зняти зірочку';
-$labels['messageactions'] = 'Додаткові дії...';
+$labels['moreactions'] = 'Інші дії...';
$labels['select'] = 'Вибрати';
$labels['all'] = 'Всі';
$labels['none'] = 'Жодного';
$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'] = 'Низький';
$labels['manager'] = 'Менеждер';
$labels['assistant'] = 'Помічник';
$labels['spouse'] = 'Шлюбний партнер';
+$labels['allfields'] = 'Усі поля';
+$labels['search'] = 'Пошук';
+$labels['advsearch'] = 'Розширений пошук';
+$labels['other'] = 'Інше';
$labels['typehome'] = 'Дім';
$labels['typework'] = 'Робота';
$labels['typeother'] = 'Інше';
$labels['typepager'] = 'Пейджер';
$labels['typevideo'] = 'Відео';
$labels['typeassistant'] = 'Помічник';
+$labels['typehomepage'] = 'Домашня сторінка';
+$labels['typeblog'] = 'Блог';
+$labels['typeprofile'] = 'Профіль';
$labels['addfield'] = 'Додати поле...';
$labels['addcontact'] = 'Додати вибрані контакти до списку контактів';
$labels['editcontact'] = 'Редагувати контакт';
$labels['export'] = 'Експортувати';
$labels['exportvcards'] = 'Експортувати контакти у формат vCard';
$labels['newcontactgroup'] = 'Створити нову групу контактів';
-$labels['groupactions'] = 'Дії з групами контактів';
+$labels['grouprename'] = 'Перейменувати групу';
+$labels['groupdelete'] = 'Видалити групу';
$labels['previouspage'] = 'Попередня сторінка';
$labels['firstpage'] = 'Перша сторінка';
$labels['nextpage'] = 'Наступна сторінка';
$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'] = 'Готово';
$labels['preferhtml'] = 'Показувати в HTML';
$labels['defaultcharset'] = 'Кодування за замовчуваннням';
$labels['htmlmessage'] = 'Лист у HTML';
+$labels['dateformat'] = 'Формат дати';
+$labels['timeformat'] = 'Формат часу';
$labels['prettydate'] = 'Дати у зручному форматі';
$labels['setdefault'] = 'Встановити за замовчуванням';
$labels['autodetect'] = 'Визначати автоматично';
$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'] = 'Назва папки';
$labels['sortby'] = 'Відсортувати за';
$labels['sortasc'] = 'Сортувати за зростанням';
$labels['sortdesc'] = 'Сортувати за спаданням';
+$labels['undo'] = 'Відмінити';
$labels['B'] = 'б';
$labels['KB'] = 'Кб';
$labels['MB'] = 'Мб';
| 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 $
*/
$messages['imaperror'] = 'Невдале з`єднання з IMAP сервером';
$messages['servererror'] = 'Помилка сервера!';
$messages['servererrormsg'] = 'Помилка сервера: $msg';
+$messages['dberror'] = 'Помилка бази даних!';
$messages['errorreadonly'] = 'Неможливо виконати операцію. Папка доступна тільки для читання.';
$messages['errornoperm'] = 'Неможливо виконати операцію. Доступ заборонено';
$messages['invalidrequest'] = 'Невірний запит! Дані не збережено.';
$messages['mailboxempty'] = 'Поштова скринька порожня';
$messages['loading'] = 'Завантаження...';
$messages['uploading'] = 'Файл відправляється...';
+$messages['uploadingmany'] = 'Завантаження файлів...';
$messages['loadingdata'] = 'Завантаження даних...';
$messages['checkingmail'] = 'Перевірка нових листів...';
$messages['sendingmessage'] = 'Відправка листа...';
$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'] = 'Помилка при збереженні відправленого листа';
$messages['errordeleting'] = 'Не вдалося видалити листи';
$messages['errormarking'] = 'Не вдалося позначити листи';
$messages['deletecontactconfirm'] = 'Ви дійсно бажаєте видалити вибрані контакти?';
+$messages['deletegroupconfirm'] = 'Ви дійсно хочете видалити обрану групу?';
$messages['deletemessagesconfirm'] = 'Ви дійсно бажаєте видалити вибрані листи?';
$messages['deletefolderconfirm'] = 'Ви дійсно бажаєте видалити цю папку?';
$messages['purgefolderconfirm'] = 'Ви дійсно бажаєте видалити всі листи у цій папці?';
+$messages['contactdeleting'] = 'Видалення контакту(ів)...';
+$messages['groupdeleting'] = 'Видалення групи...';
$messages['folderdeleting'] = 'Видалення папки...';
$messages['foldermoving'] = 'Переміщення папки...';
$messages['foldersubscribing'] = 'Підписати папку...';
$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'] = 'Перевірка...';
$messages['errorsavingcontact'] = 'Неможливо зберегти адресу контакту';
$messages['movingmessage'] = 'Переміщення листа...';
$messages['copyingmessage'] = 'Копіювання листа...';
+$messages['copyingcontact'] = 'Копіювання контакту(ів)...';
$messages['deletingmessage'] = 'Видалення листа (ів)';
$messages['markingmessage'] = 'Позначення листа (ів)';
+$messages['addingmember'] = 'Додання контакту(ів) до групи...';
+$messages['removingmember'] = 'Видалення контакту(ів) з групи...';
$messages['receiptsent'] = 'Повідомлення про прочитання відправлено';
$messages['errorsendingreceipt'] = 'Не вдалося відправити повідомлення про прочитання';
$messages['nodeletelastidentity'] = 'Ви не можете видалити цей профіль, він у Вас останній.';
$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'] = 'Неможливо створити/перемістити папку до обраної батьківської папки. Нема прав доступу.';
?>
+-----------------------------------------------------------------------+
| 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'] = '密码';
// taskbar
$labels['logout'] = '注销';
-$labels['mail'] = '电子邮件';
-$labels['settings'] = '邮箱设置';
+$labels['mail'] = '邮件';
+$labels['settings'] = '设置';
$labels['addressbook'] = '通讯录';
// mailbox names
$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'] = '标记邮件';
$labels['expand-unread'] = '展开未读';
$labels['collapse-all'] = '收合全部';
$labels['threaded'] = '线索';
+
$labels['autoexpand_threads'] = '展开消息主题';
$labels['do_expand'] = '所有主题';
$labels['expand_only_unread'] = '仅未读消息';
$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'] = '编辑为新邮件';
$labels['editortype'] = '编辑器类型';
$labels['returnreceipt'] = '邮件回执';
$labels['dsn'] = '投递状态提示';
+$labels['mailreplyintro'] = '于 $date, $sender 回复:';
$labels['editidents'] = '编辑身份';
$labels['checkspelling'] = '拼写检查';
$labels['attachments'] = '附件';
$labels['upload'] = '上传';
+$labels['uploadprogress'] = '$percent ($current / $total)';
$labels['close'] = '关闭';
$labels['messageoptions'] = '邮件选项...';
$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'] = '删除选中的联系人';
$labels['print'] = '打印';
$labels['export'] = '导出';
$labels['exportvcards'] = '以 vCard 格式导出联系人';
-$labels['newcontactgroup'] = '创建新的联系人组';
-$labels['groupactions'] = '联系人组操作...';
+$labels['newcontactgroup'] = '创建新的组';
+$labels['groupactions'] = '组操作...';
+$labels['grouprename'] = '重命名组';
+$labels['groupdelete'] = '删除组';
$labels['previouspage'] = '上一页';
$labels['firstpage'] = '第一页';
$labels['group'] = '分组';
$labels['groups'] = '分组';
-$labels['personaladrbook'] = '个人地址';
+$labels['personaladrbook'] = '个人通讯录';
$labels['import'] = '导入';
$labels['importcontacts'] = '导入联系人';
$labels['importfromfile'] = '从文件导入';
+$labels['importtarget'] = '增加新联系人到通讯录:';
$labels['importreplace'] = '替换整个地址簿';
$labels['importtext'] = '你可以从已有的地址簿导入联系人。目前支持从 vCard 数据格式导入地址簿。';
$labels['done'] = '完成';
$labels['userpreferences'] = '个人偏好';
$labels['editpreferences'] = '修改个人偏好';
-$labels['identities'] = '发邮件的身份';
+$labels['identities'] = '发件身份';
$labels['manageidentities'] = '管理此账号的身份';
$labels['newidentity'] = '添加身份';
$labels['logoutcompact'] = '退出时压缩收件箱';
$labels['uisettings'] = '用户界面';
$labels['serversettings'] = '服务器设置';
-$labels['mailboxview'] = '邮箱查看方式';
+$labels['mailboxview'] = '显示邮件';
$labels['mdnrequests'] = '发件人请求回执';
$labels['askuser'] = '询问用户';
$labels['autosend'] = '自动发送';
$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)';
$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'] = '父文件夹';
$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';
$labels['korean'] = '韩语';
$labels['chinese'] = '中文';
-?>
+?>
\ No newline at end of file
+-----------------------------------------------------------------------+
| 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 $
*/
$messages['imaperror'] = '连接到邮件服务器失败';
$messages['servererror'] = '服务器错误!';
$messages['servererrormsg'] = '服务器错误: $msg';
+$messages['databaserror'] = '数据库错误!';
$messages['errorreadonly'] = '不可对只读文件夹进行操作';
$messages['errornoperm'] = '无权限操作';
$messages['invalidrequest'] = '无效的请求!数据保存失败。';
$messages['mailboxempty'] = '邮件夹为空';
$messages['loading'] = '正在加载...';
$messages['uploading'] = '正在上传文件...';
+$messages['uploadingmany'] = '正在上传多个文件...';
$messages['loadingdata'] = '正在加载数据...';
$messages['checkingmail'] = '检查新邮件...';
$messages['sendingmessage'] = '正在发送邮件...';
$messages['successfullysaved'] = '保存成功';
$messages['addedsuccessfully'] = '成功添加联系人';
$messages['contactexists'] = '当前联系人的电子邮件地址已存在';
+$messages['contactnameexists'] = '已存在同名的联系人.';
$messages['blockedimages'] = '为保护隐私,此邮件中的远程图片未显示';
$messages['encryptedmessage'] = '因此邮件已加密,无法正常显示';
$messages['nocontactsfound'] = '未找到联系人';
$messages['errordeleting'] = '无法删除邮件';
$messages['errormarking'] = '无法标记邮件';
$messages['deletecontactconfirm'] = '确定要删除已选中的联系人?';
+$messages['deletegroupconfirm'] = '确定要删除以选中的组?';
$messages['deletemessagesconfirm'] = '确定要删除已选中的邮件?';
$messages['deletefolderconfirm'] = '确定要删除已选中的邮件夹?';
$messages['purgefolderconfirm'] = '是否确认要删除当前邮件夹中的所有邮件?';
+$messages['groupdeleting'] = '正在删除组...';
$messages['folderdeleting'] = '正在删除邮件夹';
$messages['foldermoving'] = '正在移动目录...';
$messages['foldersubscribing'] = '注册文件夹中...';
$messages['errorsavingcontact'] = '无法保存联系人的地址';
$messages['movingmessage'] = '移动邮件到...';
$messages['copyingmessage'] = '复制邮件到...';
+$messages['copyingcontact'] = '复制联系人...';
$messages['deletingmessage'] = '正在删除邮件...';
$messages['markingmessage'] = '正在标记邮件...';
+$messages['addingmember'] = '正在添加联系人到组...';
+$messages['removingmember'] = '正在从组中删除联系人...';
$messages['receiptsent'] = '成功发送了一个已读回执';
$messages['errorsendingreceipt'] = '无法发送回执';
$messages['nodeletelastidentity'] = '无法删除这个身份,这是最后一个。';
$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'] = '切换到纯文本编辑器将导致邮件正文中的所有文本格式失效,您确定要这样做吗?';
$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'] = '复制邮件成功';
$messages['nametoolong'] = '名字太长';
$messages['folderupdated'] = '成功更新文件夹';
$messages['foldercreated'] = '成功创建文件夹';
+$messages['invalidimageformat'] = '非法的图像类型.';
+$messages['mispellingsfound'] = '检查到拼写错误.';
+$messages['parentnotwritable'] = '无法创建和转移到所选的目录,权限不足.';
?>
// 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();
}
// send downlaod headers
-send_nocacheing_headers();
header('Content-Type: text/x-vcard; charset='.RCMAIL_CHARSET);
header('Content-Disposition: attachment; filename="rcube_contacts.vcf"');
| 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 $
*/
$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');
$OUTPUT->include_script('list.js');
// add some labels to client
- $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact');
+ $OUTPUT->add_label('deletecontactconfirm', 'copyingcontact', 'contactdeleting');
return $out;
}
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);
}
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(
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']++;
}
}
// 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')));
$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) {
$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));
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);
}
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 {
'group-delete' => 'groups.inc',
'group-addmembers' => 'groups.inc',
'group-delmembers' => 'groups.inc',
+ 'search-create' => 'search.inc',
+ 'search-delete' => 'search.inc',
));
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++;
| 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 $
*/
// 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
$cids = rcmail_get_cids();
$mailto = array();
+$recipients = null;
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']);
}
}
| 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 $
*/
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])) {
// 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;
}
*/
+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();
}
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)) {
}
}
+ // Values matching mode
+ $mode = (int) $RCMAIL->config->get('addressbook_search_mode');
+
// get sources list
$sources = $RCMAIL->get_address_sources();
$search_set = array();
$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;
// 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)
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');
$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
| 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 $
*/
| 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 $
*/
$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']));
$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');
| 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 $
*/
}
$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!");
}
$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;
}
$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'])
// 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)
// 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')
| 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: |
| 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 $
*/
$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);
$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;
}
}
}
- 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, '" '));
-}
-
| 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 $
*/
// 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'])
$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);
$OUTPUT->command('update_selection');
}
}
- else {
- rcmail_send_unread_count($mbox_name, true);
- }
}
$RCMAIL->plugins->exec_hook('keep_alive', array());
| 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: |
| 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 $
*/
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)
'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'])) {
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']));
}
$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'])) {
}
// 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);
// 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)
$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;
}
}
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();
// 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
$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)
$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))) {
}
}
- $fvalue = implode(', ', $fvalue);
+ $fvalue = implode($separator, $fvalue);
}
$MESSAGE->compose[$header] = $fvalue;
$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;
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
// 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);
}
}
// 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',
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'],
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";
}
$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>";
}
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)
{
function rcmail_write_compose_attachments(&$message, $bodyIsHtml)
{
- global $RCMAIL;
+ global $RCMAIL, $COMPOSE;
$cid_map = $messages = array();
foreach ((array)$message->mime_parts as $pid => $part)
}
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
}
}
- $_SESSION['compose']['forward_attachments'] = true;
+ $COMPOSE['forward_attachments'] = true;
return $cid_map;
}
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
// 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';
}
$attachment = array(
- 'group' => $_SESSION['compose']['id'],
+ 'group' => $COMPOSE['id'],
'name' => $name,
'mimetype' => 'message/rfc822',
'data' => $data,
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);
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'));
}
$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,
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,
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);
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" : '';
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'],
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",
}
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'])
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);
}
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();
| 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
$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);
| 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 $
*/
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]);
}
$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)
$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))
}
if ($IMAP->threading) {
- $OUTPUT->command('init_threads', (array) $roots);
+ $OUTPUT->command('init_threads', (array) $roots, $mbox);
}
}
$col_name = '<span class="flagged"> </span>';
break;
case 'attachment':
+ case 'priority':
case 'status':
$col_name = '<span class="' . $col .'"> </span>';
break;
* @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;
// 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
);
$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
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;
// 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];
/**
* 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':
$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;
}
$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();
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
) {
$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,
)));
/**
* 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);
// 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);
'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,
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();
$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']);
| 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);
$MESSAGE = new rcube_message(get_input_value('_uid', RCUBE_INPUT_GET));
}
-send_nocacheing_headers();
-
// show part page
if (!empty($_GET['_frame'])) {
$OUTPUT->send('messagepart');
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;
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;
+ }
+}
+
| 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 $
*/
$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')
{
$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
// send response
$OUTPUT->send();
-
-
| 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 $
*/
$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);
| 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 $
*/
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);
| 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 $
*/
$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);
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);
}
}
-$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);
// 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']);
$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();
| 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: |
| 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 $
*/
$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);
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;
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'])) {
$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'];
// 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();
// 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
}
// 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);
// 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
// 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;
// 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;
$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',
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');
$OUTPUT->command('auto_save_start');
$OUTPUT->send('iframe');
- }
-else
- {
+}
+else {
rcmail_compose_cleanup($COMPOSE_ID);
if ($store_folder && !$saved)
else
$OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'));
$OUTPUT->send('iframe');
- }
-
-
+}
| 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 $
*/
rcmail_message_error($uid);
}
- send_nocacheing_headers();
-
$mbox_name = $IMAP->get_mailbox_name();
// show images?
'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']))) {
}
}
- 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));
+ }
}
$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,
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')));
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;
$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'))
// 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')) {
| 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 $
*/
'realnames' => false,
'maxlength' => 150,
'unsubscribed' => true,
- 'exceptions' => array($mbox_imap),
+ 'skip_noinferiors' => true,
+ 'exceptions' => array($mbox_imap),
));
$form['props']['fieldsets']['location']['content']['path'] = array(
);
// 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);
'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
| 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 $
*/
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;
| 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 $
*/
$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();
}
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);
| 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 $
*/
// 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');
);
}
+ // 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';
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),
);
}
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
$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));
);
}
+ 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
// 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();
| 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 $
*/
| 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 $
*/
'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;
'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']),
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;
// 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)
$a_user_prefs['default_imap_folders'][] = $a_user_prefs[$p];
}
}
-
+
break;
}
| 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 $
*/
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;
| 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 $
*/
$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>');
$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));
| 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 $
*/
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"}}';
#directorylistbox input
{
- margin: 2px;
+ margin: 0px;
+ font-size: 11px;
width: 90%;
}
#directorylist li.contactgroup
{
padding-left: 15px;
- background-position: 20px -144px;
+ background-position: 20px -143px;
+}
+
+#directorylist li.contactsearch
+{
+ background-position: 6px -162px;
}
#directorylist li.selected
body
{
+ font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
margin: 8px;
background-color: #F6F6F6;
- color: #000000;
+ color: #000;
+ font-size: 12px;
}
body.iframe
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
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;
}
hr
{
height: 1px;
- background-color: #666666;
+ background-color: #666;
border-style: none;
}
input[type="password"],
textarea
{
- border: 1px solid #666666;
- color: #333333;
- background-color: #ffffff;
+ border: 1px solid #666;
+ color: #333;
+ background-color: #FFF;
}
input, textarea
}
#message div.notice,
-#remote-objects-message
+#message-objects div.notice
{
background: url(images/display/icons.png) 6px 3px no-repeat;
background-color: #F7FDCB;
}
#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;
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;
}
margin: auto;
}
-#rcmloginuser, #rcmloginpwd, #rcmloginhost
+#login-form table td.input input
{
width: 200px;
}
/* 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;
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%;
}
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
}
obj[show?'show':'hide']();
-
+
if (bw.ie6 && this.popups[popup].overlap) {
$('select').css('visibility', show?'hidden':'inherit');
$('select', obj).css('visibility', 'inherit');
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']();
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;
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)
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')
// 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);
// 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
#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);
}
#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,
<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 />
padding-top: 2px;
padding-bottom: 2px;
text-decoration: none;
+ height: 15px;
}
#mailboxlist li.unread
#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;
#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,
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;
#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;
background-color: #FFF;
}
-/*
-#messagelist tr.odd
-{
- background-color: #F9F9F9;
-}
-*/
-
#messagelist tr.unread
{
font-weight: bold;
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;
}
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;
}
</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>
<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>
<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 />
<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">
<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>